3 Commits

Author SHA1 Message Date
ssa
81d3c51cb7 Merge pull request 'config: change external port to 11088' (#3) from ai into main
Reviewed-on: #3
2026-02-18 23:45:22 +03:00
ssa
8ca531ca98 Merge pull request 'ai' (#2) from ai into main
Reviewed-on: #2
2026-02-18 23:27:18 +03:00
ssa
22a03735d6 Merge pull request 'ai' (#1) from ai into main
Reviewed-on: #1
2026-02-18 22:44:41 +03:00
4 changed files with 3 additions and 188 deletions

View File

@@ -1,24 +0,0 @@
name: Gitea Actions Demo
run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀
on: [push]
jobs:
Explore-Gitea-Actions:
runs-on: [ubuntu-latest]
steps:
- run: echo "🎉 The job was automatically triggered by a ${{ gitea.event_name }} event."
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by Gitea!"
- run: echo "🔎 The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
- run: whoami
- run: hostname
- run: node -v
#- name: Check out repository code
#uses: actions/checkout@v6
- run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner."
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
- name: List files in the repository
run: |
ls ${{ gitea.workspace }}
- run: echo "🍏 This job's status is ${{ job.status }}."

View File

@@ -119,56 +119,6 @@ test.describe('Environment Management', () => {
expect(hostPlaceholderCount).toBe(2);
});
test('should validate template with unquoted placeholders', async ({ page }) => {
await page.goto('/');
await page.click('button:has-text("Create new")');
await page.waitForTimeout(500);
// Add a parameter
await page.click('button:has-text("✚")');
await page.waitForTimeout(300);
const nameInput = page.locator('input[placeholder="name"]');
const valueInput = page.locator('input[placeholder="value"]');
const addButton = page.locator('button:has-text("✓")');
await nameInput.fill('port');
await valueInput.fill('8080');
await addButton.click();
await page.waitForTimeout(500);
// Go to Content Template and edit with unquoted placeholder
await page.click('a:has-text("Content Template")');
await page.waitForTimeout(300);
await page.click('button:has-text("Edit")');
await page.waitForTimeout(300);
// Fill template with unquoted @port@ placeholder
const textarea = page.locator('textarea');
await textarea.fill('{\n "Host": "@host@",\n "Port": @port@,\n "Url": "http://@host@:@port@/api"\n}');
await page.waitForTimeout(300);
// Check that Save button is enabled (validation passed)
const saveButton = page.locator('button:has-text("Save")');
await expect(saveButton).toBeEnabled();
// Check that there's no JSON error
const errorAlert = page.locator('.alert-danger');
await expect(errorAlert).not.toBeVisible();
// Save the template
await saveButton.click();
await page.waitForTimeout(500);
// Verify it was saved - should be in view mode with Edit button visible
const editButton = page.locator('button:has-text("Edit")');
await expect(editButton).toBeVisible();
// Verify the template content is displayed correctly
const codeContent = page.locator('code');
await expect(codeContent).toBeVisible();
const content = await codeContent.textContent();
expect(content).toContain('@port@');
});
test('should download config file with correct filename', async ({ page }) => {
await page.goto('/');
await page.click('button:has-text("Create new")');

View File

@@ -35,10 +35,9 @@ export function ConfigTemplate(props: ConfigTemplateProps) {
}
function handleSave() {
// Validate JSON before saving (with placeholder support)
// Validate JSON before saving
try {
const sanitizedValue = draftContent.replace(/@[^@]+@/g, '1');
JSON.parse(sanitizedValue);
JSON.parse(draftContent);
setJsonError(null);
props.onSaved(draftContent);
setMode('view');
@@ -53,9 +52,7 @@ export function ConfigTemplate(props: ConfigTemplateProps) {
try {
if (value.trim()) {
// Replace @placeholders@ with valid JSON values for validation
// Strategy: Replace ALL @...@ patterns with "1" (valid for both string and numeric contexts)
const sanitizedValue = value.replace(/@[^@]+@/g, '1');
const sanitizedValue = value.replace(/"@?(\w+)@?"/g, '"__PLACEHOLDER__"');
JSON.parse(sanitizedValue);
setJsonError(null);
} else {

View File

@@ -1,108 +0,0 @@
import { describe, it, expect } from 'vitest';
describe('JSON Validation with @placeholders@', () => {
/**
* Helper function that mimics the validation logic in ConfigTemplate.tsx
*/
function validateJsonWithPlaceholders(value: string): { valid: boolean; error?: string } {
try {
if (!value.trim()) {
return { valid: true };
}
// This is the current implementation from ConfigTemplate.tsx
// Replace ALL @...@ patterns with "1" (valid for both string and numeric contexts)
const sanitizedValue = value.replace(/@[^@]+@/g, '1');
JSON.parse(sanitizedValue);
return { valid: true };
} catch (e) {
return { valid: false, error: (e as Error).message };
}
}
it('should validate quoted placeholders', () => {
const json = `{
"Host": "@host@",
"Port": "@port@"
}`;
const result = validateJsonWithPlaceholders(json);
expect(result.valid).toBe(true);
});
it('should validate unquoted placeholders', () => {
const json = `{
"Host": "@host@",
"Port": @port@
}`;
const result = validateJsonWithPlaceholders(json);
expect(result.valid).toBe(true);
});
it('should validate mixed quoted and unquoted placeholders', () => {
const json = `{
"Host": "@host@",
"Port": @port@,
"ApiPath": "@host@:@port@/v1/data",
"MessageBroker": {
"hosts": @MessageBrokerHosts@
}
}`;
const result = validateJsonWithPlaceholders(json);
expect(result.valid).toBe(true);
});
it('should validate placeholders inside strings (URLs)', () => {
const json = `{
"ApiUrl": "http://@host@:@port@/api"
}`;
const result = validateJsonWithPlaceholders(json);
expect(result.valid).toBe(true);
});
it('should validate complex real-world template', () => {
const json = `{
"Host": "@host@",
"Port": @port@,
"ApiPath": "@host@:@port@/v1/data",
"MessageBroker": {
"hosts": @MessageBrokerHosts@
},
"basePath": "./@env_name@/in",
"NoParam": "@no_param@"
}`;
const result = validateJsonWithPlaceholders(json);
expect(result.valid).toBe(true);
});
it('should reject invalid JSON structure', () => {
const json = `{
"Host": "@host@",
"Port": @port@
"Missing": "comma"
}`;
const result = validateJsonWithPlaceholders(json);
expect(result.valid).toBe(false);
expect(result.error).toContain('Expected');
});
it('should handle empty value', () => {
const result = validateJsonWithPlaceholders('');
expect(result.valid).toBe(true);
});
it('should handle whitespace only', () => {
const result = validateJsonWithPlaceholders(' \n\t ');
expect(result.valid).toBe(true);
});
});