Skip to content

Commit aeb54cf

Browse files
WIP: added switcher working on YAML Editor
1 parent 70d2d4f commit aeb54cf

1 file changed

Lines changed: 205 additions & 95 deletions

File tree

src/views/CronTabForm/CronTabForm.tsx

Lines changed: 205 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@ import {
1818
useK8sModel,
1919
k8sCreate,
2020
useActiveNamespace,
21+
CodeEditor,
2122
} from "@openshift-console/dynamic-plugin-sdk";
2223
import { useNavigate } from "react-router-dom-v5-compat";
2324
import { useCronTabTranslation } from "@crontab-utils/hooks/useCronTabTranslation";
2425
import { cronTabGroupVersionKind } from "src/utils/utils";
2526
import { CronTabKind } from "@crontab-model/types";
27+
import yaml from "js-yaml";
28+
import { defaultCronTabYamlTemplate } from "src/templates/crontab-yaml";
2629

2730
export const CronTabForm: React.FC = () => {
2831
const [model] = useK8sModel(cronTabGroupVersionKind);
@@ -32,6 +35,10 @@ export const CronTabForm: React.FC = () => {
3235
const [replicas, setReplicas] = useState<number | "">(0);
3336
const [loading, setLoading] = useState(false);
3437
const [error, setError] = useState("");
38+
const [showYaml, setShowYaml] = useState(false);
39+
const [yamlContent, setYamlContent] = useState<string>(
40+
defaultCronTabYamlTemplate.trim()
41+
);
3542
const navigate = useNavigate();
3643
const { t } = useCronTabTranslation();
3744
const [namespace] = useActiveNamespace();
@@ -76,109 +83,212 @@ export const CronTabForm: React.FC = () => {
7683
setError(t("Error creating CronTab: {{err}}", { err: err.toString() }));
7784
});
7885
};
86+
87+
const handleYamlSubmit = () => {
88+
setLoading(true);
89+
setError("");
90+
try {
91+
const loaded = yaml.load(yamlContent) as Partial<CronTabKind> | undefined;
92+
if (
93+
!loaded ||
94+
!loaded.metadata ||
95+
!(loaded.metadata.name || loaded.metadata.generateName)
96+
) {
97+
throw new Error(
98+
t("YAML must include metadata.name or metadata.generateName")
99+
);
100+
}
101+
if (!loaded.spec) {
102+
throw new Error(t("YAML must include spec"));
103+
}
104+
105+
const data: CronTabKind = {
106+
apiVersion: (loaded.apiVersion as string) || CRONTAB_APIGROUP_VERSION,
107+
kind: (loaded.kind as string) || CRONTAB_KIND,
108+
metadata: {
109+
...loaded.metadata,
110+
namespace,
111+
},
112+
spec: {
113+
cronSpec,
114+
image,
115+
replicas: replicas ? replicas : 0,
116+
},
117+
};
118+
119+
k8sCreate({ model, data })
120+
.then(() => {
121+
setLoading(false);
122+
navigate(
123+
`/k8s/ns/${namespace}/${cronTabGroupVersionKind.group}~${cronTabGroupVersionKind.version}~${cronTabGroupVersionKind.kind}`
124+
);
125+
})
126+
.catch((err) => {
127+
setLoading(false);
128+
setError(
129+
t("Error creating CronTab: {{err}}", { err: err.toString() })
130+
);
131+
});
132+
} catch (err) {
133+
setLoading(false);
134+
setError(t("Invalid YAML: {{err}}", { err: (err as Error).message }));
135+
}
136+
};
137+
79138
return (
80139
<PageSection>
81140
<Title headingLevel="h1" data-test="page-heading">
82141
{t("Create CronTab")}
83142
</Title>
84-
<Form>
85-
<FormGroup label={t("Name")} fieldId="crontab-name" isRequired>
86-
<TextInput
87-
id="crontab-name"
88-
data-test="crontab-name"
89-
name="name"
90-
onChange={(_e, value) => setName(value)}
91-
value={name}
92-
required
93-
/>
94-
<FormHelperText>
95-
<HelperText>
96-
<HelperTextItem>
97-
{t("A unique identifier for this CronTab within the project.")}
98-
</HelperTextItem>
99-
</HelperText>
100-
</FormHelperText>
101-
</FormGroup>
102-
<FormGroup label={t("CronSpec")} fieldId="crontab-cronSpec" isRequired>
103-
<TextInput
104-
id="crontab-cronSpec"
105-
data-test="crontab-cronSpec"
106-
value={cronSpec || ""}
107-
onChange={(_e, value) => setCronSpec(value)}
108-
required
109-
/>
110-
<FormHelperText>
111-
<HelperText>
112-
<HelperTextItem>
113-
{t(
114-
"Defines the schedule on which the job will run (e.g., */5 * * * *)."
115-
)}
116-
</HelperTextItem>
117-
</HelperText>
118-
</FormHelperText>
119-
</FormGroup>
120-
<FormGroup label={t("Image")} fieldId="crontab-image" isRequired>
121-
<TextInput
122-
id="crontab-image"
123-
data-test="crontab-image"
124-
value={image || ""}
125-
onChange={(_e, value) => setImage(value)}
126-
required
127-
/>
128-
<FormHelperText>
129-
<HelperText>
130-
<HelperTextItem>
131-
{t(
132-
"Specifies the container image to be executed by the CronTab."
133-
)}
134-
</HelperTextItem>
135-
</HelperText>
136-
</FormHelperText>
137-
</FormGroup>
138-
<FormGroup label={t("Replicas")} fieldId="crontab-replicas" isRequired>
139-
<NumberInput
140-
id="crontab-replicas"
141-
data-test="crontab-replicas"
142-
value={replicas}
143-
onChange={onChangeReplicas}
144-
onMinus={onReplicasMinus}
145-
onPlus={onReplicasPlus}
146-
inputName={t("replicas")}
147-
inputAriaLabel={t("Number of replicas")}
148-
minusBtnAriaLabel={t("Decrease replicas")}
149-
plusBtnAriaLabel={t("Increase replicas")}
150-
required
151-
min={0}
143+
<Button variant="link" onClick={() => setShowYaml(!showYaml)}>
144+
{showYaml ? t("Form View") : t("YAML Editor")}
145+
</Button>
146+
147+
{showYaml ? (
148+
<>
149+
<CodeEditor
150+
value={yamlContent}
151+
language="yaml"
152+
onChange={(_e, val) => setYamlContent(val as string)}
153+
minHeight="0"
154+
height="500px"
155+
options={{
156+
wordWrap: "on",
157+
formatOnPaste: true,
158+
}}
152159
/>
153-
<FormHelperText>
154-
<HelperText>
155-
<HelperTextItem>
156-
{t("The desired number of instances of this CronTab to run.")}
157-
</HelperTextItem>
158-
</HelperText>
159-
</FormHelperText>
160-
</FormGroup>
161-
{error && <Alert variant="danger" title={error} />}
162-
<ActionGroup>
163-
<Button
164-
type="button"
165-
variant="primary"
166-
isDisabled={loading || !name || !cronSpec || !image}
167-
onClick={handleSubmit}
168-
isLoading={loading}
169-
data-test="save-changes"
160+
{error && <Alert variant="danger" title={error} />}
161+
<ActionGroup>
162+
<Button
163+
type="button"
164+
style={{ marginTop: "2rem", marginRight: "0.5rem" }}
165+
variant="primary"
166+
isDisabled={loading}
167+
onClick={handleYamlSubmit}
168+
isLoading={loading}
169+
>
170+
{t("Create")}
171+
</Button>
172+
<Button
173+
variant="secondary"
174+
style={{ marginTop: "2rem", marginLeft: "0.5rem" }}
175+
onClick={() => navigate(-1)}
176+
isDisabled={loading}
177+
>
178+
{t("Cancel")}
179+
</Button>
180+
</ActionGroup>
181+
</>
182+
) : (
183+
<Form>
184+
<FormGroup label={t("Name")} fieldId="crontab-name" isRequired>
185+
<TextInput
186+
id="crontab-name"
187+
data-test="crontab-name"
188+
name="name"
189+
onChange={(_e, value) => setName(value)}
190+
value={name}
191+
required
192+
/>
193+
<FormHelperText>
194+
<HelperText>
195+
<HelperTextItem>
196+
{t(
197+
"A unique identifier for this CronTab within the project."
198+
)}
199+
</HelperTextItem>
200+
</HelperText>
201+
</FormHelperText>
202+
</FormGroup>
203+
<FormGroup
204+
label={t("CronSpec")}
205+
fieldId="crontab-cronSpec"
206+
isRequired
170207
>
171-
{t("Create")}
172-
</Button>
173-
<Button
174-
variant="secondary"
175-
isDisabled={loading}
176-
onClick={() => navigate(-1)}
208+
<TextInput
209+
id="crontab-cronSpec"
210+
data-test="crontab-cronSpec"
211+
value={cronSpec || ""}
212+
onChange={(_e, value) => setCronSpec(value)}
213+
required
214+
/>
215+
<FormHelperText>
216+
<HelperText>
217+
<HelperTextItem>
218+
{t(
219+
"Defines the schedule on which the job will run (e.g., */5 * * * *)."
220+
)}
221+
</HelperTextItem>
222+
</HelperText>
223+
</FormHelperText>
224+
</FormGroup>
225+
<FormGroup label={t("Image")} fieldId="crontab-image" isRequired>
226+
<TextInput
227+
id="crontab-image"
228+
data-test="crontab-image"
229+
value={image || ""}
230+
onChange={(_e, value) => setImage(value)}
231+
required
232+
/>
233+
<FormHelperText>
234+
<HelperText>
235+
<HelperTextItem>
236+
{t(
237+
"Specifies the container image to be executed by the CronTab."
238+
)}
239+
</HelperTextItem>
240+
</HelperText>
241+
</FormHelperText>
242+
</FormGroup>
243+
<FormGroup
244+
label={t("Replicas")}
245+
fieldId="crontab-replicas"
246+
isRequired
177247
>
178-
{t("Cancel")}
179-
</Button>
180-
</ActionGroup>
181-
</Form>
248+
<NumberInput
249+
id="crontab-replicas"
250+
data-test="crontab-replicas"
251+
value={replicas}
252+
onChange={onChangeReplicas}
253+
onMinus={onReplicasMinus}
254+
onPlus={onReplicasPlus}
255+
inputName={t("replicas")}
256+
inputAriaLabel={t("Number of replicas")}
257+
minusBtnAriaLabel={t("Decrease replicas")}
258+
plusBtnAriaLabel={t("Increase replicas")}
259+
required
260+
min={0}
261+
/>
262+
<FormHelperText>
263+
<HelperText>
264+
<HelperTextItem>
265+
{t("The desired number of instances of this CronTab to run.")}
266+
</HelperTextItem>
267+
</HelperText>
268+
</FormHelperText>
269+
</FormGroup>
270+
{error && <Alert variant="danger" title={error} />}
271+
<ActionGroup>
272+
<Button
273+
type="button"
274+
variant="primary"
275+
isDisabled={loading || !name || !cronSpec || !image}
276+
onClick={handleSubmit}
277+
isLoading={loading}
278+
data-test="save-changes"
279+
>
280+
{t("Create")}
281+
</Button>
282+
<Button
283+
variant="secondary"
284+
isDisabled={loading}
285+
onClick={() => navigate(-1)}
286+
>
287+
{t("Cancel")}
288+
</Button>
289+
</ActionGroup>
290+
</Form>
291+
)}
182292
</PageSection>
183293
);
184294
};

0 commit comments

Comments
 (0)