|
{entry.team_name}
|
+
+ {entry.config_id ? (
+
+ {entry.config_name ?? 'Default'}
+
+ ) : (
+ —
+ )}
+ |
{entry.manifest_url ?? '—'}
|
- {entry.has_config ? (
+ {entry.config_id ? (
{entry.is_enabled ? 'Enabled' : 'Disabled'}
diff --git a/client/src/components/pages/Manifest/ManifestConfig.test.tsx b/client/src/components/pages/Manifest/ManifestConfig.test.tsx
index 84988d1..692dcf5 100644
--- a/client/src/components/pages/Manifest/ManifestConfig.test.tsx
+++ b/client/src/components/pages/Manifest/ManifestConfig.test.tsx
@@ -11,6 +11,7 @@ beforeAll(() => {
const baseConfig: TeamManifestConfig = {
id: 'mc1',
team_id: 't1',
+ name: 'Default',
manifest_url: 'https://example.com/manifest.json',
is_enabled: 1,
sync_policy: JSON.stringify({
@@ -160,6 +161,7 @@ describe('ManifestConfig — edit mode', () => {
await waitFor(() => {
expect(onSave).toHaveBeenCalledWith({
+ name: 'Default',
manifest_url: 'https://new.example.com/manifest.json',
sync_policy: {
on_field_drift: 'flag',
diff --git a/client/src/components/pages/Manifest/ManifestConfig.tsx b/client/src/components/pages/Manifest/ManifestConfig.tsx
index 214817d..915f95e 100644
--- a/client/src/components/pages/Manifest/ManifestConfig.tsx
+++ b/client/src/components/pages/Manifest/ManifestConfig.tsx
@@ -60,10 +60,12 @@ function ManifestConfig({
// Form state
const policy = parseSyncPolicy(config?.sync_policy ?? null);
+ const [formName, setFormName] = useState(config?.name ?? '');
const [formUrl, setFormUrl] = useState(config?.manifest_url ?? '');
const [formFieldDrift, setFormFieldDrift] = useState(policy.on_field_drift || 'flag');
const [formRemoval, setFormRemoval] = useState(policy.on_removal || 'flag');
const [urlError, setUrlError] = useState(null);
+ const [nameError, setNameError] = useState(null);
// Test URL state
const [isTesting, setIsTesting] = useState(false);
@@ -72,10 +74,12 @@ function ManifestConfig({
const handleEdit = () => {
const p = parseSyncPolicy(config?.sync_policy ?? null);
+ setFormName(config?.name ?? '');
setFormUrl(config?.manifest_url ?? '');
setFormFieldDrift(p.on_field_drift || 'flag');
setFormRemoval(p.on_removal || 'flag');
setUrlError(null);
+ setNameError(null);
setTestResult(null);
setTestError(null);
setIsEditing(true);
@@ -119,17 +123,32 @@ function ManifestConfig({
};
const handleSave = async () => {
+ const trimmedName = formName.trim();
const trimmedUrl = formUrl.trim();
+
+ let hasError = false;
+
+ if (!trimmedName) {
+ setNameError('Name is required');
+ hasError = true;
+ } else {
+ setNameError(null);
+ }
+
if (!trimmedUrl) {
setUrlError('Manifest URL is required');
- return;
- }
- if (!isValidUrl(trimmedUrl)) {
+ hasError = true;
+ } else if (!isValidUrl(trimmedUrl)) {
setUrlError('Please enter a valid HTTP or HTTPS URL');
- return;
+ hasError = true;
+ } else {
+ setUrlError(null);
}
+ if (hasError) return;
+
const input: ManifestConfigInput = {
+ name: trimmedName,
manifest_url: trimmedUrl,
sync_policy: {
on_field_drift: formFieldDrift,
@@ -154,6 +173,26 @@ function ManifestConfig({
return (
+
+
+ {
+ setFormName(e.target.value);
+ setNameError(null);
+ }}
+ placeholder="e.g. Production, Staging, Core Services"
+ required
+ maxLength={100}
+ />
+ {nameError && {nameError}}
+
+
|