Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
karesti committed Sep 4, 2024
1 parent 9cb58fd commit cb6562c
Show file tree
Hide file tree
Showing 10 changed files with 272 additions and 19 deletions.
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
35 changes: 22 additions & 13 deletions src/app/IndexManagement/IndexManagement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import * as React from 'react';
import { useState } from 'react';
import {
Button,
ButtonVariant,
Card,
CardBody,
ButtonVariant, Card, CardBody,
EmptyState,
EmptyStateBody,
EmptyStateIcon,
EmptyStateVariant,
Grid,
GridItem,
PageSection,
Expand All @@ -18,16 +20,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 +36,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 +145,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 +222,13 @@ 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
141 changes: 141 additions & 0 deletions src/app/IndexManagement/ViewMetamodel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import React, { useState } from 'react';
import { Icon, Modal } from '@patternfly/react-core';
import { useTranslation } from 'react-i18next';
import { CheckCircleIcon, 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 [rows, setRows] = useState<IndexValueField[]>([]);
const [loadingFields, setLoadingFields] = useState(props.loading && rows.length == 0)
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 buildContent = () => {
if (props.loading || props.error !== '' || !props.metamodels.get(props.metamodelName)) {
return (
<TableEmptyState loading={props.loading}
error={props.error}
empty={t('common.loading-empty-message')}/>
)
}

const metamodel = props.metamodels.get(props.metamodelName) as IndexMetamodel;
return (
<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.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>
);
}

return (
<Modal
titleIconVariant={ListIcon}
width={'90%'}
isOpen={props.isModalOpen}
title={props.metamodelName}
onClose={props.closeModal}
>
{buildContent()}
</Modal>
);
};

export { ViewMetamodel };
19 changes: 19 additions & 0 deletions src/app/assets/languages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"clear": "Clear",
"update": "Update"
},
"loading-empty-message": "No result found.",
"loading-error-message": "There was an error retrieving data. Check your connection and try again.",
"tracing": {
"enabled": "Tracing is enabled",
Expand Down Expand Up @@ -696,6 +697,24 @@
"title": "Update schema?",
"description1": "Add new fields to the existing schema without having to rebuild the entire index.",
"description2": "This process may take a few minutes."
},
"metamodel": {
"column-name": "Name",
"column-searchable": "Searchable",
"column-searchable-tooltip": "A searchable field is one you can search within to find matching content.",
"column-sortable": "Sortable",
"column-sortable-tooltip": "A sortable field is one you can use to sort search results in order.",
"column-projectable": "Projectable",
"column-projectable-tooltip": "A projectable field is one you can include in the search results to display its value.",
"column-aggregable": "Aggregable",
"column-aggregable-tooltip": "An aggregable field is one you can use to group or calculate summary data, like totals or averages.",
"column-multi-valued": "Multi valued",
"column-multi-valued-tooltip": "A multi-valued field is one that can hold multiple values instead of just one.",
"column-multi-valued-root": "Multi valued in root",
"column-multi-valued-root-tooltip": "A multi-valued in root is a field that can hold multiple values at the top level of a document or object.",
"column-type": "Type",
"column-projection-type": "Projection type",
"column-argument-type": "Argument type"
}
},
"tracing": {
Expand Down
27 changes: 27 additions & 0 deletions src/app/services/searchHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,30 @@ export function useSearch(cacheName: string) {

return { search, setSearch };
}

export function useIndexMetamodel(cacheName: string) {
const [indexMetamodel, setIndexMetamodel] = useState<Map<string, IndexMetamodel>>(new Map());
const [errorIndexMetamodel, setErrorMetamodel] = useState('');
const [loadingIndexMetamodel, setLoadingIndexMetamodel] = useState(true);

useEffect(() => {
if (loadingIndexMetamodel) {
ConsoleServices.search()
.retrieveIndexMetamodel(cacheName)
.then((eitherMetamodel) => {
if (eitherMetamodel.isRight()) {
setIndexMetamodel(eitherMetamodel.value);
} else {
setErrorMetamodel(eitherMetamodel.value.message);
}
})
.then(() => setLoadingIndexMetamodel(false));
}
}, [loadingIndexMetamodel]);

return {
loadingIndexMetamodel,
errorIndexMetamodel,
indexMetamodel
};
}
33 changes: 33 additions & 0 deletions src/services/searchService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,39 @@ export class SearchService {
});
}

/**
* Retrieve index metamodel
*
* @param cacheName
*/
public async retrieveIndexMetamodel(cacheName: string): Promise<Either<ActionResponse, Map<string, IndexMetamodel>>> {
return this.utils.get(this.endpoint + encodeURIComponent(cacheName) + '/search/indexes/metamodel', (data) => {
const metamodels = new Map();
data.forEach(metamodel => {
const name = metamodel['entity-name'];
metamodels.set(name,
<IndexMetamodel>{
indexName: metamodel['index-name'],
entityName: name,
valueFields: Object.keys(metamodel['value-fields'])
.map(valueField => <IndexValueField> {
name: valueField,
multiValued: metamodel['value-fields'][valueField]['multi-valued'],
multiValuedInRoot: metamodel['value-fields'][valueField]['multi-valued-in-root'],
type: metamodel['value-fields'][valueField]['type'],
projectionType: metamodel['value-fields'][valueField]['projection-type'],
argumentType: metamodel['value-fields'][valueField]['argument-type'],
searchable: metamodel['value-fields'][valueField]['searchable'],
sortable: metamodel['value-fields'][valueField]['sortable'],
projectable: metamodel['value-fields'][valueField]['projectable'],
aggregable: metamodel['value-fields'][valueField]['aggregable'],
analyzer: metamodel['value-fields'][valueField]['analyzer']
})});
})
return metamodels;
});
}

/**
* Purge index for the cache name
*
Expand Down
Loading

0 comments on commit cb6562c

Please sign in to comment.