Skip to content

Commit

Permalink
ISPN-16490 Index metamodel view
Browse files Browse the repository at this point in the history
  • Loading branch information
karesti committed Sep 4, 2024
1 parent 9cb58fd commit 6636f03
Show file tree
Hide file tree
Showing 11 changed files with 344 additions and 29 deletions.
13 changes: 0 additions & 13 deletions src/app/CacheManagers/CacheManagers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,19 +142,6 @@ const CacheManagers = () => {
);
};

const buildSiteDisplay = (siteName: string | undefined) => {
if (!siteName || siteName == '') {
return '';
}

return (
<React.Fragment>
<Divider orientation={{ default: 'vertical' }} />
<FlexItem>{'Site: ' + siteName}</FlexItem>
</React.Fragment>
);
};

const buildHeader = () => {
const title = t('cache-managers.title');
if (!cm) {
Expand Down
6 changes: 4 additions & 2 deletions src/app/CacheManagers/CacheTableDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ const CacheTableDisplay = (props: { setCachesCount: (count: number) => void; isV
if (filteredCaches) {
const initSlice = (cachesPagination.page - 1) * cachesPagination.perPage;
const updateRows = filteredCaches.slice(initSlice, initSlice + cachesPagination.perPage);
updateRows.length > 0 ? setRows(updateRows) : setRows([]);
setRows(updateRows);
}
}, [cachesPagination, filteredCaches]);

Expand Down Expand Up @@ -218,7 +218,9 @@ const CacheTableDisplay = (props: { setCachesCount: (count: number) => void; isV
setTimeout(() => {
if (menuRef.current) {
const firstElement = menuRef.current.querySelector('li > button:not(:disabled)');
firstElement && (firstElement as HTMLElement).focus();
if (firstElement) {
(firstElement as HTMLElement).focus();
}
}
}, 0);
setIsFilterOpen(!isFilterOpen);
Expand Down
6 changes: 4 additions & 2 deletions src/app/CacheManagers/CounterTableDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ const CounterTableDisplay = (props: { setCountersCount: (number) => void; isVisi
if (filteredCounters) {
const initSlice = (countersPagination.page - 1) * countersPagination.perPage;
const updateRows = filteredCounters.slice(initSlice, initSlice + countersPagination.perPage);
updateRows.length > 0 ? setRows(updateRows) : setRows([]);
setRows(updateRows);
}
}, [countersPagination, filteredCounters]);

Expand Down Expand Up @@ -250,7 +250,9 @@ const CounterTableDisplay = (props: { setCountersCount: (number) => void; isVisi
setTimeout(() => {
if (menuRef.current) {
const firstElement = menuRef.current.querySelector('li > button:not(:disabled)');
firstElement && (firstElement as HTMLElement).focus();
if (firstElement) {
(firstElement as HTMLElement).focus();
}
}
}, 0);
setIsFilterOpen(!isFilterOpen);
Expand Down
2 changes: 1 addition & 1 deletion src/app/Caches/Entries/CacheEntries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ const CacheEntries = (props: { cacheName: string }) => {
if (filteredEntries) {
const initSlice = (entriesPagination.page - 1) * entriesPagination.perPage;
const updateRows = filteredEntries.slice(initSlice, initSlice + entriesPagination.perPage);
updateRows.length > 0 ? setRows(updateRows) : setRows([]);
setRows(updateRows);
}
}, [entriesPagination, filteredEntries]);

Expand Down
2 changes: 1 addition & 1 deletion src/app/Common/TableEmptyState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const TableEmptyState = (props: { loading: boolean; error: string; empty: string
}

return (
<Bullseye data-cy="noCacheConfigsFound">
<Bullseye data-cy="emptyStateTable">
<EmptyState variant={EmptyStateVariant.sm}>
<EmptyStateHeader
titleText={<>{props.empty}</>}
Expand Down
32 changes: 22 additions & 10 deletions src/app/IndexManagement/IndexManagement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import {
ButtonVariant,
Card,
CardBody,
EmptyState,
EmptyStateBody,
EmptyStateIcon,
EmptyStateVariant,
Grid,
GridItem,
PageSection,
Expand All @@ -18,16 +22,11 @@ import {
TextListVariants,
TextVariants,
Toolbar,
ToolbarItem,
ToolbarContent,
EmptyState,
EmptyStateVariant,
EmptyStateIcon,
EmptyStateBody
ToolbarItem
} from '@patternfly/react-core';
import { Link, useParams } from 'react-router-dom';
import { global_spacer_md } from '@patternfly/react-tokens';
import { useApiAlert } from '@app/utils/useApiAlert';
import { DataContainerBreadcrumb } from '@app/Common/DataContainerBreadcrumb';
import { TableErrorState } from '@app/Common/TableErrorState';
import { PurgeIndex } from '@app/IndexManagement/PurgeIndex';
Expand All @@ -39,16 +38,19 @@ import { useConnectedUser } from '@app/services/userManagementHook';
import { useSearchStats } from '@app/services/statsHook';
import { DatabaseIcon } from '@patternfly/react-icons';
import { UpdateSchema } from '@app/IndexManagement/UpdateSchema';
import { useIndexMetamodel } from '@app/services/searchHook';
import { ViewMetamodel } from '@app/IndexManagement/ViewMetamodel';

const IndexManagement = () => {
const { t } = useTranslation();
const { addAlert } = useApiAlert();
const { connectedUser } = useConnectedUser();
const cacheName = useParams()['cacheName'] as string;
const { stats, loading, error, setLoading } = useSearchStats(cacheName);
const { indexMetamodel, loadingIndexMetamodel, errorIndexMetamodel } = useIndexMetamodel(cacheName);
const [purgeModalOpen, setPurgeModalOpen] = useState<boolean>(false);
const [reindexModalOpen, setReindexModalOpen] = useState<boolean>(false);
const [updateSchemaModalOpen, setUpdateSchemaModalOpen] = useState<boolean>(false);
const [indexMetamodelName, setIndexMetamodelName] = useState<string>('');

const closePurgeModal = () => {
setPurgeModalOpen(false);
Expand Down Expand Up @@ -145,19 +147,21 @@ const IndexManagement = () => {
<TextList component={TextListVariants.dl}>
<TextListItem component={TextListItemVariants.dt}>{t('caches.index.class-name')}</TextListItem>
<TextListItem component={TextListItemVariants.dd} key={'classNameValue'}>
<TextContent>{indexData.name}</TextContent>
<Text component={'a'} onClick={() => setIndexMetamodelName(indexData.name)}>
{indexData.name}
</Text>
</TextListItem>
<TextListItem component={TextListItemVariants.dt} key={'entriesCount'}>
{t('caches.index.entities-number')}
</TextListItem>
<TextListItem component={TextListItemVariants.dd} key={'entriesCountValue'}>
<TextContent>{indexData.count}</TextContent>
<Text>{indexData.count}</Text>
</TextListItem>
<TextListItem component={TextListItemVariants.dt} key={'sizes'}>
{t('caches.index.size')}
</TextListItem>
<TextListItem component={TextListItemVariants.dd} key={'sizesValue'}>
<TextContent>{indexData.size}</TextContent>
<Text>{indexData.size}</Text>
</TextListItem>
</TextList>
</TextContent>
Expand Down Expand Up @@ -220,6 +224,14 @@ const IndexManagement = () => {
<PurgeIndex cacheName={cacheName} isModalOpen={purgeModalOpen} closeModal={closePurgeModal} />
<Reindex cacheName={cacheName} isModalOpen={reindexModalOpen} closeModal={closeReindexModal} />
<UpdateSchema cacheName={cacheName} isModalOpen={updateSchemaModalOpen} closeModal={closeUpdateSchemaModal} />
<ViewMetamodel
metamodelName={indexMetamodelName}
metamodels={indexMetamodel}
loading={loadingIndexMetamodel}
error={errorIndexMetamodel}
isModalOpen={indexMetamodelName.length > 0}
closeModal={() => setIndexMetamodelName('')}
/>
</React.Fragment>
);
};
Expand Down
209 changes: 209 additions & 0 deletions src/app/IndexManagement/ViewMetamodel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
import React, { useState } from 'react';
import { Button, ButtonVariant, Icon, Modal, Pagination, Popover, Toolbar, ToolbarItem } from '@patternfly/react-core';
import { useTranslation } from 'react-i18next';
import { CheckCircleIcon, HelpIcon, ListIcon } from '@patternfly/react-icons';
import { TableEmptyState } from '@app/Common/TableEmptyState';
import { Table, TableVariant, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table';

/**
* Update schema modal
*/
const ViewMetamodel = (props: {
metamodelName: string;
metamodels: Map<string, IndexMetamodel>;
loading: boolean;
error: string;
isModalOpen: boolean;
closeModal: () => void;
}) => {
const { t } = useTranslation();
const [loadingFields, setLoadingFields] = useState(true);
const [fieldsPagination, setFieldsPagination] = useState<PaginationType>({
page: 1,
perPage: 10
});

const columnNames = {
name: t('caches.index.metamodel.column-name'),
searchable: t('caches.index.metamodel.column-searchable'),
sortable: t('caches.index.metamodel.column-sortable'),
projectable: t('caches.index.metamodel.column-projectable'),
aggregable: t('caches.index.metamodel.column-aggregable'),
multiValued: t('caches.index.metamodel.column-multi-valued'),
multiValuedInRoot: t('caches.index.metamodel.column-multi-valued-root'),
type: t('caches.index.metamodel.column-type'),
projectionType: t('caches.index.metamodel.column-projection-type'),
argumentType: t('caches.index.metamodel.column-argument-type')
};

const displayEnabled = (enabled: boolean) => {
if (!enabled) {
return <></>;
}

return (
<Icon status={'success'}>
<CheckCircleIcon />
</Icon>
);
};

const onSetPage = (_event, pageNumber) => {
setFieldsPagination({
...fieldsPagination,
page: pageNumber
});
};

const onPerPageSelect = (_event, perPage) => {
setFieldsPagination({
page: 1,
perPage: perPage
});
};

const buildContent = () => {
if (props.loading || props.error !== '' || !props.metamodels.get(props.metamodelName)) {
return <TableEmptyState loading={loadingFields} error={props.error} empty={t('common.loading-empty-message')} />;
}

const metamodel = props.metamodels.get(props.metamodelName) as IndexMetamodel;
const initSlice = (fieldsPagination.page - 1) * fieldsPagination.perPage;
const toolbarPagination = (dropDirection) => {
return (
<Toolbar>
<ToolbarItem variant="pagination">
<Pagination
data-cy="paginationArea"
itemCount={metamodel.valueFields.length}
perPage={fieldsPagination.perPage}
page={fieldsPagination.page}
onSetPage={onSetPage}
widgetId="pagination-fields"
onPerPageSelect={onPerPageSelect}
isCompact
dropDirection={dropDirection}
/>
</ToolbarItem>
</Toolbar>
);
};
return (
<React.Fragment>
{toolbarPagination('down')}
<Table aria-label="Metamodel table" variant={TableVariant.compact}>
<Thead>
<Tr>
<Th>{columnNames.name}</Th>
<Th>{columnNames.type}</Th>
<Th
info={{
popover: t('caches.index.metamodel.column-multi-valued-tooltip'),
popoverProps: {
headerContent: t('caches.index.metamodel.column-multi-valued')
}
}}
colSpan={1}
>
{columnNames.multiValued}
</Th>
<Th
info={{
popover: t('caches.index.metamodel.column-multi-valued-root-tooltip'),
popoverProps: {
headerContent: t('caches.index.metamodel.column-multi-valued-root')
}
}}
colSpan={1}
>
{columnNames.multiValuedInRoot}
</Th>
<Th
info={{
popover: t('caches.index.metamodel.column-aggregable-tooltip'),
popoverProps: {
headerContent: t('caches.index.metamodel.column-aggregable')
}
}}
colSpan={1}
>
{columnNames.aggregable}
</Th>
<Th
info={{
popover: t('caches.index.metamodel.column-projectable-tooltip'),
popoverProps: {
headerContent: t('caches.index.metamodel.column-projectable')
}
}}
colSpan={1}
>
{columnNames.projectable}
</Th>
<Th
info={{
popover: t('caches.index.metamodel.column-searchable-tooltip'),
popoverProps: {
headerContent: t('caches.index.metamodel.column-searchable')
}
}}
colSpan={1}
>
{columnNames.searchable}
</Th>
<Th
info={{
popover: t('caches.index.metamodel.column-sortable-tooltip'),
popoverProps: {
headerContent: t('caches.index.metamodel.column-sortable')
}
}}
colSpan={1}
>
{columnNames.sortable}
</Th>
</Tr>
</Thead>
<Tbody>
{metamodel.valueFields.slice(initSlice, initSlice + fieldsPagination.perPage).map((field) => (
<Tr key={field.name}>
<Td dataLabel={columnNames.name}>{field.name}</Td>
<Td dataLabel={columnNames.type}>{field.type}</Td>
<Td dataLabel={columnNames.multiValued}>{displayEnabled(field.multiValued)}</Td>
<Td dataLabel={columnNames.multiValuedInRoot}>{displayEnabled(field.multiValuedInRoot)}</Td>
<Td dataLabel={columnNames.aggregable}>{displayEnabled(field.aggregable)}</Td>
<Td dataLabel={columnNames.projectable}>{displayEnabled(field.projectable)}</Td>
<Td dataLabel={columnNames.searchable}>{displayEnabled(field.searchable)}</Td>
<Td dataLabel={columnNames.sortable}>{displayEnabled(field.sortable)}</Td>
</Tr>
))}
</Tbody>
</Table>
{toolbarPagination('up')}
</React.Fragment>
);
};

return (
<Modal
titleIconVariant={ListIcon}
isOpen={props.isModalOpen}
title={props.metamodelName}
onClose={props.closeModal}
help={
<Popover
headerContent={<div>{t('caches.index.metamodel.tooltip-title')}</div>}
bodyContent={<div>{t('caches.index.metamodel.tooltip-content')}</div>}
>
<Button variant="plain" aria-label="Help">
<HelpIcon />
</Button>
</Popover>
}
>
{buildContent()}
</Modal>
);
};

export { ViewMetamodel };
Loading

0 comments on commit 6636f03

Please sign in to comment.