Skip to content

Commit

Permalink
refactor(FR-343): migrate maintenance page to react by using SettingL…
Browse files Browse the repository at this point in the history
…ist (#3009)

### This PR resolves [#3006](#3006) [(FR-343)](https://lablup.atlassian.net/browse/FR-343)

**Changes**
* Updated routing from LitElement to React components.
* From now on, the `/maintenance` page will operate exclusively with React
* Updated `SettingList` component
	* `isShowChangedOptionFilter`, `isShowResetButton`, and `isShowSearchBar` have been added as props to SettingList. Now, these features can be disabled when they are unnecessary.
* Updated i18n.

**Checklist:** (if applicable)

- [ ] Mention to the original issue
- [ ] Documentation
- [ ] Minium required manager version
- [ ] Specific setting for review (eg., KB link, endpoint or how to setup)
- [ ] Minimum requirements to check during review
- [ ] Test case(s) to demonstrate the difference of before/after

[FR-343]: https://lablup.atlassian.net/browse/FR-343?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
  • Loading branch information
nowgnuesLee committed Jan 15, 2025
1 parent c04f7c9 commit 529a225
Show file tree
Hide file tree
Showing 31 changed files with 275 additions and 578 deletions.
11 changes: 11 additions & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"words": [
"ahooks",
"Antd",
"Automount",
"backend.ai-webserver",
"Backendai",
"backendaiclient",
Expand All @@ -13,15 +15,24 @@
"Frgmt",
"Frgmts",
"Gaudi",
"Hyperaccel",
"keypair",
"Keypairs",
"Lablup",
"lucide",
"noti",
"OPENBLAS",
"Popconfirm",
"preopen",
"rescan",
"Rescanning",
"RNGD",
"shmem",
"Signout",
"superadmin",
"Tensorboard",
"textbox",
"Totp",
"vaadin",
"vfolder",
"vfolders",
Expand Down
6 changes: 6 additions & 0 deletions react/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ const ComputeSessionList = React.lazy(
() => import('./components/ComputeSessionList'),
);
const AgentSummaryPage = React.lazy(() => import('./pages/AgentSummaryPage'));
const MaintenancePage = React.lazy(() => import('./pages/MaintenancePage'));

interface CustomHandle {
title?: string;
Expand Down Expand Up @@ -319,6 +320,11 @@ const router = createBrowserRouter([
},
{
path: '/maintenance',
element: (
<BAIErrorBoundary>
<MaintenancePage />
</BAIErrorBoundary>
),
handle: { labelKey: 'webui.menu.Maintenance' },
},
{
Expand Down
141 changes: 141 additions & 0 deletions react/src/components/MaintenanceSettingList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { useSuspendedBackendaiClient } from '../hooks';
import {
CLOSING_DURATION,
useSetBAINotification,
} from '../hooks/useBAINotification';
import SettingList, { SettingGroup } from './SettingList';
import { RedoOutlined } from '@ant-design/icons';
import { Button } from 'antd';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';

const MaintenanceSettingList = () => {
const [isRecalculating, setIsRecalculating] = useState(false);
const [isRescanning, setIsRescanning] = useState(false);

const { t } = useTranslation();
const { upsertNotification } = useSetBAINotification();
const baiClient = useSuspendedBackendaiClient();

const recalculateUsage = () => {
setIsRecalculating(true);

upsertNotification({
message: t('maintenance.RecalculateUsage'),
description: t('maintenance.Recalculating'),
open: true,
backgroundTask: {
status: 'pending',
promise: baiClient.maintenance
.recalculate_usage()
.finally(() => setIsRecalculating(false)),
statusDescriptions: {
pending: t('maintenance.Recalculating'),
resolved: t('maintenance.RecalculationFinished'),
rejected: t('maintenance.RecalculationFailed'),
},
},
});
};

const rescanImages = () => {
setIsRescanning(true);
const notiKey = upsertNotification({
message: t('maintenance.RescanImages'),
description: t('maintenance.RescanImageScanning'),
open: true,
backgroundTask: {
status: 'pending',
},
});
// If values can be passed through resolve, please refactor the following function using promises
baiClient.maintenance
.rescan_images()
.then(({ rescan_images }) => {
if (rescan_images.ok) {
upsertNotification({
key: notiKey,
backgroundTask: {
status: 'pending',
percent: 0,
taskId: rescan_images.task_id,
statusDescriptions: {
pending: t('maintenance.RescanImageScanning'),
resolved: t('maintenance.RescanImageFinished'),
rejected: t('maintenance.RescanFailed'),
},
},
duration: 0,
});
} else {
throw new Error(t('maintenance.RescanFailed'));
}
})
.catch((err: any) => {
upsertNotification({
key: notiKey,
// description: painKiller.relieve(err?.title),
backgroundTask: {
status: 'rejected',
statusDescriptions: {
rejected: err?.message || t('maintenance.RescanFailed'),
},
},
open: true,
duration: CLOSING_DURATION,
});
})
.finally(() => {
setIsRescanning(false);
});
};

const settingGroupList: SettingGroup = [
{
title: t('maintenance.Fix'),
settingItems: [
{
type: 'custom',
title: t('maintenance.MatchDatabase'),
description: t('maintenance.DescMatchDatabase'),
children: (
<Button
icon={<RedoOutlined />}
onClick={recalculateUsage}
loading={isRecalculating}
>
{isRecalculating
? t('maintenance.Recalculating')
: t('maintenance.RecalculateUsage')}
</Button>
),
},
],
},
{
title: t('maintenance.ImagesEnvironment'),
settingItems: [
{
type: 'custom',
title: t('maintenance.RescanImageList'),
description: t('maintenance.DescRescanImageList'),
children: (
<Button
icon={<RedoOutlined />}
onClick={rescanImages}
loading={isRescanning}
>
{isRescanning
? t('maintenance.RescanImageScanning')
: t('maintenance.RescanImages')}
</Button>
),
},
],
},
];

return <SettingList settingGroup={settingGroupList} showSearchBar />;
};

export default MaintenanceSettingList;
55 changes: 36 additions & 19 deletions react/src/components/SettingList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,25 @@ const useStyles = createStyles(({ css }) => ({
`,
}));

export type SettingGroup = Array<{
title: string;
settingItems: SettingItemProps[];
}>;

interface SettingPageProps {
settingGroup: { title: string; settingItems: SettingItemProps[] }[];
settingGroup: SettingGroup;
tabDirection?: 'top' | 'left';
showChangedOptionFilter?: boolean;
showResetButton?: boolean;
showSearchBar?: boolean;
}

const SettingList: React.FC<SettingPageProps> = ({
settingGroup,
tabDirection = 'left',
showChangedOptionFilter,
showResetButton,
showSearchBar,
}) => {
const { t } = useTranslation();
const { token } = theme.useToken();
Expand Down Expand Up @@ -75,24 +86,30 @@ const SettingList: React.FC<SettingPageProps> = ({
}}
>
<Flex justify="start" gap={'xs'}>
<Input
prefix={<SearchOutlined />}
placeholder={t('settings.SearchPlaceholder')}
onChange={(e) => setSearchValue(e.target.value)}
value={searchValue}
/>
<Checkbox
onChange={(e) => setChangedOptionFilter(e.target.checked)}
style={{ whiteSpace: 'nowrap' }}
>
{t('settings.ShowOnlyChanged')}
</Checkbox>
<Button
icon={<RedoOutlined />}
onClick={() => setIsOpenResetChangesModal()}
>
{t('button.Reset')}
</Button>
{!!showSearchBar && (
<Input
prefix={<SearchOutlined />}
placeholder={t('settings.SearchPlaceholder')}
onChange={(e) => setSearchValue(e.target.value)}
value={searchValue}
/>
)}
{!!showChangedOptionFilter && (
<Checkbox
onChange={(e) => setChangedOptionFilter(e.target.checked)}
style={{ whiteSpace: 'nowrap' }}
>
{t('settings.ShowOnlyChanged')}
</Checkbox>
)}
{!!showResetButton && (
<Button
icon={<RedoOutlined />}
onClick={() => setIsOpenResetChangesModal()}
>
{t('button.Reset')}
</Button>
)}
</Flex>
<Tabs
className={styles.TabStyles}
Expand Down
11 changes: 11 additions & 0 deletions react/src/hooks/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,17 @@ export type BackendAIClient = {
end?: string | Date | number | null,
) => string;
};
maintenance: {
rescan_images: (registry?: string) => Promise<{
rescan_images: {
msg: string;
ok: boolean;
task_id: string;
};
}>;
recalculate_usage: () => Promise<any>;
[key: string]: any;
};
};
export const useSuspendedBackendaiClient = () => {
const { data: client } = useSuspenseTanQuery<any>({
Expand Down
Loading

0 comments on commit 529a225

Please sign in to comment.