Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft/Example: Custom pages #17

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
Draft
124 changes: 124 additions & 0 deletions pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import { SessionProvider } from 'next-auth/react';
import { NextAdapter } from 'next-query-params';
import App, { AppContext, AppInitialProps, AppProps } from 'next/app';
import Head from 'next/head';
import { useRouter } from 'next/router';
import { QueryParamProvider } from 'use-query-params';

import type { EuiSideNavItemType } from '@elastic/eui';
import { EuiProvider, EuiThemeColorMode } from '@elastic/eui';
import '@elastic/eui/dist/eui_theme_dark.min.css';
import '@elastic/eui/dist/eui_theme_light.min.css';
Expand Down Expand Up @@ -49,6 +51,7 @@ function CustomApp({
pageProps,
orchestratorConfig,
}: AppProps & AppOwnProps) {
const router = useRouter();
const [queryClient] = useState(() => new QueryClient(queryClientConfig));

const [themeMode, setThemeMode] = useState<EuiThemeColorMode>(
Expand All @@ -72,6 +75,124 @@ function CustomApp({
}
}, []);

const getMenuItems = (): EuiSideNavItemType<object>[] => {
return [
{
name: 'Start',
id: '2',
isSelected: router.pathname === '/',
onClick: (e) => {
e.preventDefault();
router.push('/');
},
},
{
name: 'Routines',
id: '3',
isSelected: router.pathname === '/custom/routines',
href: '/custom/routines',
onClick: (e) => {
e.preventDefault();
router.push('/custom/routines');
},
},
{
name: 'Notifications',
id: '4',
isSelected: router.pathname === '/custom/notifications',
href: '/custom/notifications',
onClick: (e) => {
e.preventDefault();
router.push('/custom/notifications');
},
},
{
name: 'Configuration',
id: '5',
href: '/custom/configuration/custom-fixed-version-types',
onClick: () => {
router.push(
'/custom/configuration/custom-fixed-version-types',
);
},
items: [
{
name: 'Fixed Version Types',
id: '5.1',
isSelected:
router.pathname ===
'/custom/configuration/custom-fixed-version-types',
onClick: (e) => {
e.preventDefault();
router.push(
'/custom/configuration/custom-fixed-version-types',
);
},
},
{
name: 'Product blocks',
id: '5.2',
isSelected:
router.pathname ===
'/custom/configuration/custom-product-blocks',
onClick: (e) => {
e.preventDefault();
router.push(
'/custom/configuration/custom-product-blocks',
);
},
},
{
name: 'Products',
id: '5.3',
isSelected:
router.pathname ===
'/custom/configuration/custom-products',
onClick: (e) => {
e.preventDefault();
router.push(
'/custom/configuration/custom-products',
);
},
},
{
name: 'Routines',
id: '5.4',
isSelected:
router.pathname ===
'/custom/configuration/custom-routines',
onClick: (e) => {
e.preventDefault();
router.push(
'/custom/configuration/custom-routines',
);
},
},
],
},
{
name: 'Jobs',
isSelected: router.pathname === '/custom/jobs',
id: '6',
onClick: (e) => {
e.preventDefault();
router.push('/custom/jobs');
},
href: '/custom/jobs',
},
{
name: 'Settings',
isSelected: router.pathname === '/custom/custom-settings',
id: '7',
onClick: (e) => {
e.preventDefault();
router.push('/custom/custom-settings');
},
href: '/custom/custom-settings',
},
];
};

return (
<WfoErrorBoundary>
<OrchestratorConfigProvider
Expand Down Expand Up @@ -110,6 +231,9 @@ function CustomApp({
onThemeSwitch={
handleThemeSwitch
}
overrideMenuItems={
getMenuItems
}
>
<QueryParamProvider
adapter={
Expand Down
24 changes: 24 additions & 0 deletions pages/custom/configuration/configurationTabs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { MetaDataTab } from '@orchestrator-ui/orchestrator-ui-components';

export const configurationTabs: MetaDataTab[] = [
{
id: 1,
translationKey: 'fixedVersionTypes',
path: '/custom/configuration/custom-fixed-version-types',
},
{
id: 2,
translationKey: 'products',
path: '/custom/configuration/custom-products',
},
{
id: 3,
translationKey: 'productBlocks',
path: '/custom/configuration/custom-product-blocks',
},
{
id: 4,
translationKey: 'routines',
path: '/custom/configuration/custom-routines',
},
];
211 changes: 211 additions & 0 deletions pages/custom/configuration/custom-fixed-version-types.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
import React, { useEffect, useState } from 'react';

import { useTranslations } from 'next-intl';

import { EuiBadgeGroup } from '@elastic/eui';
import type { Pagination } from '@elastic/eui/src/components';
import {
DEFAULT_PAGE_SIZE,
DEFAULT_PAGE_SIZES,
METADATA_RESOURCE_TYPES_TABLE_LOCAL_STORAGE_KEY,
WfoProductBlockBadge,
WfoTableWithFilter,
getDataSortHandler,
getPageChangeHandler,
getQueryStringHandler,
} from '@orchestrator-ui/orchestrator-ui-components';
import type {
StoredTableConfig,
WfoDataSorting,
WfoTableColumns,
} from '@orchestrator-ui/orchestrator-ui-components';
import {
useDataDisplayParams,
useShowToastMessage,
useStoredTableConfig,
} from '@orchestrator-ui/orchestrator-ui-components';
import {
useGetResourceTypesQuery,
useLazyGetResourceTypesQuery,
} from '@orchestrator-ui/orchestrator-ui-components';
import {
BadgeType,
GraphqlQueryVariables,
ResourceTypeDefinition,
SortOrder,
} from '@orchestrator-ui/orchestrator-ui-components';
import { getQueryVariablesForExport } from '@orchestrator-ui/orchestrator-ui-components';
import {
csvDownloadHandler,
getCsvFileNameWithDate,
} from '@orchestrator-ui/orchestrator-ui-components';
import { WfoFirstPartUUID } from '@orchestrator-ui/orchestrator-ui-components';
import { mapSortableAndFilterableValuesToTableColumnConfig } from '@orchestrator-ui/orchestrator-ui-components';
import { WfoMetadataPageLayout } from '@orchestrator-ui/orchestrator-ui-components';

import { configurationTabs } from './configurationTabs';

export const RESOURCE_TYPE_FIELD_ID = 'resourceTypeId';
export const RESOURCE_TYPE_FIELD_TYPE = 'resourceType';
export const RESOURCE_TYPE_FIELD_DESCRIPTION = 'description';
export const RESOURCE_TYPE_FIELD_PRODUCT_BLOCKS = 'productBlocks';

export default function WfoResourceTypesPage() {
const t = useTranslations('configurations.fixedVersionTypes');
const tError = useTranslations('errors');
const { showToastMessage } = useShowToastMessage();
const [tableDefaults, setTableDefaults] =
useState<StoredTableConfig<ResourceTypeDefinition>>();

const getStoredTableConfig = useStoredTableConfig<ResourceTypeDefinition>(
METADATA_RESOURCE_TYPES_TABLE_LOCAL_STORAGE_KEY,
);

useEffect(() => {
const storedConfig = getStoredTableConfig();

if (storedConfig) {
setTableDefaults(storedConfig);
}
}, [getStoredTableConfig]);

const { dataDisplayParams, setDataDisplayParam } =
useDataDisplayParams<ResourceTypeDefinition>({
// TODO: Improvement: A default pageSize value is set to avoid a graphql error when the query is executed
// the fist time before the useEffect has populated the tableDefaults. Better is to create a way for
// the query to wait for the values to be available
// https://github.com/workfloworchestrator/orchestrator-ui/issues/261
pageSize: tableDefaults?.selectedPageSize || DEFAULT_PAGE_SIZE,
sortBy: {
field: RESOURCE_TYPE_FIELD_TYPE,
order: SortOrder.ASC,
},
});

const tableColumns: WfoTableColumns<ResourceTypeDefinition> = {
resourceTypeId: {
field: RESOURCE_TYPE_FIELD_ID,
name: t('resourceId'),
width: '90',
render: (value) => <WfoFirstPartUUID UUID={value} />,
renderDetails: (value) => value,
},
resourceType: {
field: RESOURCE_TYPE_FIELD_TYPE,
name: t('type'),
width: '200',
render: (value) => (
<WfoProductBlockBadge badgeType={BadgeType.RESOURCE_TYPE}>
{value}
</WfoProductBlockBadge>
),
},
description: {
field: RESOURCE_TYPE_FIELD_DESCRIPTION,
name: t('description'),
},
productBlocks: {
field: RESOURCE_TYPE_FIELD_PRODUCT_BLOCKS,
name: t('usedInProductBlocks'),
render: (productBlocks) => (
<>
{productBlocks.map((productBlock, index) => (
<WfoProductBlockBadge
key={index}
badgeType={BadgeType.PRODUCT_BLOCK}
>
{productBlock.name}
</WfoProductBlockBadge>
))}
</>
),
renderDetails: (productBlocks) => (
<EuiBadgeGroup gutterSize="s">
{productBlocks.map((productBlock, index) => (
<WfoProductBlockBadge
key={index}
badgeType={BadgeType.PRODUCT_BLOCK}
>
{productBlock.name}
</WfoProductBlockBadge>
))}
</EuiBadgeGroup>
),
},
};

const { pageSize, pageIndex, sortBy, queryString } = dataDisplayParams;
const graphqlQueryVariables: GraphqlQueryVariables<ResourceTypeDefinition> =
{
first: pageSize,
after: pageIndex * pageSize,
sortBy: sortBy,
query: queryString || undefined,
};
const { data, isFetching, isError } = useGetResourceTypesQuery(
graphqlQueryVariables,
);

const [getResourceTypesTrigger, { isFetching: isFetchingCsv }] =
useLazyGetResourceTypesQuery();

const getResourceTypesForExport = () =>
getResourceTypesTrigger(
getQueryVariablesForExport(graphqlQueryVariables),
).unwrap();

const dataSorting: WfoDataSorting<ResourceTypeDefinition> = {
field: sortBy?.field ?? RESOURCE_TYPE_FIELD_TYPE,
sortOrder: sortBy?.order ?? SortOrder.ASC,
};

const { totalItems, sortFields, filterFields } = data?.pageInfo || {};

const pagination: Pagination = {
pageSize: pageSize,
pageIndex: pageIndex,
pageSizeOptions: DEFAULT_PAGE_SIZES,
totalItemCount: totalItems ? totalItems : 0,
};

return (
<WfoMetadataPageLayout tabs={configurationTabs}>
<WfoTableWithFilter<ResourceTypeDefinition>
data={data ? data.resourceTypes : []}
tableColumns={mapSortableAndFilterableValuesToTableColumnConfig(
tableColumns,
sortFields,
filterFields,
)}
dataSorting={dataSorting}
defaultHiddenColumns={tableDefaults?.hiddenColumns}
onUpdateDataSort={getDataSortHandler<ResourceTypeDefinition>(
setDataDisplayParam,
)}
onUpdatePage={getPageChangeHandler<ResourceTypeDefinition>(
setDataDisplayParam,
)}
onUpdateQueryString={getQueryStringHandler<ResourceTypeDefinition>(
setDataDisplayParam,
)}
pagination={pagination}
isLoading={isFetching}
hasError={isError}
queryString={queryString}
localStorageKey={
METADATA_RESOURCE_TYPES_TABLE_LOCAL_STORAGE_KEY
}
onExportData={csvDownloadHandler(
getResourceTypesForExport,
(data) => data.resourceTypes,
(data) => data.pageInfo,
Object.keys(tableColumns),
getCsvFileNameWithDate('ResourceTypes'),
showToastMessage,
tError,
)}
exportDataIsLoading={isFetchingCsv}
/>
</WfoMetadataPageLayout>
);
}
Loading