Skip to content

Commit f7414a7

Browse files
committed
Remove unneeded style in Tile configuration
Signed-off-by: Trung Nguyen <[email protected]>
1 parent 5543511 commit f7414a7

File tree

2 files changed

+213
-190
lines changed

2 files changed

+213
-190
lines changed
Lines changed: 136 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,143 @@
1-
import { v1 } from "@docker/extension-api-client-types";
2-
import CheckOutlined from "@mui/icons-material/CheckOutlined";
3-
import CloseOutlined from "@mui/icons-material/CloseOutlined";
4-
import { Alert, CircularProgress, IconButton, Stack, TextField, Typography } from "@mui/material";
5-
import * as JsonSchema from "json-schema-library";
6-
import { useEffect, useMemo, useState } from "react";
7-
8-
import { buildObjectFromFlattenedObject, deepFlattenObject } from "../../MergeDeep";
9-
import { useConfig } from "../../queries/useConfig";
10-
import { CatalogItemRichened } from "../../types/catalog";
1+
import { v1 } from '@docker/extension-api-client-types';
2+
import CheckOutlined from '@mui/icons-material/CheckOutlined';
3+
import CloseOutlined from '@mui/icons-material/CloseOutlined';
4+
import {
5+
Alert,
6+
CircularProgress,
7+
IconButton,
8+
OutlinedInput,
9+
Stack,
10+
TextField,
11+
Typography,
12+
} from '@mui/material';
13+
import * as JsonSchema from 'json-schema-library';
14+
import { useEffect, useMemo, useState } from 'react';
15+
16+
import {
17+
buildObjectFromFlattenedObject,
18+
deepFlattenObject,
19+
} from '../../MergeDeep';
20+
import { useConfig } from '../../queries/useConfig';
21+
import { CatalogItemRichened } from '../../types/catalog';
1122

1223
JsonSchema.settings.GET_TEMPLATE_RECURSION_LIMIT = 1000;
1324
JsonSchema.settings.templateDefaultOptions.addOptionalProps = true;
1425

15-
const EmptyState = () => {
16-
return (
17-
<Alert severity="info"> No config available </Alert>
18-
)
19-
}
20-
21-
const LoadingState = () => {
22-
return (
23-
<Stack direction="row" spacing={2} alignItems="center">
24-
<CircularProgress />
25-
<Typography>Loading config...</Typography>
26-
</Stack>
27-
)
28-
}
29-
30-
const ConfigEditor = ({ catalogItem, client }: { catalogItem: CatalogItemRichened, client: v1.DockerDesktopClient }) => {
31-
const configSchema = catalogItem.configSchema;
32-
33-
const { config, saveConfig: updateExistingConfig, configLoading } = useConfig(client);
34-
35-
const existingConfigForItem = catalogItem.configValue || {};
36-
37-
38-
const [localConfig, setLocalConfig] = useState<{ [key: string]: any } | undefined>(undefined);
39-
const [savingKeys, setSavingKeys] = useState<Set<string>>(new Set());
40-
41-
// Use memoized flattenedConfig to ensure it only updates when config changes
42-
// This MUST be called before any early returns to avoid conditional hook calls
43-
const flattenedConfig = useMemo(() =>
44-
configSchema ? deepFlattenObject({ ...catalogItem.configTemplate, ...existingConfigForItem }) : {},
45-
[catalogItem.configTemplate, existingConfigForItem, configSchema]);
46-
47-
// Reset local config when the existing config changes
48-
useEffect(() => {
49-
if (!configSchema) return;
50-
setLocalConfig(flattenedConfig);
51-
}, [flattenedConfig]);
52-
53-
// Early returns
54-
if (!configSchema) {
55-
return <EmptyState />;
56-
}
57-
58-
if (!config && !configLoading) {
59-
return <EmptyState />;
60-
}
61-
62-
if (configLoading) {
63-
return <LoadingState />;
64-
}
65-
66-
if (!config || !localConfig) {
67-
return <LoadingState />;
68-
}
69-
70-
return (
71-
<Stack>
72-
<Typography variant="h6">Config</Typography>
73-
<Stack direction="column" spacing={2}>
74-
{Object.keys(flattenedConfig).map((key: string) => {
75-
const edited = localConfig[key] !== flattenedConfig[key];
76-
const isSaving = savingKeys.has(key);
77-
78-
return (
79-
<Stack key={key} direction="row" spacing={2}>
80-
<TextField
81-
label={key}
82-
value={localConfig[key] || ''}
83-
onChange={(e) => setLocalConfig({ ...localConfig, [key]: e.target.value })}
84-
disabled={isSaving}
85-
/>
86-
{edited && <Stack direction="row" spacing={2}>
87-
{isSaving ? (
88-
<CircularProgress size={24} />
89-
) : (
90-
<Stack direction="row" spacing={2}>
91-
<IconButton onClick={() => updateExistingConfig(catalogItem.name, buildObjectFromFlattenedObject(localConfig))}
92-
disabled={isSaving}
93-
>
94-
<CheckOutlined sx={{ color: 'success.main' }} />
95-
</IconButton>
96-
<IconButton onClick={() => setLocalConfig({
97-
...localConfig,
98-
[key]: flattenedConfig[key]
99-
})}
100-
disabled={isSaving}
101-
>
102-
<CloseOutlined sx={{ color: 'error.main' }} />
103-
</IconButton>
104-
</Stack>
105-
)}
106-
</Stack>}
107-
</Stack>
108-
)
109-
})}
26+
const ConfigEditor = ({
27+
catalogItem,
28+
client,
29+
}: {
30+
catalogItem: CatalogItemRichened;
31+
client: v1.DockerDesktopClient;
32+
}) => {
33+
const configSchema = catalogItem.configSchema;
34+
35+
const {
36+
config,
37+
saveConfig: updateExistingConfig,
38+
configLoading,
39+
} = useConfig(client);
40+
41+
const existingConfigForItem = catalogItem.configValue || {};
42+
43+
const [localConfig, setLocalConfig] = useState<
44+
{ [key: string]: any } | undefined
45+
>(undefined);
46+
const [savingKeys, setSavingKeys] = useState<Set<string>>(new Set());
47+
48+
// Use memoized flattenedConfig to ensure it only updates when config changes
49+
// This MUST be called before any early returns to avoid conditional hook calls
50+
const flattenedConfig = useMemo(
51+
() =>
52+
configSchema
53+
? deepFlattenObject({
54+
...catalogItem.configTemplate,
55+
...existingConfigForItem,
56+
})
57+
: {},
58+
[catalogItem.configTemplate, existingConfigForItem, configSchema]
59+
);
60+
61+
// Reset local config when the existing config changes
62+
useEffect(() => {
63+
if (!configSchema) return;
64+
setLocalConfig(flattenedConfig);
65+
}, [flattenedConfig]);
66+
67+
// Early returns
68+
if (!configSchema) {
69+
return null;
70+
}
71+
72+
if (!config && !configLoading) {
73+
return null;
74+
}
75+
76+
if (configLoading) {
77+
return null;
78+
}
79+
80+
if (!config || !localConfig) {
81+
return null;
82+
}
83+
84+
return (
85+
<Stack>
86+
<Typography variant="subtitle2">Config</Typography>
87+
<Stack direction="column" spacing={2}>
88+
{Object.keys(flattenedConfig).map((key: string) => {
89+
const edited = localConfig[key] !== flattenedConfig[key];
90+
const isSaving = savingKeys.has(key);
91+
92+
return (
93+
<Stack key={key} direction="row" spacing={2}>
94+
<OutlinedInput
95+
size="small"
96+
placeholder={key}
97+
value={localConfig[key] || ''}
98+
onChange={(e) =>
99+
setLocalConfig({ ...localConfig, [key]: e.target.value })
100+
}
101+
disabled={isSaving}
102+
/>
103+
{edited && (
104+
<Stack direction="row" spacing={2}>
105+
{isSaving ? (
106+
<CircularProgress size={24} />
107+
) : (
108+
<Stack direction="row" spacing={2}>
109+
<IconButton
110+
onClick={() =>
111+
updateExistingConfig(
112+
catalogItem.name,
113+
buildObjectFromFlattenedObject(localConfig)
114+
)
115+
}
116+
disabled={isSaving}
117+
>
118+
<CheckOutlined sx={{ color: 'success.main' }} />
119+
</IconButton>
120+
<IconButton
121+
onClick={() =>
122+
setLocalConfig({
123+
...localConfig,
124+
[key]: flattenedConfig[key],
125+
})
126+
}
127+
disabled={isSaving}
128+
>
129+
<CloseOutlined sx={{ color: 'error.main' }} />
130+
</IconButton>
131+
</Stack>
132+
)}
133+
</Stack>
134+
)}
110135
</Stack>
111-
</Stack>
112-
)
113-
}
136+
);
137+
})}
138+
</Stack>
139+
</Stack>
140+
);
141+
};
114142

115143
export default ConfigEditor;

0 commit comments

Comments
 (0)