Skip to content

Commit

Permalink
Implemented table view for backend list (#653)
Browse files Browse the repository at this point in the history
Added navigate link for repo id cell in runs table
  • Loading branch information
olgenn authored Aug 16, 2023
1 parent ee697c9 commit b47f7c7
Show file tree
Hide file tree
Showing 12 changed files with 343 additions and 244 deletions.
3 changes: 2 additions & 1 deletion hub/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ export const API = {
LIST: () => `${API.PROJECTS.BASE()}/list`,
CREATE: () => `${API.PROJECTS.BASE()}/create`,
DELETE: () => `${API.PROJECTS.BASE()}/delete`,
DETAILS: (name: IProject['project_name']) => `${API.PROJECTS.BASE()}/${name}/info`,
DETAILS: (name: IProject['project_name']) => `${API.PROJECTS.BASE()}/${name}`,
DETAILS_INFO: (name: IProject['project_name']) => `${API.PROJECTS.DETAILS(name)}/info`,
MEMBERS: (name: IProject['project_name']) => `${API.PROJECTS.DETAILS(name)}/members`,

// Repos
Expand Down
15 changes: 14 additions & 1 deletion hub/src/locale/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
"page_title_other": "Backends",
"add_backend": "Add backend",
"edit_backend": "Edit backend",
"empty_message_title": "No backends",
"empty_message_text": "No backends to display.",
"type": {
"aws": "AWS",
"aws_description": "Run workflows and store data in Amazon Web Services ",
Expand All @@ -62,8 +64,19 @@
"local_description": "Run workflows and store data locally via Docker"
},

"table": {
"region": "Region/Location",
"bucket": "Bucket",
"extra_regions": "Extra Region/Extra Locations",
"subnet": "Subnet"
},

"edit": {
"success_notification": "Project updating is successful"
"success_notification": "Project updating is successful",
"delete_backend_confirm_title": "Delete backend",
"delete_backend_confirm_message": "Are you sure you want to delete this backend?",
"delete_backends_confirm_title": "Delete backends",
"delete_backends_confirm_message": "Are you sure you want to delete these backends?"
},

"create": {
Expand Down
1 change: 1 addition & 0 deletions hub/src/pages/Project/Backends/Table/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './useColumnsDefinitions';
169 changes: 169 additions & 0 deletions hub/src/pages/Project/Backends/Table/hooks/useColumnsDefinitions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import React, { useMemo } from 'react';
import { useTranslation } from 'react-i18next';

import { Button } from 'components';
import { ButtonWithConfirmation } from 'components/ButtonWithConfirmation';

import { BackendTypesEnum } from '../../Form/types';

import styles from '../styles.module.scss';

type hookArgs = {
loading?: boolean;
onDeleteClick?: (backend: IProjectBackend) => void;
onEditClick?: (backend: IProjectBackend) => void;
};

export const useColumnsDefinitions = ({ loading, onDeleteClick, onEditClick }: hookArgs) => {
const { t } = useTranslation();

const getRegionByBackendType = (backend: IProjectBackend) => {
switch (backend.config.type) {
case BackendTypesEnum.AWS:
return backend.config.region_name_title;
case BackendTypesEnum.AZURE:
return backend.config.location;
case BackendTypesEnum.GCP:
return backend.config.region;
case BackendTypesEnum.LAMBDA: {
const regions = backend.config?.regions.join(', ') ?? '-';
return (
<div className={styles.ellipsisCell} title={regions}>
{regions}
</div>
);
}
default:
return '-';
}
};

const getBucketByBackendType = (backend: IProjectBackend) => {
switch (backend.config.type) {
case BackendTypesEnum.AWS:
return backend.config.s3_bucket_name;
case BackendTypesEnum.GCP:
return backend.config.bucket_name;
case BackendTypesEnum.LAMBDA:
return backend.config.storage_backend.bucket_name;
default:
return '-';
}
};

const getSubnetByBackendType = (backend: IProjectBackend) => {
switch (backend.config.type) {
case BackendTypesEnum.AWS:
return backend.config.ec2_subnet_id;
case BackendTypesEnum.GCP:
return backend.config.subnet;
default:
return '-';
}
};

const getExtraRegionsByBackendType = (backend: IProjectBackend) => {
switch (backend.config.type) {
case BackendTypesEnum.AWS: {
const extraRegions = backend.config.extra_regions?.join(', ');

return (
<div className={styles.ellipsisCell} title={extraRegions}>
{extraRegions}
</div>
);
}

case BackendTypesEnum.AZURE: {
const extraLocations = backend.config.extra_locations?.join(', ');

return (
<div className={styles.ellipsisCell} title={extraLocations}>
{extraLocations}
</div>
);
}

case BackendTypesEnum.GCP: {
const extraRegions = backend.config.extra_regions?.join(', ');

return (
<div className={styles.ellipsisCell} title={extraRegions}>
{extraRegions}
</div>
);
}

default:
return '-';
}
};

const columns = useMemo(() => {
return [
{
id: 'type',
header: t('projects.edit.backend_type'),
cell: (backend: IProjectBackend) => backend.config.type,
},

{
id: 'regions',
header: t('backend.table.region'),
cell: getRegionByBackendType,
},

{
id: 'bucket',
header: t('backend.table.bucket'),
cell: getBucketByBackendType,
},

{
id: 'subnet',
header: t('backend.table.subnet'),
cell: getSubnetByBackendType,
},

{
id: 'extra_regions',
header: t('backend.table.extra_regions'),
cell: getExtraRegionsByBackendType,
},

{
id: 'actions',
header: '',
cell: (backend: IProjectBackend) => (
<div className={styles.cell}>
<div className={styles.contextMenu}>
{onEditClick && (
<Button
disabled={loading}
formAction="none"
onClick={() => onEditClick(backend)}
variant="icon"
iconName="edit"
/>
)}

{onDeleteClick && (
<ButtonWithConfirmation
disabled={loading}
formAction="none"
onClick={() => onDeleteClick(backend)}
variant="icon"
iconName="remove"
confirmTitle={t('backend.edit.delete_backend_confirm_title')}
confirmContent={t('backend.edit.delete_backend_confirm_message')}
/>
)}
</div>
</div>
),
},
];
}, [loading, onEditClick, onDeleteClick]);

return { columns } as const;
};
96 changes: 96 additions & 0 deletions hub/src/pages/Project/Backends/Table/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import React from 'react';
import { useTranslation } from 'react-i18next';

import { Button, ButtonWithConfirmation, Header, ListEmptyMessage, SpaceBetween, Table } from 'components';

import { useCollection } from 'hooks';

import { useColumnsDefinitions } from './hooks';

import { IProps } from './types';

export const BackendsTable: React.FC<IProps> = ({
backends,
editBackend,
deleteBackends,
onClickAddBackend,
isDisabledDelete,
}) => {
const { t } = useTranslation();

const renderEmptyMessage = (): React.ReactNode => {
return (
<ListEmptyMessage title={t('backend.empty_message_title')} message={t('backend.empty_message_text')}>
{onClickAddBackend && <Button onClick={onClickAddBackend}>{t('common.add')}</Button>}
</ListEmptyMessage>
);
};

const { items, collectionProps } = useCollection(backends ?? [], {
filtering: {
empty: renderEmptyMessage(),
noMatch: renderEmptyMessage(),
},
selection: {},
});

const { selectedItems } = collectionProps;

const isDisabledDeleteSelected = !selectedItems?.length || isDisabledDelete;

const deleteSelectedBackends = () => {
if (!selectedItems?.length || !deleteBackends) return;

deleteBackends(selectedItems);
};

const { columns } = useColumnsDefinitions({
...(editBackend ? { onEditClick: (backend) => editBackend(backend) } : {}),
...(deleteBackends ? { onDeleteClick: (backend) => deleteBackends([backend]) } : {}),
});

const renderCounter = () => {
if (!backends?.length) return '';

return `(${backends.length})`;
};

return (
<Table
{...collectionProps}
columnDefinitions={columns}
items={items}
loadingText={t('common.loading')}
selectionType="multi"
stickyHeader={true}
header={
<Header
counter={renderCounter()}
actions={
<SpaceBetween size="xs" direction="horizontal">
{deleteBackends && (
<ButtonWithConfirmation
disabled={isDisabledDeleteSelected}
formAction="none"
onClick={deleteSelectedBackends}
confirmTitle={t('backend.edit.delete_backends_confirm_title')}
confirmContent={t('backend.edit.delete_backends_confirm_message')}
>
{t('common.delete')}
</ButtonWithConfirmation>
)}

{onClickAddBackend && (
<Button onClick={onClickAddBackend} /*disabled={isDisabledAddBackendButton}*/>
{t('common.add')}
</Button>
)}
</SpaceBetween>
}
>
{t('backend.page_title_other')}
</Header>
}
/>
);
};
16 changes: 16 additions & 0 deletions hub/src/pages/Project/Backends/Table/styles.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.cell {
display: flex;
align-items: center;
}

.contextMenu {
margin-left: auto;
padding-left: 20px;
}

.ellipsisCell {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
max-width: 240px;
}
7 changes: 7 additions & 0 deletions hub/src/pages/Project/Backends/Table/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export interface IProps {
backends: IProjectBackend[];
onClickAddBackend?: () => void;
deleteBackends?: (backends: readonly IProjectBackend[] | IProjectBackend[]) => void;
editBackend?: (backend: IProjectBackend) => void;
isDisabledDelete?: boolean;
}
Loading

0 comments on commit b47f7c7

Please sign in to comment.