feat: refactor Form View to Edit only (#451)
Signed-off-by: Charles Thao <cthao@redhat.com>
This commit is contained in:
parent
28f2471bb5
commit
ca8e94c5c1
|
@ -1,4 +1,4 @@
|
|||
import React, { useCallback, useState } from 'react';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Content,
|
||||
|
@ -13,6 +13,7 @@ import {
|
|||
} from '@patternfly/react-core';
|
||||
import { useTypedNavigate } from '~/app/routerHelper';
|
||||
import useGenericObjectState from '~/app/hooks/useGenericObjectState';
|
||||
import { useNotebookAPI } from '~/app/hooks/useNotebookAPI';
|
||||
import { WorkspaceKindFormData } from '~/app/types';
|
||||
import { WorkspaceKindFileUpload } from './fileUpload/WorkspaceKindFileUpload';
|
||||
import { WorkspaceKindFormProperties } from './properties/WorkspaceKindFormProperties';
|
||||
|
@ -27,6 +28,7 @@ export type ValidationStatus = 'success' | 'error' | 'default';
|
|||
|
||||
export const WorkspaceKindForm: React.FC = () => {
|
||||
const navigate = useTypedNavigate();
|
||||
const { api } = useNotebookAPI();
|
||||
// TODO: Detect mode by route
|
||||
const [mode] = useState('create');
|
||||
const [yamlValue, setYamlValue] = useState('');
|
||||
|
@ -35,14 +37,6 @@ export const WorkspaceKindForm: React.FC = () => {
|
|||
const [validated, setValidated] = useState<ValidationStatus>('default');
|
||||
const workspaceKindFileUploadId = 'workspace-kind-form-fileupload-view';
|
||||
|
||||
const handleViewClick = (event: React.MouseEvent<unknown> | React.KeyboardEvent | MouseEvent) => {
|
||||
const { id } = event.currentTarget as HTMLElement;
|
||||
setView(
|
||||
id === workspaceKindFileUploadId
|
||||
? WorkspaceKindFormView.FileUpload
|
||||
: WorkspaceKindFormView.Form,
|
||||
);
|
||||
};
|
||||
const [data, setData, resetData] = useGenericObjectState<WorkspaceKindFormData>({
|
||||
properties: {
|
||||
displayName: '',
|
||||
|
@ -59,16 +53,41 @@ export const WorkspaceKindForm: React.FC = () => {
|
|||
},
|
||||
});
|
||||
|
||||
const handleCreate = useCallback(() => {
|
||||
// TODO: Complete handleCreate with API call to create a new WS kind
|
||||
if (!Object.keys(data).length) {
|
||||
return;
|
||||
}
|
||||
const handleViewClick = useCallback(
|
||||
(event: React.MouseEvent<unknown> | React.KeyboardEvent | MouseEvent) => {
|
||||
const { id } = event.currentTarget as HTMLElement;
|
||||
setView(
|
||||
id === workspaceKindFileUploadId
|
||||
? WorkspaceKindFormView.FileUpload
|
||||
: WorkspaceKindFormView.Form,
|
||||
);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const handleSubmit = useCallback(async () => {
|
||||
setIsSubmitting(true);
|
||||
}, [data]);
|
||||
// TODO: Complete handleCreate with API call to create a new WS kind
|
||||
try {
|
||||
if (mode === 'create') {
|
||||
const newWorkspaceKind = await api.createWorkspaceKind({}, yamlValue);
|
||||
console.info('New workspace kind created:', JSON.stringify(newWorkspaceKind));
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Error ${mode === 'edit' ? 'editing' : 'creating'} workspace kind: ${err}`);
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
navigate('workspaceKinds');
|
||||
}, [navigate, mode, api, yamlValue]);
|
||||
|
||||
const canSubmit = useMemo(
|
||||
() => !isSubmitting && yamlValue.length > 0 && validated === 'success',
|
||||
[yamlValue, isSubmitting, validated],
|
||||
);
|
||||
|
||||
const cancel = useCallback(() => {
|
||||
navigate('workspaceKindCreate');
|
||||
navigate('workspaceKinds');
|
||||
}, [navigate]);
|
||||
|
||||
return (
|
||||
|
@ -83,29 +102,30 @@ export const WorkspaceKindForm: React.FC = () => {
|
|||
</Content>
|
||||
<Content component={ContentVariants.p}>
|
||||
{view === WorkspaceKindFormView.FileUpload
|
||||
? `Please upload a Workspace Kind YAML file. Select 'Form View' to view
|
||||
and edit the workspace kind's information`
|
||||
? `Please upload or drag and drop a Workspace Kind YAML file.`
|
||||
: `View and edit the Workspace Kind's information. Some fields may not be
|
||||
represented in this form`}
|
||||
</Content>
|
||||
</FlexItem>
|
||||
<FlexItem>
|
||||
<ToggleGroup className="workspace-kind-form-header" aria-label="Toggle form view">
|
||||
<ToggleGroupItem
|
||||
text="YAML Upload"
|
||||
buttonId={workspaceKindFileUploadId}
|
||||
isSelected={view === WorkspaceKindFormView.FileUpload}
|
||||
onChange={handleViewClick}
|
||||
/>
|
||||
<ToggleGroupItem
|
||||
text="Form View"
|
||||
buttonId="workspace-kind-form-form-view"
|
||||
isSelected={view === WorkspaceKindFormView.Form}
|
||||
onChange={handleViewClick}
|
||||
isDisabled={yamlValue === '' || validated === 'error'}
|
||||
/>
|
||||
</ToggleGroup>
|
||||
</FlexItem>
|
||||
{mode === 'edit' && (
|
||||
<FlexItem>
|
||||
<ToggleGroup className="workspace-kind-form-header" aria-label="Toggle form view">
|
||||
<ToggleGroupItem
|
||||
text="YAML Upload"
|
||||
buttonId={workspaceKindFileUploadId}
|
||||
isSelected={view === WorkspaceKindFormView.FileUpload}
|
||||
onChange={handleViewClick}
|
||||
/>
|
||||
<ToggleGroupItem
|
||||
text="Form View"
|
||||
buttonId="workspace-kind-form-form-view"
|
||||
isSelected={view === WorkspaceKindFormView.Form}
|
||||
onChange={handleViewClick}
|
||||
isDisabled={yamlValue === '' || validated === 'error'}
|
||||
/>
|
||||
</ToggleGroup>
|
||||
</FlexItem>
|
||||
)}
|
||||
</Flex>
|
||||
</Stack>
|
||||
</PageSection>
|
||||
|
@ -144,8 +164,8 @@ export const WorkspaceKindForm: React.FC = () => {
|
|||
<Button
|
||||
variant="primary"
|
||||
ouiaId="Primary"
|
||||
onClick={handleCreate}
|
||||
isDisabled={!isSubmitting}
|
||||
onClick={handleSubmit}
|
||||
isDisabled={!canSubmit}
|
||||
>
|
||||
{mode === 'create' ? 'Create' : 'Edit'}
|
||||
</Button>
|
||||
|
|
|
@ -171,6 +171,48 @@ export const restDELETE = <T>(
|
|||
parseJSON: options?.parseJSON,
|
||||
});
|
||||
|
||||
/** POST -- but with YAML content directly in body */
|
||||
export const restYAML = <T>(
|
||||
host: string,
|
||||
path: string,
|
||||
yamlContent: string,
|
||||
queryParams?: Record<string, unknown>,
|
||||
options?: APIOptions,
|
||||
): Promise<T> => {
|
||||
const { method, ...otherOptions } = mergeRequestInit(options, { method: 'POST' });
|
||||
|
||||
const sanitizedQueryParams = queryParams
|
||||
? Object.entries(queryParams).reduce((acc, [key, value]) => {
|
||||
if (value) {
|
||||
return { ...acc, [key]: value };
|
||||
}
|
||||
return acc;
|
||||
}, {})
|
||||
: null;
|
||||
|
||||
const searchParams = sanitizedQueryParams
|
||||
? new URLSearchParams(sanitizedQueryParams).toString()
|
||||
: null;
|
||||
|
||||
return fetch(`${host}${path}${searchParams ? `?${searchParams}` : ''}`, {
|
||||
...otherOptions,
|
||||
headers: {
|
||||
...otherOptions.headers,
|
||||
...(DEV_MODE && { [AUTH_HEADER]: localStorage.getItem(AUTH_HEADER) }),
|
||||
'Content-Type': 'application/vnd.kubeflow-notebooks.manifest+yaml',
|
||||
},
|
||||
method,
|
||||
body: yamlContent,
|
||||
}).then((response) =>
|
||||
response.text().then((fetchedData) => {
|
||||
if (options?.parseJSON !== false) {
|
||||
return JSON.parse(fetchedData);
|
||||
}
|
||||
return fetchedData;
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
export const isNotebookResponse = <T>(response: unknown): response is ResponseBody<T> => {
|
||||
if (typeof response === 'object' && response !== null) {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
|
|
|
@ -90,7 +90,7 @@ export interface WorkspaceKindPodTemplate {
|
|||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||
export interface WorkspaceKindCreate {}
|
||||
export type WorkspaceKindCreate = string;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||
export interface WorkspaceKindUpdate {}
|
||||
|
|
|
@ -4,7 +4,6 @@ import {
|
|||
Workspace,
|
||||
WorkspaceCreate,
|
||||
WorkspaceKind,
|
||||
WorkspaceKindCreate,
|
||||
WorkspaceKindPatch,
|
||||
WorkspaceKindUpdate,
|
||||
WorkspacePatch,
|
||||
|
@ -63,10 +62,7 @@ export type StartWorkspace = (
|
|||
// WorkspaceKind
|
||||
export type ListWorkspaceKinds = (opts: APIOptions) => Promise<WorkspaceKind[]>;
|
||||
export type GetWorkspaceKind = (opts: APIOptions, kind: string) => Promise<WorkspaceKind>;
|
||||
export type CreateWorkspaceKind = (
|
||||
opts: APIOptions,
|
||||
data: RequestData<WorkspaceKindCreate>,
|
||||
) => Promise<WorkspaceKind>;
|
||||
export type CreateWorkspaceKind = (opts: APIOptions, data: string) => Promise<WorkspaceKind>;
|
||||
export type UpdateWorkspaceKind = (
|
||||
opts: APIOptions,
|
||||
kind: string,
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
restGET,
|
||||
restPATCH,
|
||||
restUPDATE,
|
||||
restYAML,
|
||||
} from '~/shared/api/apiUtils';
|
||||
import { handleRestFailures } from '~/shared/api/errorUtils';
|
||||
import {
|
||||
|
@ -96,7 +97,7 @@ export const getWorkspaceKind: GetWorkspaceKindAPI = (hostPath) => (opts, kind)
|
|||
);
|
||||
|
||||
export const createWorkspaceKind: CreateWorkspaceKindAPI = (hostPath) => (opts, data) =>
|
||||
handleRestFailures(restCREATE(hostPath, `/workspacekinds`, data, {}, opts)).then((response) =>
|
||||
handleRestFailures(restYAML(hostPath, `/workspacekinds`, data, {}, opts)).then((response) =>
|
||||
extractNotebookResponse<WorkspaceKind>(response),
|
||||
);
|
||||
|
||||
|
|
Loading…
Reference in New Issue