conflicts
authorPawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>
Mon, 3 Dec 2018 12:32:53 +0000 (13:32 +0100)
committerPawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>
Mon, 3 Dec 2018 12:32:53 +0000 (13:32 +0100)
Feature #14498

Arvados-DCO-1.1-Signed-off-by: Pawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>

1  2 
src/index.tsx
src/services/auth-service/auth-service.ts
src/store/advanced-tab/advanced-tab.ts
src/store/context-menu/context-menu-actions.ts
src/store/keep-services/keep-services-actions.ts
src/views-components/context-menu/action-sets/keep-service-action-set.ts
src/views-components/context-menu/context-menu.tsx
src/views/keep-service-panel/keep-service-panel-root.tsx
src/views/keep-service-panel/keep-service-panel.tsx
src/views/workbench/workbench.tsx

diff --cc src/index.tsx
index 3ff8088cc411e89ee3c45d4220d887cdb420704a,79525a8a6387de7deb9001c8b414b941154a6886..d83859675fc11e6f78b9b4fee37a4314fa1bccf0
@@@ -50,8 -50,8 +50,9 @@@ import HTML5Backend from 'react-dnd-htm
  import { initAdvanceFormProjectsTree } from '~/store/search-bar/search-bar-actions';
  import { repositoryActionSet } from '~/views-components/context-menu/action-sets/repository-action-set';
  import { sshKeyActionSet } from '~/views-components/context-menu/action-sets/ssh-key-action-set';
+ import { keepServiceActionSet } from '~/views-components/context-menu/action-sets/keep-service-action-set';
  import { loadVocabulary } from '~/store/vocabulary/vocabulary-actions';
 +import { virtualMachineActionSet } from '~/views-components/context-menu/action-sets/virtual-machine-action-set';
  
  console.log(`Starting arvados [${getBuildInfo()}]`);
  
@@@ -70,7 -70,7 +71,8 @@@ addMenuActionSet(ContextMenuKind.PROCES
  addMenuActionSet(ContextMenuKind.TRASH, trashActionSet);
  addMenuActionSet(ContextMenuKind.REPOSITORY, repositoryActionSet);
  addMenuActionSet(ContextMenuKind.SSH_KEY, sshKeyActionSet);
 +addMenuActionSet(ContextMenuKind.VIRTUAL_MACHINE, virtualMachineActionSet);
+ addMenuActionSet(ContextMenuKind.KEEP_SERVICE, keepServiceActionSet);
  
  fetchConfig()
      .then(({ config, apiHost }) => {
index fd68eb4b6cd673a9e1233b93766311a65787a864,c48011d2094f182a5c80ba0682e62d18c14c2285..d9dabe5ce5b8f646f7127f266181c5ea4953fb9e
@@@ -16,10 -16,7 +16,11 @@@ import { ServiceRepository } from '~/se
  import { FilterBuilder } from '~/services/api/filter-builder';
  import { RepositoryResource } from '~/models/repositories';
  import { SshKeyResource } from '~/models/ssh-key';
 +import { VirtualMachinesResource } from '~/models/virtual-machines';
 +import { UserResource } from '~/models/user';
 +import { ListResults } from '~/services/common-service/common-resource-service';
 +import { LinkResource } from '~/models/link';
+ import { KeepServiceResource } from '~/models/keep-services';
  
  export const ADVANCED_TAB_DIALOG = 'advancedTabDialog';
  
@@@ -62,21 -59,15 +63,27 @@@ enum SshKeyData 
      CREATED_AT = 'created_at'
  }
  
-     VIRTUAL_MACHINES = 'virtual_machines'
 +enum VirtualMachineData {
 +    VIRTUAL_MACHINE = 'virtual_machine',
 +    CREATED_AT = 'created_at'
 +}
 +
 +enum ResourcePrefix {
 +    REPOSITORIES = 'repositories',
 +    AUTORIZED_KEYS = 'authorized_keys',
- type AdvanceResourceKind = CollectionData | ProcessData | ProjectData | RepositoryData | SshKeyData | VirtualMachineData;
++    VIRTUAL_MACHINES = 'virtual_machines',
++    KEEP_SERVICES = 'keep_services'
 +}
 +
 -type AdvanceResourceKind = CollectionData | ProcessData | ProjectData | RepositoryData | SshKeyData | KeepServiceData;
 -type AdvanceResourcePrefix = GroupContentsResourcePrefix | 'repositories' | 'authorized_keys' | 'keep_services';
+ enum KeepServiceData {
+     KEEP_SERVICE = 'keep_services',
+     CREATED_AT = 'created_at'
+ }
++type AdvanceResourceKind = CollectionData | ProcessData | ProjectData | RepositoryData | SshKeyData | VirtualMachineData | KeepServiceData;
 +type AdvanceResourcePrefix = GroupContentsResourcePrefix | ResourcePrefix;
  
 -export const openAdvancedTabDialog = (uuid: string, index?: number) =>
 +export const openAdvancedTabDialog = (uuid: string) =>
      async (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
          const kind = extractUuidKind(uuid);
          switch (kind) {
                  dispatch<any>(initAdvancedTabDialog(advanceDataRepository));
                  break;
              case ResourceKind.SSH_KEY:
 -                const dataSshKey = getState().auth.sshKeys[index!];
 -                const advanceDataSshKey: AdvancedTabDialogData = advancedTabData(uuid, '', '', sshKeyApiResponse, dataSshKey, SshKeyData.SSH_KEY, 'authorized_keys', SshKeyData.CREATED_AT, dataSshKey.createdAt);
 +                const dataSshKey = getState().auth.sshKeys.find(it => it.uuid === uuid);
 +                const advanceDataSshKey: AdvancedTabDialogData = advancedTabData({
 +                    uuid,
 +                    metadata: '',
 +                    user: '',
 +                    apiResponseKind: sshKeyApiResponse,
 +                    data: dataSshKey,
 +                    resourceKind: SshKeyData.SSH_KEY,
 +                    resourcePrefix: ResourcePrefix.AUTORIZED_KEYS,
 +                    resourceKindProperty: SshKeyData.CREATED_AT,
 +                    property: dataSshKey!.createdAt
 +                });
                  dispatch<any>(initAdvancedTabDialog(advanceDataSshKey));
                  break;
 -                const dataKeepService = getState().keepServices[index!];
 -                const advanceDataKeepService: AdvancedTabDialogData = advancedTabData(uuid, '', '', keepServiceApiResponse, dataKeepService, KeepServiceData.KEEP_SERVICE, 'keep_services', KeepServiceData.CREATED_AT, dataKeepService.createdAt);
 +            case ResourceKind.VIRTUAL_MACHINE:
 +                const dataVirtualMachine = getState().virtualMachines.virtualMachines.items.find(it => it.uuid === uuid);
 +                const advanceDataVirtualMachine: AdvancedTabDialogData = advancedTabData({
 +                    uuid,
 +                    metadata: '',
 +                    user: '',
 +                    apiResponseKind: virtualMachineApiResponse,
 +                    data: dataVirtualMachine,
 +                    resourceKind: VirtualMachineData.VIRTUAL_MACHINE,
 +                    resourcePrefix: ResourcePrefix.VIRTUAL_MACHINES,
 +                    resourceKindProperty: VirtualMachineData.CREATED_AT,
 +                    property: dataVirtualMachine.createdAt
 +                });
 +                dispatch<any>(initAdvancedTabDialog(advanceDataVirtualMachine));
 +                break;
+             case ResourceKind.KEEP_SERVICE:
++                const dataKeepService = getState().keepServices.find(it => it.uuid === uuid);
++                const advanceDataKeepService: AdvancedTabDialogData = advancedTabData({
++                    uuid,
++                    metadata: '',
++                    user: '',
++                    apiResponseKind: keepServiceApiResponse,
++                    data: dataKeepService,
++                    resourceKind: KeepServiceData.KEEP_SERVICE,
++                    resourcePrefix: ResourcePrefix.KEEP_SERVICES,
++                    resourceKindProperty: KeepServiceData.CREATED_AT,
++                    property: dataKeepService!.createdAt
++                });
+                 dispatch<any>(initAdvancedTabDialog(advanceDataKeepService));
+                 break;
              default:
                  dispatch(snackbarActions.OPEN_SNACKBAR({ message: "Could not open advanced tab for this resource.", hideDuration: 2000, kind: SnackbarKind.ERROR }));
          }
@@@ -377,14 -306,22 +399,36 @@@ const sshKeyApiResponse = (apiResponse
      return response;
  };
  
-     const response = `"uuid": "${uuid}",
 +const virtualMachineApiResponse = (apiResponse: VirtualMachinesResource) => {
 +    const { uuid, ownerUuid, createdAt, modifiedAt, modifiedByClientUuid, modifiedByUserUuid, hostname } = apiResponse;
- "hostname": ${stringify(hostname)},
++    const response = `"hostname": ${stringify(hostname)},
++"uuid": "${uuid}",
 +"owner_uuid": "${ownerUuid}",
 +"modified_by_client_uuid": ${stringify(modifiedByClientUuid)},
 +"modified_by_user_uuid": ${stringify(modifiedByUserUuid)},
 +"modified_at": ${stringify(modifiedAt)},
++"modified_at": ${stringify(modifiedAt)},
 +"created_at": "${createdAt}"`;
++
++    return response;
++};
++
+ const keepServiceApiResponse = (apiResponse: KeepServiceResource) => {
+     const {
+         uuid, readOnly, serviceHost, servicePort, serviceSslFlag, serviceType,
+         ownerUuid, createdAt, modifiedAt, modifiedByClientUuid, modifiedByUserUuid
+     } = apiResponse;
+     const response = `"uuid": "${uuid}",
+ "owner_uuid": "${ownerUuid}",
+ "modified_by_client_uuid": ${stringify(modifiedByClientUuid)},
+ "modified_by_user_uuid": ${stringify(modifiedByUserUuid)},
+ "modified_at": ${stringify(modifiedAt)},
+ "service_host": "${serviceHost}",
+ "service_port": "${servicePort}",
+ "service_ssl_flag": "${stringify(serviceSslFlag)}",
+ "service_type": "${serviceType}",
+ "created_at": "${createdAt}",
+ "read_only": "${stringify(readOnly)}"`;
      return response;
  };
index 1412d958ee32dd18ab11070c35abce7edb1e1cbb,2c533d66b394b553249755ebd1df84f6daf7ddac..d56a3fb5ae520bd3bb1309c14e4f9656bf8182d2
@@@ -15,7 -15,7 +15,8 @@@ import { extractUuidKind, ResourceKind 
  import { Process } from '~/store/processes/process';
  import { RepositoryResource } from '~/models/repositories';
  import { SshKeyResource } from '~/models/ssh-key';
 +import { VirtualMachinesResource } from '~/models/virtual-machines';
+ import { KeepServiceResource } from '~/models/keep-services';
  
  export const contextMenuActions = unionize({
      OPEN_CONTEXT_MENU: ofType<{ position: ContextMenuPosition, resource: ContextMenuResource }>(),
@@@ -96,6 -88,18 +98,17 @@@ export const openSshKeyContextMenu = (e
          }));
      };
  
 -export const openKeepServiceContextMenu = (event: React.MouseEvent<HTMLElement>, index: number, keepService: KeepServiceResource) =>
++export const openKeepServiceContextMenu = (event: React.MouseEvent<HTMLElement>, keepService: KeepServiceResource) =>
+     (dispatch: Dispatch) => {
+         dispatch<any>(openContextMenu(event, {
+             name: '',
+             uuid: keepService.uuid,
+             ownerUuid: keepService.ownerUuid,
+             kind: ResourceKind.KEEP_SERVICE,
 -            menuKind: ContextMenuKind.KEEP_SERVICE,
 -            index
++            menuKind: ContextMenuKind.KEEP_SERVICE
+         }));
+     };
  export const openRootProjectContextMenu = (event: React.MouseEvent<HTMLElement>, projectUuid: string) =>
      (dispatch: Dispatch, getState: () => RootState) => {
          const res = getResource<UserResource>(projectUuid)(getState().resources);
index 0000000000000000000000000000000000000000,1de6802e7e37c1e8257305e8220289cc02614acc..54a7c3fe87161b6488d0060c576ae7e7dbcd2af5
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,71 +1,71 @@@
 -export const openKeepServiceAttributesDialog = (index: number) =>
+ // Copyright (C) The Arvados Authors. All rights reserved.
+ //
+ // SPDX-License-Identifier: AGPL-3.0
+ import { Dispatch } from "redux";
+ import { unionize, ofType, UnionOf } from "~/common/unionize";
+ import { RootState } from '~/store/store';
+ import { setBreadcrumbs } from '~/store/breadcrumbs/breadcrumbs-actions';
+ import { ServiceRepository } from "~/services/services";
+ import { KeepServiceResource } from '~/models/keep-services';
+ import { dialogActions } from '~/store/dialog/dialog-actions';
+ import { snackbarActions } from '~/store/snackbar/snackbar-actions';
+ import { navigateToRootProject } from '~/store/navigation/navigation-action';
+ export const keepServicesActions = unionize({
+     SET_KEEP_SERVICES: ofType<KeepServiceResource[]>(),
+     REMOVE_KEEP_SERVICE: ofType<string>()
+ });
+ export type KeepServicesActions = UnionOf<typeof keepServicesActions>;
+ export const KEEP_SERVICE_REMOVE_DIALOG = 'keepServiceRemoveDialog';
+ export const KEEP_SERVICE_ATTRIBUTES_DIALOG = 'keepServiceAttributesDialog';
+ export const loadKeepServicesPanel = () =>
+     async (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
+         const user = getState().auth.user;
+         if(user && user.isAdmin) {
+             try {
+                 dispatch(setBreadcrumbs([{ label: 'Keep Services' }]));
+                 const response = await services.keepService.list();
+                 dispatch(keepServicesActions.SET_KEEP_SERVICES(response.items));
+             } catch (e) {
+                 return;
+             }
+         } else {
+             dispatch(navigateToRootProject);
+             dispatch(snackbarActions.OPEN_SNACKBAR({ message: "You don't have permissions to view this page", hideDuration: 2000 }));
+         }
+     };
 -        const keepService = getState().keepServices[index];
++export const openKeepServiceAttributesDialog = (uuid: string) =>
+     (dispatch: Dispatch, getState: () => RootState) => {
++        const keepService = getState().keepServices.find(it => it.uuid === uuid);
+         dispatch(dialogActions.OPEN_DIALOG({ id: KEEP_SERVICE_ATTRIBUTES_DIALOG, data: { keepService } }));
+     };
+ export const openKeepServiceRemoveDialog = (uuid: string) =>
+     (dispatch: Dispatch, getState: () => RootState) => {
+         dispatch(dialogActions.OPEN_DIALOG({
+             id: KEEP_SERVICE_REMOVE_DIALOG,
+             data: {
+                 title: 'Remove keep service',
+                 text: 'Are you sure you want to remove this keep service?',
+                 confirmButtonLabel: 'Remove',
+                 uuid
+             }
+         }));
+     };
+ export const removeKeepService = (uuid: string) =>
+     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+         dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removing ...' }));
+         try {
+             await services.keepService.delete(uuid);
+             dispatch(keepServicesActions.REMOVE_KEEP_SERVICE(uuid));
+             dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Keep service has been successfully removed.', hideDuration: 2000 }));
+         } catch (e) {
+             return;
+         }
+     };
index 0000000000000000000000000000000000000000,5d27e4e9670407a43a833c05da3794e20582d2c7..807a3abf59783a73f3c56bcef40c69fc28c0af2e
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,28 +1,28 @@@
 -    execute: (dispatch, { index }) => {
 -        dispatch<any>(openKeepServiceAttributesDialog(index!));
+ // Copyright (C) The Arvados Authors. All rights reserved.
+ //
+ // SPDX-License-Identifier: AGPL-3.0
+ import { openKeepServiceAttributesDialog, openKeepServiceRemoveDialog } from '~/store/keep-services/keep-services-actions';
+ import { openAdvancedTabDialog } from '~/store/advanced-tab/advanced-tab';
+ import { ContextMenuActionSet } from "~/views-components/context-menu/context-menu-action-set";
+ import { AdvancedIcon, RemoveIcon, AttributesIcon } from "~/components/icon/icon";
+ export const keepServiceActionSet: ContextMenuActionSet = [[{
+     name: "Attributes",
+     icon: AttributesIcon,
 -    execute: (dispatch, { uuid, index }) => {
 -        dispatch<any>(openAdvancedTabDialog(uuid, index));
++    execute: (dispatch, { uuid }) => {
++        dispatch<any>(openKeepServiceAttributesDialog(uuid));
+     }
+ }, {
+     name: "Advanced",
+     icon: AdvancedIcon,
++    execute: (dispatch, { uuid }) => {
++        dispatch<any>(openAdvancedTabDialog(uuid));
+     }
+ }, {
+     name: "Remove",
+     icon: RemoveIcon,
+     execute: (dispatch, { uuid }) => {
+         dispatch<any>(openKeepServiceRemoveDialog(uuid));
+     }
+ }]];
index d08798f773beef21fd7e29dec533b71a6d69eedd,211881ca599954728c2cb22a1a8b62a744ca8bb9..5f321bfe72f9f292542b86225d521a14207234d9
@@@ -71,5 -71,5 +71,6 @@@ export enum ContextMenuKind 
      PROCESS_LOGS = "ProcessLogs",
      REPOSITORY = "Repository",
      SSH_KEY = "SshKey",
-     VIRTUAL_MACHINE = "VirtualMachine"
++    VIRTUAL_MACHINE = "VirtualMachine",
+     KEEP_SERVICE = "KeepService"
  }
index 0000000000000000000000000000000000000000,57193d355af336ea9c1baaeebde8abcd2ba29a77..8c266b616016d8d48318364103c96274106c7722
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,87 +1,87 @@@
 -    openRowOptions: (event: React.MouseEvent<HTMLElement>, index: number, keepService: KeepServiceResource) => void;
+ // Copyright (C) The Arvados Authors. All rights reserved.
+ //
+ // SPDX-License-Identifier: AGPL-3.0
+ import * as React from 'react';
+ import { StyleRulesCallback, WithStyles, withStyles, Card, CardContent, Button, Typography, Grid, Table, TableHead, TableRow, TableCell, TableBody, Tooltip, IconButton, Checkbox } from '@material-ui/core';
+ import { ArvadosTheme } from '~/common/custom-theme';
+ import { MoreOptionsIcon } from '~/components/icon/icon';
+ import { KeepServiceResource } from '~/models/keep-services';
+ type CssRules = 'root' | 'tableRow';
+ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+     root: {
+         width: '100%',
+         overflow: 'auto'
+     },
+     tableRow: {
+         '& td, th': {
+             whiteSpace: 'nowrap'
+         }
+     }
+ });
+ export interface KeepServicePanelRootActionProps {
 -                                                <IconButton onClick={event => openRowOptions(event, index, keepService)}>
++    openRowOptions: (event: React.MouseEvent<HTMLElement>, keepService: KeepServiceResource) => void;
+ }
+ export interface KeepServicePanelRootDataProps {
+     keepServices: KeepServiceResource[];
+     hasKeepSerices: boolean;
+ }
+ type KeepServicePanelRootProps = KeepServicePanelRootActionProps & KeepServicePanelRootDataProps & WithStyles<CssRules>;
+ export const KeepServicePanelRoot = withStyles(styles)(
+     ({ classes, hasKeepSerices, keepServices, openRowOptions }: KeepServicePanelRootProps) => 
+         <Card className={classes.root}>
+             <CardContent>
+                 {hasKeepSerices && <Grid container direction="row">
+                     <Grid item xs={12}>
+                         <Table>
+                             <TableHead>
+                                 <TableRow className={classes.tableRow}>
+                                     <TableCell>UUID</TableCell>
+                                     <TableCell>Read only</TableCell>
+                                     <TableCell>Service host</TableCell>
+                                     <TableCell>Service port</TableCell>
+                                     <TableCell>Service SSL flag</TableCell>
+                                     <TableCell>Service type</TableCell>
+                                     <TableCell />
+                                 </TableRow>
+                             </TableHead>
+                             <TableBody>
+                                 {keepServices.map((keepService, index) =>
+                                     <TableRow key={index} className={classes.tableRow}>
+                                         <TableCell>{keepService.uuid}</TableCell>
+                                         <TableCell>
+                                             <Checkbox
+                                                 disableRipple
+                                                 color="primary"
+                                                 checked={keepService.readOnly} />
+                                         </TableCell>
+                                         <TableCell>{keepService.serviceHost}</TableCell>
+                                         <TableCell>{keepService.servicePort}</TableCell>
+                                         <TableCell>
+                                             <Checkbox
+                                                 disableRipple
+                                                 color="primary"
+                                                 checked={keepService.serviceSslFlag} />
+                                         </TableCell>
+                                         <TableCell>{keepService.serviceType}</TableCell>
+                                         <TableCell>
+                                             <Tooltip title="More options" disableFocusListener>
++                                                <IconButton onClick={event => openRowOptions(event, keepService)}>
+                                                     <MoreOptionsIcon />
+                                                 </IconButton>
+                                             </Tooltip>
+                                         </TableCell>
+                                     </TableRow>)}
+                             </TableBody>
+                         </Table>
+                     </Grid>
+                 </Grid>}
+             </CardContent>
+         </Card>
+ );
index 0000000000000000000000000000000000000000,2c6323b079b90e10efbf15c6974ecfce299fab42..a11cee0b22b7a780edcabfa2656ee8d0160848c9
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,29 +1,29 @@@
 -    openRowOptions: (event, index, keepService) => {
 -        dispatch<any>(openKeepServiceContextMenu(event, index, keepService));
+ // Copyright (C) The Arvados Authors. All rights reserved.
+ //
+ // SPDX-License-Identifier: AGPL-3.0
+ import { RootState } from '~/store/store';
+ import { Dispatch } from 'redux';
+ import { connect } from 'react-redux';
+ import { } from '~/store/keep-services/keep-services-actions';
+ import { 
+     KeepServicePanelRoot, 
+     KeepServicePanelRootDataProps, 
+     KeepServicePanelRootActionProps 
+ } from '~/views/keep-service-panel/keep-service-panel-root';
+ import { openKeepServiceContextMenu } from '~/store/context-menu/context-menu-actions';
+ const mapStateToProps = (state: RootState): KeepServicePanelRootDataProps => {
+     return {
+         keepServices: state.keepServices,
+         hasKeepSerices: state.keepServices.length > 0
+     };
+ };
+ const mapDispatchToProps = (dispatch: Dispatch): KeepServicePanelRootActionProps => ({
++    openRowOptions: (event, keepService) => {
++        dispatch<any>(openKeepServiceContextMenu(event, keepService));
+     }
+ });
+ export const KeepServicePanel = connect(mapStateToProps, mapDispatchToProps)(KeepServicePanelRoot);
index 3fc514af87daf45de5fb6de6858946878e07c22e,dd4f802c54b335e8dad86d6c2001fa02df4137ad..2d17fad9629d80aabdf7c493155012c33bc38302
@@@ -57,10 -58,10 +58,12 @@@ import { CreateRepositoryDialog } from 
  import { RemoveRepositoryDialog } from '~/views-components/repository-remove-dialog/repository-remove-dialog';
  import { CreateSshKeyDialog } from '~/views-components/dialog-forms/create-ssh-key-dialog';
  import { PublicKeyDialog } from '~/views-components/ssh-keys-dialog/public-key-dialog';
+ import { RemoveKeepServiceDialog } from '~/views-components/keep-services-dialog/remove-dialog';
  import { RemoveSshKeyDialog } from '~/views-components/ssh-keys-dialog/remove-dialog';
+ import { AttributesKeepServiceDialog } from '~/views-components/keep-services-dialog/attributes-dialog';
  import { AttributesSshKeyDialog } from '~/views-components/ssh-keys-dialog/attributes-dialog';
 +import { VirtualMachineAttributesDialog } from '~/views-components/virtual-machines-dialog/attributes-dialog';
 +import { RemoveVirtualMachineDialog } from '~/views-components/virtual-machines-dialog/remove-dialog';
  
  type CssRules = 'root' | 'container' | 'splitter' | 'asidePanel' | 'contentWrapper' | 'content';