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

ISPN-16490 Metamodel index view #481

Merged
merged 1 commit into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading