Merge pull request #549 from ylei-tsubame/issues/404-prevent-peer-autocomplete

Web UI: patch 404, 545, 546
main
Digimer 1 year ago committed by GitHub
commit 20ae35758a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      striker-ui-api/out/index.js
  2. 2
      striker-ui-api/src/lib/accessModule.ts
  3. 4
      striker-ui-api/src/lib/disassembleEntityId.ts
  4. 20
      striker-ui-api/src/lib/request_handlers/anvil/buildQueryAnvilDetail.ts
  5. 6
      striker-ui-api/src/lib/request_handlers/host/getHostConnection.ts
  6. 4
      striker-ui-api/src/lib/request_handlers/manifest/getManifestDetail.ts
  7. 2
      striker-ui-api/src/lib/request_handlers/manifest/getManifestTemplate.ts
  8. 2
      striker-ui-api/src/lib/request_handlers/ssh-key/getSSHKeyConflict.ts
  9. 2
      striker-ui-api/src/lib/shell.ts
  10. 4
      striker-ui/components/Files/EditFileForm.tsx
  11. 91
      striker-ui/components/Files/ManageFilePanel.tsx
  12. 73
      striker-ui/components/List.tsx
  13. 6
      striker-ui/components/ManageFence/ManageFencePanel.tsx
  14. 6
      striker-ui/components/ManageManifest/ManageManifestPanel.tsx
  15. 106
      striker-ui/components/StrikerConfig/AddPeerDialog.tsx
  16. 55
      striker-ui/hooks/useActiveFetch.ts
  17. 6
      striker-ui/hooks/useChecklist.tsx
  18. 1
      striker-ui/out/_next/static/BhFewlGkfrUA_bCvxhgLY/_buildManifest.js
  19. 0
      striker-ui/out/_next/static/BhFewlGkfrUA_bCvxhgLY/_middlewareManifest.js
  20. 0
      striker-ui/out/_next/static/BhFewlGkfrUA_bCvxhgLY/_ssgManifest.js
  21. 1
      striker-ui/out/_next/static/aBwJM8_Hf5TQtM8KFF7tW/_buildManifest.js
  22. 1
      striker-ui/out/_next/static/chunks/209-4e2794319babfeec.js
  23. 1
      striker-ui/out/_next/static/chunks/247-0dbdd6350b819672.js
  24. 1
      striker-ui/out/_next/static/chunks/27-7790e406eb2ea28d.js
  25. 2
      striker-ui/out/_next/static/chunks/336-33ece0c8120f3bd4.js
  26. 2
      striker-ui/out/_next/static/chunks/404-b8e9ff2043a0d30c.js
  27. 2
      striker-ui/out/_next/static/chunks/560-a9c9ecda0eca25a9.js
  28. 1
      striker-ui/out/_next/static/chunks/62-09a1812bcc63d819.js
  29. 1
      striker-ui/out/_next/static/chunks/62-1cb6d52404130873.js
  30. 1
      striker-ui/out/_next/static/chunks/638-13a283c3a7da370b.js
  31. 2
      striker-ui/out/_next/static/chunks/707-705fb5e735d81042.js
  32. 2
      striker-ui/out/_next/static/chunks/86-d7025c9609028f44.js
  33. 1
      striker-ui/out/_next/static/chunks/94-8322ed453a3c08f0.js
  34. 1
      striker-ui/out/_next/static/chunks/94-f83c1e7821f76736.js
  35. 1
      striker-ui/out/_next/static/chunks/960-e28948d6eb4c8144.js
  36. 1
      striker-ui/out/_next/static/chunks/987-1ff0d82724b0e58b.js
  37. 2
      striker-ui/out/_next/static/chunks/pages/anvil-3bce568d47e8eaba.js
  38. 1
      striker-ui/out/_next/static/chunks/pages/config-511a465cb55668af.js
  39. 1
      striker-ui/out/_next/static/chunks/pages/config-f22ac92929f0daf0.js
  40. 1
      striker-ui/out/_next/static/chunks/pages/file-manager-53de9163caaf5a86.js
  41. 1
      striker-ui/out/_next/static/chunks/pages/file-manager-a085c3bead0f489f.js
  42. 1
      striker-ui/out/_next/static/chunks/pages/index-0bfb652a4f03dc4d.js
  43. 1
      striker-ui/out/_next/static/chunks/pages/index-e5b260a0ddaa050c.js
  44. 2
      striker-ui/out/_next/static/chunks/pages/init-59fe9f29b6489800.js
  45. 2
      striker-ui/out/_next/static/chunks/pages/login-183a6e481fd67cca.js
  46. 1
      striker-ui/out/_next/static/chunks/pages/manage-element-a689bf0140460775.js
  47. 1
      striker-ui/out/_next/static/chunks/pages/manage-element-d8b8ab9027cbbb98.js
  48. 2
      striker-ui/out/anvil.html
  49. 2
      striker-ui/out/config.html
  50. 2
      striker-ui/out/file-manager.html
  51. 2
      striker-ui/out/index.html
  52. 2
      striker-ui/out/init.html
  53. 2
      striker-ui/out/login.html
  54. 2
      striker-ui/out/manage-element.html
  55. 2
      striker-ui/out/server.html
  56. 1
      striker-ui/types/List.d.ts
  57. 1
      striker-ui/types/ManageFile.d.ts

File diff suppressed because one or more lines are too long

@ -463,7 +463,7 @@ const getVncinfo = async (serverUuid: string): Promise<ServerDetailVncInfo> => {
const [[vncinfo]] = rows;
const [domain, rPort] = vncinfo.split(':');
const port = Number.parseInt(rPort);
const port = Number(rPort);
const protocol = 'ws';
return { domain, port, protocol };

@ -1,7 +1,7 @@
export const getEntityName = (id: string) => id.replace(/\d*$/, '');
export const getEntityNumber = (id: string) =>
Number.parseInt(id.replace(/^[^\d]*/, ''));
Number(id.replace(/^[^\d]*/, ''));
export const getEntityParts = (id: string) => {
let name = '';
@ -13,7 +13,7 @@ export const getEntityParts = (id: string) => {
const parts = matchResult;
name = parts[1];
number = Number.parseInt(parts[2]);
number = Number(parts[2]);
}
return { name, number };

@ -258,17 +258,17 @@ const buildQueryAnvilDetail = ({
stores = {};
}
if (!previous[anvilUUID]) {
if (anvilUUID && !previous[anvilUUID]) {
previous[anvilUUID] = {
anvilUUID,
anvilName,
anvilDescription,
anvilTotalCPUCores: parseInt(anvilTotalCPUCores),
anvilTotalCPUCores: Number(anvilTotalCPUCores),
anvilTotalMemory: String(anvilTotalMemory),
anvilTotalAllocatedCPUCores: parseInt(
anvilTotalAllocatedCPUCores: Number(
anvilTotalAllocatedCPUCores,
),
anvilTotalAvailableCPUCores: parseInt(
anvilTotalAvailableCPUCores: Number(
anvilTotalAvailableCPUCores,
),
} as AnvilDetailForProvisionServer;
@ -276,16 +276,16 @@ const buildQueryAnvilDetail = ({
puuid = anvilUUID;
}
if (!hosts[hostUUID]) {
if (hostUUID && !hosts[hostUUID]) {
hosts[hostUUID] = {
hostUUID,
hostName,
hostCPUCores: parseInt(hostCPUCores),
hostCPUCores: Number(hostCPUCores),
hostMemory: String(hostMemory),
};
}
if (!servers[serverUUID]) {
if (serverUUID && !servers[serverUUID]) {
const serverMemory =
dSize(serverMemoryValue, {
fromUnit: serverMemoryUnit,
@ -297,12 +297,12 @@ const buildQueryAnvilDetail = ({
servers[serverUUID] = {
serverUUID,
serverName,
serverCPUCores: parseInt(serverCPUCores),
serverCPUCores: Number(serverCPUCores),
serverMemory,
};
}
if (!stores[storageGroupUUID]) {
if (storageGroupUUID && !stores[storageGroupUUID]) {
stores[storageGroupUUID] = {
storageGroupUUID,
storageGroupName,
@ -311,7 +311,7 @@ const buildQueryAnvilDetail = ({
};
}
if (!files[fileUUID]) {
if (fileUUID && !files[fileUUID]) {
files[fileUUID] = {
fileUUID,
fileName,

@ -15,7 +15,7 @@ const buildHostConnections = (
) =>
Object.entries(databaseHash).reduce<HostConnectionOverview>(
(previous, [hostUUID, { host: ipAddress, ping, port: rawPort, user }]) => {
const port = parseInt(rawPort);
const port = Number(rawPort);
if (hostUUID === fromHostUUID) {
previous.inbound.port = port;
@ -91,8 +91,8 @@ export const getHostConnection = buildGetRequestHandler(
hostUUID,
ipAddress,
ipAddressUUID,
networkLinkNumber: parseInt(rawNetworkLinkNumber),
networkNumber: parseInt(rawNetworkNumber),
networkLinkNumber: Number(rawNetworkLinkNumber),
networkNumber: Number(rawNetworkNumber),
networkType,
};
},

@ -217,7 +217,7 @@ export const getManifestDetail: RequestHandler = async (request, response) => {
name,
networkConfig: {
dnsCsv,
mtu: Number.parseInt(mtu),
mtu: Number(mtu),
networks: Object.entries(networkList)
.sort(handleSortNetworks)
.reduce<ManifestDetailNetworkList>(
@ -252,7 +252,7 @@ export const getManifestDetail: RequestHandler = async (request, response) => {
ntpCsv,
},
prefix,
sequence: Number.parseInt(sequence),
sequence: Number(sequence),
};
response.status(200).send(manifestData);

@ -105,7 +105,7 @@ export const getManifestTemplate: RequestHandler = async (
}
if (lastSequence) {
previous.sequence = Number.parseInt(lastSequence) + 1;
previous.sequence = Number(lastSequence) + 1;
}
return previous;

@ -38,7 +38,7 @@ export const getSSHKeyConflict = buildGetRequestHandler(
previous[hostUUIDKey][stateUUID] = {
badFile,
badLine: parseInt(badLine),
badLine: Number(badLine),
hostName,
hostUUID,
ipAddress,

@ -48,7 +48,7 @@ export const uuidgen = (...args: string[]) =>
systemCall(SERVER_PATHS.usr.bin.uuidgen.self, args);
export const resolveId = (id: number | string, database: string) =>
Number.parseInt(getent(database, String(id)).split(':', 3)[2]);
Number(getent(database, String(id)).split(':', 3)[2]);
export const resolveGid = (id: number | string) => resolveId(id, 'group');

@ -66,7 +66,7 @@ const toEditFileRequestBody = (
};
const EditFileForm: FC<EditFileFormProps> = (props) => {
const { anvils, drHosts, previous: file } = props;
const { anvils, drHosts, onSuccess, previous: file } = props;
const messageGroupRef = useRef<MessageGroupForwardedRefContent>({});
@ -113,6 +113,8 @@ const EditFileForm: FC<EditFileFormProps> = (props) => {
.put(`/file/${file.uuid}`, body)
.then(() => {
setApiMessage({ children: <>File updated.</> });
onSuccess?.call(null);
})
.catch((error) => {
const emsg = handleAPIError(error);

@ -12,13 +12,13 @@ import { DialogWithHeader } from '../Dialog';
import Divider from '../Divider';
import EditFileForm from './EditFileForm';
import FlexBox from '../FlexBox';
import handleAPIError from '../../lib/handleAPIError';
import List from '../List';
import MessageGroup, { MessageGroupForwardedRefContent } from '../MessageGroup';
import { Panel, PanelHeader } from '../Panels';
import periodicFetch from '../../lib/fetchers/periodicFetch';
import Spinner from '../Spinner';
import { BodyText, HeaderText, MonoText } from '../Text';
import useActiveFetch from '../../hooks/useActiveFetch';
import useChecklist from '../../hooks/useChecklist';
import useConfirmDialogProps from '../../hooks/useConfirmDialogProps';
import useFetch from '../../hooks/useFetch';
@ -118,15 +118,29 @@ const ManageFilePanel: FC = () => {
const [file, setFile] = useProtectedState<APIFileDetail | undefined>(
undefined,
);
const [loadingFile, setLoadingFile] = useProtectedState<boolean>(false);
const [files, setFiles] = useProtectedState<APIFileOverviewList | undefined>(
undefined,
);
const { data: rows, isLoading: loadingFiles } = periodicFetch<string[][]>(
const { isLoading: loadingFilesPeriodic } = periodicFetch<string[][]>(
`${API_BASE_URL}/file`,
{
onSuccess: (rows) => {
setFiles(toFileOverviewList(rows));
},
},
);
const files = useMemo(
() => (rows ? toFileOverviewList(rows) : undefined),
[rows],
const { fetch: getFiles, loading: loadingFilesActive } = useActiveFetch<
string[][]
>({
onData: (data) => setFiles(toFileOverviewList(data)),
url: '/file',
});
const loadingFiles = useMemo<boolean>(
() => loadingFilesPeriodic || loadingFilesActive,
[loadingFilesActive, loadingFilesPeriodic],
);
const {
@ -136,6 +150,7 @@ const ManageFilePanel: FC = () => {
hasAllChecks,
hasChecks,
multipleItems,
resetChecks,
setAllChecks,
setCheck,
} = useChecklist({
@ -148,28 +163,16 @@ const ManageFilePanel: FC = () => {
[],
);
const getFileDetail = useCallback(
(fileUuid: string) => {
setLoadingFile(true);
api
.get<string[][]>(`file/${fileUuid}`)
.then(({ data }) => {
setFile(toFileDetail(data));
})
.catch((error) => {
const emsg = handleAPIError(error);
emsg.children = <>Failed to get file detail. {emsg.children}</>;
setApiMessage(emsg);
})
.finally(() => {
setLoadingFile(false);
});
const { fetch: getFile, loading: loadingFile } = useActiveFetch<string[][]>({
onData: (data) => setFile(toFileDetail(data)),
onError: ({ children: previous, ...rest }) => {
setApiMessage({
children: <>Failed to get file detail. {previous}</>,
...rest,
});
},
[setApiMessage, setFile, setLoadingFile],
);
url: '/file/',
});
const { data: rawAnvils, loading: loadingAnvils } =
useFetch<APIAnvilOverviewArray>('/anvil', {
@ -226,7 +229,13 @@ const ManageFilePanel: FC = () => {
setConfirmDialogProps(
buildDeleteDialogProps({
onProceedAppend: () => {
checks.forEach((fileUuid) => api.delete(`/file/${fileUuid}`));
const promises = checks.map((fileUuid) =>
api.delete(`/file/${fileUuid}`),
);
Promise.all(promises).then(() => getFiles());
resetChecks();
},
getConfirmDialogTitle: (count) =>
`Delete the following ${count} file(s)?`,
@ -243,7 +252,7 @@ const ManageFilePanel: FC = () => {
}}
onItemClick={(value, uuid) => {
editFormDialogRef.current?.setOpen(true);
getFileDetail(uuid);
getFile(uuid);
}}
renderListItem={(uuid, { checksum, name, size, type }) => (
<FlexBox columnSpacing={0} fullWidth md="row" xs="column">
@ -266,10 +275,12 @@ const ManageFilePanel: FC = () => {
edit,
files,
getCheck,
getFileDetail,
getFile,
getFiles,
hasAllChecks,
hasChecks,
multipleItems,
resetChecks,
setAllChecks,
setCheck,
setConfirmDialogProps,
@ -289,13 +300,14 @@ const ManageFilePanel: FC = () => {
);
const loadingAddForm = useMemo<boolean>(
() => loadingFiles || loadingAnvils || loadingDrHosts,
[loadingAnvils, loadingDrHosts, loadingFiles],
() => loadingFilesPeriodic || loadingAnvils || loadingDrHosts,
[loadingAnvils, loadingDrHosts, loadingFilesPeriodic],
);
const loadingEditForm = useMemo<boolean>(
() => loadingFiles || loadingAnvils || loadingDrHosts || loadingFile,
[loadingAnvils, loadingDrHosts, loadingFile, loadingFiles],
() =>
loadingFilesPeriodic || loadingAnvils || loadingDrHosts || loadingFile,
[loadingAnvils, loadingDrHosts, loadingFile, loadingFilesPeriodic],
);
const addForm = useMemo(
@ -309,9 +321,16 @@ const ManageFilePanel: FC = () => {
anvils &&
drHosts &&
file && (
<EditFileForm anvils={anvils} drHosts={drHosts} previous={file} />
<EditFileForm
anvils={anvils}
drHosts={drHosts}
onSuccess={() => {
getFiles();
}}
previous={file}
/>
),
[anvils, drHosts, file],
[anvils, drHosts, file, getFiles],
);
return (

@ -22,6 +22,7 @@ import Checkbox from './Checkbox';
import Divider from './Divider';
import FlexBox from './FlexBox';
import IconButton from './IconButton';
import Spinner from './Spinner';
import { BodyText } from './Text';
const List = forwardRef(
@ -43,6 +44,7 @@ const List = forwardRef(
listItemProps: { sx: listItemSx, ...restListItemProps } = {},
listItems,
listProps: { sx: listSx, ...restListProps } = {},
loading,
onAdd,
onDelete,
onEdit,
@ -186,48 +188,47 @@ const List = forwardRef(
);
const listItemElements = useMemo(() => {
let result = listEmptyElement;
if (loading) return <Spinner mt={0} />;
if (listItems) {
const entries = Object.entries(listItems);
if (!listItems) return listEmptyElement;
if (entries.length > 0) {
result = entries.map(([key, value]) => {
const listItem = renderListItem(key, value);
const entries = Object.entries(listItems);
return (
<MUIListItem
{...restListItemProps}
key={`${listItemKeyPrefix}-${key}`}
sx={{ paddingLeft: 0, paddingRight: 0, ...listItemSx }}
>
{listItemCheckbox(
key,
renderListItemCheckboxState?.call(null, key, value),
getListItemCheckboxProps?.call(null, key, value),
)}
{isAllowItemButton ? (
<ListItemButton
onClick={(...args) => {
onItemClick?.call(null, value, key, ...args);
}}
sx={{ borderRadius: BORDER_RADIUS }}
>
{listItem}
</ListItemButton>
) : (
listItem
)}
</MUIListItem>
);
});
}
}
if (entries.length <= 0) return listEmptyElement;
return entries.map(([key, value]) => {
const listItem = renderListItem(key, value);
return result;
return (
<MUIListItem
{...restListItemProps}
key={`${listItemKeyPrefix}-${key}`}
sx={{ paddingLeft: 0, paddingRight: 0, ...listItemSx }}
>
{listItemCheckbox(
key,
renderListItemCheckboxState?.call(null, key, value),
getListItemCheckboxProps?.call(null, key, value),
)}
{isAllowItemButton ? (
<ListItemButton
onClick={(...args) => {
onItemClick?.call(null, value, key, ...args);
}}
sx={{ borderRadius: BORDER_RADIUS }}
>
{listItem}
</ListItemButton>
) : (
listItem
)}
</MUIListItem>
);
});
}, [
listEmptyElement,
loading,
listItems,
listEmptyElement,
renderListItem,
restListItemProps,
listItemKeyPrefix,

@ -160,7 +160,7 @@ const ManageFencePanel: FC = () => {
checks,
getCheck,
hasChecks,
resetChecklist,
resetChecks,
setCheck,
} = useChecklist({ list: fenceOverviews });
@ -246,7 +246,7 @@ const ManageFencePanel: FC = () => {
method: 'delete',
onSuccess: () => {
getFenceOverviews();
resetChecklist();
resetChecks();
},
url: '/fence',
});
@ -382,7 +382,7 @@ const ManageFencePanel: FC = () => {
getFormSummaryEntryLabel,
hasChecks,
isEditFences,
resetChecklist,
resetChecks,
setCheck,
setConfirmDialogProps,
setFormDialogProps,

@ -217,7 +217,7 @@ const ManageManifestPanel: FC = () => {
checks,
getCheck,
hasChecks,
resetChecklist,
resetChecks,
setCheck,
} = useChecklist({
list: manifestOverviews,
@ -445,7 +445,7 @@ const ManageManifestPanel: FC = () => {
method: 'delete',
onSuccess: () => {
getManifestOverviews();
resetChecklist();
resetChecks();
},
url: `/manifest`,
});
@ -503,7 +503,7 @@ const ManageManifestPanel: FC = () => {
hasChecks,
isEditManifests,
manifestOverviews,
resetChecklist,
resetChecks,
setCheck,
setConfirmDialogProps,
setManifestDetail,

@ -11,7 +11,6 @@ import INPUT_TYPES from '../../lib/consts/INPUT_TYPES';
import api from '../../lib/api';
import buildMapToMessageSetter from '../../lib/buildMapToMessageSetter';
import buildNumberTestBatch from '../../lib/test_input/buildNumberTestBatch';
import buildObjectStateSetterCallback from '../../lib/buildObjectStateSetterCallback';
import CheckboxWithLabel from '../CheckboxWithLabel';
import ConfirmDialog from '../ConfirmDialog';
@ -27,8 +26,7 @@ import {
buildIPAddressTestBatch,
buildPeacefulStringTestBatch,
} from '../../lib/test_input';
import { BodyText, HeaderText } from '../Text';
import useProtect from '../../hooks/useProtect';
import { HeaderText } from '../Text';
import useProtectedState from '../../hooks/useProtectedState';
const IT_IDS = {
@ -51,8 +49,6 @@ const AddPeerDialog = forwardRef<
ConfirmDialogForwardedRefContent,
AddPeerDialogProps
>(({ formGridColumns = 2 }, ref) => {
const { protect } = useProtect();
const inputPeerDBPortRef = useRef<InputForwardedRefContent<'string'>>({});
const inputPeerIPAddressRef = useRef<InputForwardedRefContent<'string'>>({});
const inputPeerPasswordRef = useRef<InputForwardedRefContent<'string'>>({});
@ -65,7 +61,7 @@ const AddPeerDialog = forwardRef<
}>({});
const [isEnablePingTest, setIsEnablePingTest] = useState<boolean>(false);
const [isSubmittingAddPeer, setIsSubmittingAddPeer] =
useProtectedState<boolean>(false, protect);
useProtectedState<boolean>(false);
const buildInputFirstRenderFunction = useCallback(
(key: string) =>
@ -100,42 +96,22 @@ const AddPeerDialog = forwardRef<
<Grid
columns={{ xs: 1, sm: formGridColumns }}
layout={{
'add-peer-user-and-ip-address': {
'add-peer-ip-address': {
children: (
<FlexBox row spacing=".3em">
<InputWithRef
input={
<OutlinedInputWithLabel
formControlProps={{
sx: { minWidth: '4.6em', width: '25%' },
}}
id="add-peer-user-input"
inputProps={{ placeholder: 'admin' }}
label={LABEL.user}
/>
}
inputTestBatch={buildPeacefulStringTestBatch(
LABEL.user,
() => {
msgSetters.user();
},
{
onFinishBatch: buildFinishInputTestBatchFunction(
IT_IDS.user,
),
},
(message) => {
msgSetters.user({ children: message });
},
)}
onFirstRender={buildInputFirstRenderFunction(IT_IDS.user)}
ref={inputPeerUserRef}
/>
<BodyText>@</BodyText>
<InputWithRef
input={
<OutlinedInputWithLabel
id="add-peer-ip-address-input"
inputProps={{
// Initiallize the field as read-only, then unlock
// when the user focuses; this avoids browser's
// auto-complete.
readOnly: true,
onFocus: (event) => {
event.target.readOnly = false;
},
}}
label={LABEL.ipAddress}
/>
}
@ -193,64 +169,6 @@ const AddPeerDialog = forwardRef<
/>
),
},
'add-peer-db-and-ssh-port': {
children: (
<FlexBox row>
<InputWithRef
input={
<OutlinedInputWithLabel
id="add-peer-db-port-input"
inputProps={{ placeholder: '5432' }}
label={LABEL.dbPort}
/>
}
inputTestBatch={buildNumberTestBatch(
LABEL.dbPort,
() => {
msgSetters.dbPort();
},
{
onFinishBatch: buildFinishInputTestBatchFunction(
IT_IDS.dbPort,
),
},
(message) => {
msgSetters.dbPort({ children: message });
},
)}
onFirstRender={buildInputFirstRenderFunction(IT_IDS.dbPort)}
ref={inputPeerDBPortRef}
/>
<InputWithRef
input={
<OutlinedInputWithLabel
id="add-peer-ssh-port-input"
inputProps={{ placeholder: '22' }}
label={LABEL.sshPort}
/>
}
inputTestBatch={buildNumberTestBatch(
LABEL.sshPort,
() => {
msgSetters.sshPort();
},
{
onFinishBatch: buildFinishInputTestBatchFunction(
IT_IDS.sshPort,
),
},
(message) => {
msgSetters.sshPort({ children: message });
},
)}
onFirstRender={buildInputFirstRenderFunction(
IT_IDS.sshPort,
)}
ref={inputPeerSSHPortRef}
/>
</FlexBox>
),
},
'add-peer-is-ping': {
children: (
<CheckboxWithLabel

@ -0,0 +1,55 @@
import { useCallback } from 'react';
import api from '../lib/api';
import handleAPIError from '../lib/handleAPIError';
import useProtectedState from './useProtectedState';
type ActiveFetchSetter<T> = (data: T) => void;
type ActiveFetcher = (url?: string) => void;
type ActiveFetchHookResponse = {
fetch: ActiveFetcher;
loading: boolean;
};
const useActiveFetch = <Data>(
options: {
onData?: ActiveFetchSetter<Data>;
onError?: (emsg: Message) => void;
url?: string;
} = {},
): ActiveFetchHookResponse => {
const { onError, onData, url: urlPrefix = '' } = options;
const [loading, setLoading] = useProtectedState<boolean>(false);
const fetch = useCallback<ActiveFetcher>(
(urlPostfix = '') => {
const url = `${urlPrefix}${urlPostfix}`;
if (!url) return;
setLoading(true);
api
.get<Data>(url)
.then(({ data }) => {
onData?.call(null, data);
})
.catch((error) => {
const emsg = handleAPIError(error);
onError?.call(null, emsg);
})
.finally(() => {
setLoading(false);
});
},
[urlPrefix, setLoading, onError, onData],
);
return { fetch, loading };
};
export default useActiveFetch;

@ -16,7 +16,7 @@ const useChecklist = ({
hasAllChecks: boolean;
hasChecks: boolean;
multipleItems: boolean;
resetChecklist: () => void;
resetChecks: () => void;
setAllChecks: SetAllChecksFunction;
setCheck: SetCheckFunction;
} => {
@ -62,7 +62,7 @@ const useChecklist = ({
[checklist],
);
const resetChecklist = useCallback(() => setChecklist({}), []);
const resetChecks = useCallback(() => setChecklist({}), []);
const setAllChecks = useCallback<SetAllChecksFunction>(
(checked) =>
@ -92,7 +92,7 @@ const useChecklist = ({
hasAllChecks,
hasChecks,
multipleItems,
resetChecklist,
resetChecks,
setAllChecks,
setCheck,
};

@ -0,0 +1 @@
self.__BUILD_MANIFEST=function(s,c,a,e,t,n,i,f,d,b,u,k,h,j,r,g,l){return{__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":[s,a,e,f,d,"static/chunks/82-b2661d1af04f38ff.js",c,t,n,i,h,j,"static/chunks/pages/index-0bfb652a4f03dc4d.js"],"/_error":["static/chunks/pages/_error-2280fa386d040b66.js"],"/anvil":[s,a,e,f,d,"static/chunks/638-13a283c3a7da370b.js",c,t,n,i,h,"static/chunks/pages/anvil-3bce568d47e8eaba.js"],"/config":[s,a,e,u,"static/chunks/519-4b7761e884c88eb9.js",c,t,n,i,b,k,r,"static/chunks/pages/config-511a465cb55668af.js"],"/file-manager":["static/chunks/29107295-fbcfe2172188e46f.js",s,a,e,f,"static/chunks/176-7308c25ba374961e.js",c,t,i,b,"static/chunks/pages/file-manager-a085c3bead0f489f.js"],"/init":[s,a,f,d,u,g,c,t,n,i,l,"static/chunks/pages/init-59fe9f29b6489800.js"],"/login":[s,a,e,c,t,n,b,k,"static/chunks/pages/login-183a6e481fd67cca.js"],"/manage-element":[s,a,e,f,d,u,g,"static/chunks/111-2605129c170ed35d.js",c,t,n,i,b,k,l,r,"static/chunks/pages/manage-element-d8b8ab9027cbbb98.js"],"/server":[s,e,"static/chunks/528-72edc50189f30fa9.js",c,j,"static/chunks/pages/server-8faafa80170f67f2.js"],sortedPages:["/","/_app","/_error","/anvil","/config","/file-manager","/init","/login","/manage-element","/server"]}}("static/chunks/412-d77d0985f9905450.js","static/chunks/62-09a1812bcc63d819.js","static/chunks/438-0147a63d98e89439.js","static/chunks/894-e57948de523bcf96.js","static/chunks/195-fa06e61dd4339031.js","static/chunks/27-7790e406eb2ea28d.js","static/chunks/157-d1418743accab385.js","static/chunks/182-08683bbe95fbb010.js","static/chunks/209-4e2794319babfeec.js","static/chunks/48-d4400834d0a31c6e.js","static/chunks/644-4eec2b397fdacb0c.js","static/chunks/336-33ece0c8120f3bd4.js","static/chunks/707-705fb5e735d81042.js","static/chunks/94-f83c1e7821f76736.js","static/chunks/560-a9c9ecda0eca25a9.js","static/chunks/404-b8e9ff2043a0d30c.js","static/chunks/86-d7025c9609028f44.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();

@ -1 +0,0 @@
self.__BUILD_MANIFEST=function(s,c,a,e,t,n,i,f,u,k,d,h,j,b,r,g,l){return{__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":[s,a,e,f,u,"static/chunks/82-b2661d1af04f38ff.js",c,t,n,i,j,b,"static/chunks/pages/index-e5b260a0ddaa050c.js"],"/_error":["static/chunks/pages/_error-2280fa386d040b66.js"],"/anvil":[s,a,e,f,u,"static/chunks/247-0dbdd6350b819672.js",c,t,n,i,j,"static/chunks/pages/anvil-48975a0cc7fcbd1f.js"],"/config":[s,a,e,d,"static/chunks/519-4b7761e884c88eb9.js",c,t,n,i,k,h,r,"static/chunks/pages/config-f22ac92929f0daf0.js"],"/file-manager":["static/chunks/29107295-fbcfe2172188e46f.js",s,a,e,f,"static/chunks/176-7308c25ba374961e.js",c,t,i,k,"static/chunks/pages/file-manager-53de9163caaf5a86.js"],"/init":[s,a,f,u,d,g,c,t,n,i,l,"static/chunks/pages/init-84d6e766b3c27e21.js"],"/login":[s,a,e,c,t,n,k,h,"static/chunks/pages/login-6f7a93d56a339079.js"],"/manage-element":[s,a,e,f,u,d,g,"static/chunks/111-2605129c170ed35d.js",c,t,n,i,k,h,l,r,"static/chunks/pages/manage-element-a689bf0140460775.js"],"/server":[s,e,"static/chunks/528-72edc50189f30fa9.js",c,b,"static/chunks/pages/server-8faafa80170f67f2.js"],sortedPages:["/","/_app","/_error","/anvil","/config","/file-manager","/init","/login","/manage-element","/server"]}}("static/chunks/412-d77d0985f9905450.js","static/chunks/62-1cb6d52404130873.js","static/chunks/438-0147a63d98e89439.js","static/chunks/894-e57948de523bcf96.js","static/chunks/195-fa06e61dd4339031.js","static/chunks/987-1ff0d82724b0e58b.js","static/chunks/157-d1418743accab385.js","static/chunks/182-08683bbe95fbb010.js","static/chunks/960-e28948d6eb4c8144.js","static/chunks/48-d4400834d0a31c6e.js","static/chunks/644-4eec2b397fdacb0c.js","static/chunks/336-24770f9b2621610a.js","static/chunks/707-445cd83859b24a36.js","static/chunks/94-8322ed453a3c08f0.js","static/chunks/560-0ed707609765e23a.js","static/chunks/692-f4e7771f3a43db26.js","static/chunks/86-366ac64963a6a0fd.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -27,6 +27,7 @@ type ListOptionalProps<T extends unknown = unknown> = {
listItemProps?: import('@mui/material').ListItemProps;
listItems?: Record<string, T>;
listProps?: import('@mui/material').ListProps;
loading?: boolean;
onAdd?: import('../components/IconButton').IconButtonProps['onClick'];
onDelete?: import('../components/IconButton').IconButtonProps['onClick'];
onEdit?: import('../components/IconButton').IconButtonProps['onClick'];

@ -52,6 +52,7 @@ type AddFileFormProps = Pick<FileInputGroupProps, 'anvils' | 'drHosts'>;
/** EditFileForm */
type EditFileFormProps = Pick<FileInputGroupProps, 'anvils' | 'drHosts'> & {
onSuccess?: () => void;
previous: APIFileDetail;
};

Loading…
Cancel
Save