diff --git a/Makefile b/Makefile index 26e6d8451..bd02e661d 100644 --- a/Makefile +++ b/Makefile @@ -66,6 +66,7 @@ E2EDrecordsetEdit=test/e2e/specs/default-config/recordset/edit.config.ts E2ErecordsetAdd=test/e2e/specs/default-config/recordset/add.config.ts E2EDrecordsetIndFacet=test/e2e/specs/delete-prohibited/recordset/facet.config.ts E2EDrecordsetHistFacet=test/e2e/specs/delete-prohibited/recordset/histogram-facet.config.ts +E2EDrecordsetFacetWithinFacet=test/e2e/specs/default-config/recordset/facet-within-facet.config.ts E2ErecordsetSavedQuery=test/e2e/specs/all-features/recordset/saved-query.config.ts # misc tests @@ -88,7 +89,7 @@ Manualrecordset=test/manual/specs/recordset.config.ts # playwright tests NAVBAR_TESTS=$(E2Enavbar) $(E2EnavbarHeadTitle) $(E2EnavbarCatalogConfig) RECORD_TESTS=$(E2EDrecord) $(E2ErecordNoDeleteBtn) $(E2EDrecordRelatedTable) $(E2EDrecordCopy) $(E2EDrecordLinks) -RECORDSET_TESTS=$(E2EDrecordset) $(E2ErecordsetAdd) $(E2EDrecordsetEdit) $(E2ErecordsetSavedQuery) $(E2EDrecordsetIndFacet) $(E2EDrecordsetHistFacet) +RECORDSET_TESTS=$(E2EDrecordset) $(E2ErecordsetAdd) $(E2EDrecordsetEdit) $(E2ErecordsetSavedQuery) $(E2EDrecordsetIndFacet) $(E2EDrecordsetHistFacet) $(E2EDrecordsetFacetWithinFacet) RECORDADD_TESTS=$(E2EDIrecordAdd) $(E2EDIrecordImmutable) $(E2EDIrecordMultiFormInput) $(E2ErecordEditForeignKeyDropdown) $(E2EDrecordEditCompositeKey) RECORDEDIT_TESTS=$(E2EDIrecordEdit) $(E2EDrecordEditNullValues) $(E2ErecordEditInputIframe) $(E2EDrecordEditDomainFilter) PERMISSIONS_TESTS=$(E2EmultiPermissionsVisibility) diff --git a/config/chaise-config-sample.js b/config/chaise-config-sample.js index a085b52d1..b271a800c 100644 --- a/config/chaise-config-sample.js +++ b/config/chaise-config-sample.js @@ -25,7 +25,6 @@ var chaiseConfig = { editRecord: true, deleteRecord: true, maxRecordsetRowHeight: 160, - showFaceting: true, navbarBanner: [ { markdown_pattern: "This is a development version of Chaise", diff --git a/docs/dev-docs/e2e-test-writing.md b/docs/dev-docs/e2e-test-writing.md index 69a57a665..6bf4493ec 100644 --- a/docs/dev-docs/e2e-test-writing.md +++ b/docs/dev-docs/e2e-test-writing.md @@ -262,6 +262,11 @@ In here we've listed all the actions that we encountered and we found useful. Pl - Useful links - https://playwright.dev/docs/pages +- Use `generateChaiseURL` for creating a chaise url: + ```ts + await page.goto(generateChaiseURL(APP_NAMES.RECORD, 'schema', 'table', testInfo, baseURL) + '/id=12'); + ``` + - Use `clickNewTabLink` function in `page-utils.ts` for testing buttons that open a new tab: ```ts const newPage = await PageLocators.clickNewTabLink(someButton, context); diff --git a/docs/user-docs/chaise-config-change-logs.md b/docs/user-docs/chaise-config-change-logs.md index 0a68d25aa..58c9d263d 100644 --- a/docs/user-docs/chaise-config-change-logs.md +++ b/docs/user-docs/chaise-config-change-logs.md @@ -2,6 +2,17 @@ The file contains changes made to chaise-config parameters. - Refer to [chaise-config.d](chaise-config.md) for currently supported parameters - Refer to [chaise-config-deprecated.md](chaise-config-deprecated.md) for deprecated parameters +#### 09/25/2024 #### + +###### PR Link + - [chaise](https://github.com/informatics-isi-edu/chaise/pull/2545) + +###### Removed + - `showFaceting` has been removed in favor of the new `maxFacetDepth` property of `facetPanelDisplay`. + +###### Added + - `maxFacetDepth` was added to `facetPanelDisplay`. + #### 03/15/2024 #### ###### PR Link diff --git a/docs/user-docs/chaise-config-deprecated.md b/docs/user-docs/chaise-config-deprecated.md index 0aa28f405..dd2046416 100644 --- a/docs/user-docs/chaise-config-deprecated.md +++ b/docs/user-docs/chaise-config-deprecated.md @@ -11,6 +11,7 @@ This document contains deprecated chaise-config parameters. * [profileURL](#profileURL) * [Display Configuration:](#display-configuration) * [maxRelatedTablesOpen](#maxrelatedtablesopen) + * [showFaceting](#showfaceting) * [Share and Cite Configuration:](#share-and-cite-configuration) * [shareCiteAcls](#shareciteacls) * [Search Application](#search-application) @@ -72,6 +73,20 @@ This document contains deprecated chaise-config parameters. maxRelatedTablesOpen: 5 ``` +#### showFaceting + + If `true`, shows the faceting panel on the recordset app. + +> Now faceting panel is displayed by default. If you would like to disable it use the new `maxFacetDepth` property of [`facetPanelDisplay`](chaise-config.md#facetpaneldisplay). + + + - Type: Boolean + - Default behavior: the faceting panel will not be available on recordset page + - Sample syntax: + ``` + showFaceting: true + ``` + ### Share and Cite Configuration: #### shareCiteAcls diff --git a/docs/user-docs/chaise-config.md b/docs/user-docs/chaise-config.md index adfbf9682..a0b66231e 100644 --- a/docs/user-docs/chaise-config.md +++ b/docs/user-docs/chaise-config.md @@ -444,15 +444,6 @@ If a property appears in the same configuration twice, the property defined late showWriterEmptyRelatedOnLoad: false ``` - #### showFaceting - If `true`, shows the faceting panel on the recordset app. - - Type: Boolean - - Default behavior: the faceting panel will not be available on recordset page - - Sample syntax: - ``` - showFaceting: true - ``` - #### hideTableOfContents If true, hides the table of contents panel on the record app. - Type: Boolean @@ -481,24 +472,31 @@ If a property appears in the same configuration twice, the property defined late ``` #### facetPanelDisplay - Use this property to change the visibility of the facet panel on load. Currently the supported properties are `open` and `closed`. Both properties expect an array of - contexts and subcontexts associated with `compact` displays. `*` may be used but will be treated the same as `compact`. If a context is present in both open and closed, open will take priority. If the current context is not mentioned in either `open` or `closed`, it will try to inherit its value from a parent context. Defining only one array, `open` or `closed`, will assume the other property is equal to `[]`. + Use this property to change the settings related to the facet panel. + - Type: Object - - Default behavior: The facet panel will be open in the `compact` display and closed in all others. + - Default behavior: The facet panel will be displayed for all tables. It will be opened in the `compact` context (recordset app) and closed in all other subcontexts. - General syntax: ``` facetPanelDisplay: { open: [_context_], - closed: [_context_] + closed: [_context_], + maxFacetDepth: number } ``` - - `facetPanelDisplay` attributes: - - `open`: An array of contexts that the facet panel should be open for on page load. + - Attributes: + - `open`: An array of contexts that the facet panel should be open for on page load. Since facet panels are displayed on context and subcontexts associated with `compact`, only these annotations would be appropriate here. `*` may be used but will be treated the same as `compact`. If a context is present in both open and closed, open will take priority. If the current context is not mentioned in either `open` or `closed`, it will try to inherit its value from a parent context. Defining only one array, `open` or `closed`, will assume the other property is equal to `[]`. - `closed`: An array of contexts that the facet panel should be closed for on page load. + - `maxFacetDepth`: A number indicating how many levels of facets we should allow. The following are the acceptable values: + - 0: disable the faceting feature. + - 1: The default behavior. Facet panel is displayed on the initial recordset page or recordset popups. But it's not offered on the facet popups. + - 2: Facet panel is displayed on the initial recordset page or recordset popups. It's also displayed on the facet popups. + - 2+: Not allowed for now, as we think allowing more facets would confuse the users. When we encounter this value, we will use the maximum we support (2). - Sample syntax: ``` facetPanelDisplay: { - open: ["compact/select/association"] + open: ["compact/select/association"], + maxFacetDepth: 2 } ``` diff --git a/src/assets/scss/_faceting.scss b/src/assets/scss/_faceting.scss index 15f5f93ef..b48cae95d 100644 --- a/src/assets/scss/_faceting.scss +++ b/src/assets/scss/_faceting.scss @@ -64,6 +64,8 @@ border: 0; border-radius: 0; padding: 10px 5px; + // reserve enough space for the spinner and drag icons: + padding-right: 40px; text-transform: none; position: relative; // Overriding accordian-button css to align right angle bracket icon to left diff --git a/src/assets/scss/_modal.scss b/src/assets/scss/_modal.scss index a23e87a2f..c33b5b9d8 100644 --- a/src/assets/scss/_modal.scss +++ b/src/assets/scss/_modal.scss @@ -245,8 +245,22 @@ div.modal-title { .modal-header { padding: 0; padding-top: 20px; + &.modal-header-reduced-top-padding { + padding-top: 10px; + } + // we don't want it to be flex, since we're doing flex ourselves display: block; + + /** + * we have to make sure we're setting the min-width here as well, + * because the modal-header is outside of the recordset-container, so the _recordset.scss rule is not applied here + * (written the same way as app.scss and _recordset.scss) + */ + .top-panel-container .top-flex-panel .top-left-panel.open-panel, + .bottom-panel-container .side-panel-resizable.open-panel { + min-width: variables.$recordset-facet-panel-min-width; + } } .modal-body { diff --git a/src/assets/scss/_recordset.scss b/src/assets/scss/_recordset.scss index 46990bfe9..22c8fa7a4 100644 --- a/src/assets/scss/_recordset.scss +++ b/src/assets/scss/_recordset.scss @@ -3,11 +3,10 @@ .chaise-body { .recordset-container { - // override the minimum width of side-panel (written the same way as app.scss - // this is done to fit the more-filters message + // override the minimum width of side-panel (written the same way as app.scss) .top-panel-container .top-flex-panel .top-left-panel.open-panel, .bottom-panel-container .side-panel-resizable.open-panel { - min-width: 305px; + min-width: variables.$recordset-facet-panel-min-width; } .top-panel-container { @@ -159,6 +158,18 @@ } } + .modal-header-context { + color: map-get(variables.$color-map, 'modal-header-context'); + + .modal-header-context-separator { + padding: 0 0.3em; + font-size: 0.8em; + } + .modal-header-context-colon { + padding-left: 1px; + } + } + .side-panel-container { overflow-y: auto; overflow-x: hidden; diff --git a/src/assets/scss/_variables.scss b/src/assets/scss/_variables.scss index 915075ffe..e7d91cb49 100644 --- a/src/assets/scss/_variables.scss +++ b/src/assets/scss/_variables.scss @@ -32,6 +32,13 @@ $chaise-checkbox-height: 20px; // currently only used in recordedit. content/input shouldn't be wider than this $re-max-allowed-input-width: 1200px; +/** + * the value is set this so it would: + * - fit the more-filters message + * - have enough space for the drag icon and the rest of items on the header. + */ +$recordset-facet-panel-min-width: 305px; + // fonts $font-size: 14px; $h1-font-size: 2.5rem; diff --git a/src/assets/scss/maps/_color-map.scss b/src/assets/scss/maps/_color-map.scss index 18ab94d04..60494cfd8 100644 --- a/src/assets/scss/maps/_color-map.scss +++ b/src/assets/scss/maps/_color-map.scss @@ -18,6 +18,7 @@ $color-map: ( 'input-error-message-danger': #dc3545, 'input-error-message-warning': #c48d3e, 'link': #0366d6, + 'modal-header-context': #666, 'navbar-banner': #f9e3a1, 'navbar-collapsed-submenu': #d0e0f0, 'navbar-dropdown-submenu': #777, diff --git a/src/components/faceting/facet-choice-picker.tsx b/src/components/faceting/facet-choice-picker.tsx index b8fb19a8b..5f3075572 100644 --- a/src/components/faceting/facet-choice-picker.tsx +++ b/src/components/faceting/facet-choice-picker.tsx @@ -5,6 +5,7 @@ import ChaiseTooltip from '@isrd-isi-edu/chaise/src/components/tooltip'; import FacetCheckList from '@isrd-isi-edu/chaise/src/components/faceting/facet-check-list'; import RecordsetModal from '@isrd-isi-edu/chaise/src/components/modals/recordset-modal'; import SearchInput from '@isrd-isi-edu/chaise/src/components/search-input'; +import { TitleProps } from '@isrd-isi-edu/chaise/src/components/title'; // hooks import { useEffect, useLayoutEffect, useRef, useState } from 'react'; @@ -25,7 +26,6 @@ import { LogService } from '@isrd-isi-edu/chaise/src/services/log'; import $log from '@isrd-isi-edu/chaise/src/services/logger'; // utilities -import Q from 'q'; import { getNotNullFacetCheckBoxRow, getNullFacetCheckBoxRow } from '@isrd-isi-edu/chaise/src/utils/faceting-utils'; import { FACET_PANEL_DEFAULT_PAGE_SIZE, RECORDSET_DEFAULT_PAGE_SIZE } from '@isrd-isi-edu/chaise/src/utils/constants'; import { isStringAndNotEmpty } from '@isrd-isi-edu/chaise/src/utils/type-utils'; @@ -72,6 +72,10 @@ type FacetChoicePickerProps = { * get the facet log stack object */ getFacetLogStack: (index: number, extraInfo?: any) => any, + + recordsetUIContextTitles?: TitleProps[], + + recordsetFacetDepthLevel: number } const FacetChoicePicker = ({ @@ -85,6 +89,8 @@ const FacetChoicePicker = ({ updateRecordsetReference, getFacetLogAction, getFacetLogStack, + recordsetUIContextTitles, + recordsetFacetDepthLevel }: FacetChoicePickerProps): JSX.Element => { const isFirstRender = useIsFirstRender(); @@ -210,179 +216,178 @@ const FacetChoicePicker = ({ /** * The registered callback to pre-process facets */ - const preProcessFacet = () => { - const defer = Q.defer(); - - // if not_null exist, other filters are not relevant - if (facetColumnRef.current.hasNotNullFilter) { - // facetModel.appliedFilters.push(facetingUtils.getNotNullFilter(true)); - setCheckboxRows([getNotNullFacetCheckBoxRow(true)]); - - defer.resolve(); - } - else if (facetColumnRef.current.choiceFilters.length === 0) { - defer.resolve(); - } - else { - const res: FacetCheckBoxRow[] = []; - - // getChoiceDisplaynames won't return the null filter, so we need to check for it first - if (facetColumnRef.current.hasNullFilter) { - res.push(getNullFacetCheckBoxRow(true)); + const preProcessFacet = (): Promise => { + return new Promise((resolve, reject) => { + // if not_null exist, other filters are not relevant + if (facetColumnRef.current.hasNotNullFilter) { + // facetModel.appliedFilters.push(facetingUtils.getNotNullFilter(true)); + setCheckboxRows([getNotNullFacetCheckBoxRow(true)]); + + resolve(true); } + else if (facetColumnRef.current.choiceFilters.length === 0) { + resolve(true); + } + else { + const res: FacetCheckBoxRow[] = []; + + // getChoiceDisplaynames won't return the null filter, so we need to check for it first + if (facetColumnRef.current.hasNullFilter) { + res.push(getNullFacetCheckBoxRow(true)); + } - const facetLog = getDefaultLogInfo(); - facetLog.action = getFacetLogAction(facetIndex, LogActions.PRESELECTED_FACETS_LOAD); - facetColumnRef.current.getChoiceDisplaynames(facetLog).then(function (filters: any) { - filters.forEach(function (f: any) { - res.push({ - uniqueId: f.uniqueId, - displayname: f.displayname, - tuple: f.tuple, // the returned tuple might be null (in case of scalar) - selected: true + const facetLog = getDefaultLogInfo(); + facetLog.action = getFacetLogAction(facetIndex, LogActions.PRESELECTED_FACETS_LOAD); + facetColumnRef.current.getChoiceDisplaynames(facetLog).then(function (filters: any) { + filters.forEach(function (f: any) { + res.push({ + uniqueId: f.uniqueId, + displayname: f.displayname, + tuple: f.tuple, // the returned tuple might be null (in case of scalar) + selected: true + }); }); - }); - setCheckboxRows(res); + setCheckboxRows(res); - // this timeout will ensure that the set state is done before resolving - setTimeout(() => { - defer.resolve(); + // this timeout will ensure that the set state is done before resolving + setTimeout(() => { + resolve(true); + }); + }).catch(function (error: any) { + reject(error); }); - }).catch(function (error: any) { - defer.reject(error); - }); - } + } - return defer.promise; + }); } /** * The registered callback to process and update facets */ - const processFacet = (reloadCauses: string[], reloadStartTime: number) => { - const defer = Q.defer(); - - // we will set the checkboxRows to the value of this variable at the end - const updatedRows: FacetCheckBoxRow[] = []; - - // add not-null filter if it should be added - if (!facetColumnRef.current.hideNotNullChoice) { - updatedRows.push(getNotNullFacetCheckBoxRow(facetColumnRef.current.hasNotNullFilter)); - } + const processFacet = (reloadCauses: string[], reloadStartTime: number): Promise => { + return new Promise((resolve, reject) => { + // we will set the checkboxRows to the value of this variable at the end + const updatedRows: FacetCheckBoxRow[] = []; + + // add not-null filter if it should be added + if (!facetColumnRef.current.hideNotNullChoice) { + updatedRows.push(getNotNullFacetCheckBoxRow(facetColumnRef.current.hasNotNullFilter)); + } - // add null filter if it should be added - if (!facetColumnRef.current.hideNullChoice) { - updatedRows.push(getNullFacetCheckBoxRow(facetColumnRef.current.hasNullFilter)); - } + // add null filter if it should be added + if (!facetColumnRef.current.hideNullChoice) { + updatedRows.push(getNullFacetCheckBoxRow(facetColumnRef.current.hasNullFilter)); + } - // add the already selected facets (except null and not-null since they are already added) - updatedRows.push(...getAppliedFilters().filter((f) => !f.isNotNull && f.uniqueId !== null)); + // add the already selected facets (except null and not-null since they are already added) + updatedRows.push(...getAppliedFilters().filter((f) => !f.isNotNull && f.uniqueId !== null)); - // appliedLen: number of applied filters (apart from null and not-null) - //if this is more than PAGE_SIZE, we don't need to read the data. - let appliedLen = updatedRows.length; - if (facetColumn.hasNullFilter) appliedLen--; - if (facetColumn.hasNotNullFilter) appliedLen--; + // appliedLen: number of applied filters (apart from null and not-null) + //if this is more than PAGE_SIZE, we don't need to read the data. + let appliedLen = updatedRows.length; + if (facetColumn.hasNullFilter) appliedLen--; + if (facetColumn.hasNotNullFilter) appliedLen--; - // there are more than PAGE_SIZE selected rows, just display them. - if (appliedLen >= FACET_PANEL_DEFAULT_PAGE_SIZE) { - // there might be more, we're not sure - processFavorites(updatedRows).then(function (res) { + // there are more than PAGE_SIZE selected rows, just display them and don't fetch from the server. + if (appliedLen >= FACET_PANEL_DEFAULT_PAGE_SIZE) { + // there might be more, we're not sure + processFavorites(updatedRows).then((res: boolean) => { - setHasMore(true); - setCheckboxRows(updatedRows); + setHasMore(true); + setCheckboxRows(updatedRows); - defer.resolve(res); - }).catch(function (err) { - defer.reject(err); - }); - return defer.promise; - } - - (function (uri) { - // the reload causes and stuff should be handled by the parent not here - const facetLog = getDefaultLogInfo(); + resolve(res); + }).catch(function (err) { + reject(err); + }); - // // create the action - let action = LogActions.FACET_CHOICE_LOAD; - if (reloadCauses.length > 0) { - action = LogActions.FACET_CHOICE_RELOAD; - // add causes - facetLog.stack = LogService.addCausesToStack(facetLog.stack, reloadCauses, reloadStartTime); + // this is needed to ensure we're skipping the request + return; } - facetLog.action = getFacetLogAction(facetIndex, action); - // update the filter log info to stack - LogService.updateStackFilterInfo(facetLog.stack, facetReferenceRef.current.filterLogInfo); + (function (uri) { + // the reload causes and stuff should be handled by the parent not here + const facetLog = getDefaultLogInfo(); - facetReferenceRef.current.read(FACET_PANEL_DEFAULT_PAGE_SIZE, facetLog, true).then((page: any) => { - // if this is not the result of latest facet change - if (facetReferenceRef.current.uri !== uri) { - defer.resolve(false); - return defer.promise; + // // create the action + let action = LogActions.FACET_CHOICE_LOAD; + if (reloadCauses.length > 0) { + action = LogActions.FACET_CHOICE_RELOAD; + // add causes + facetLog.stack = LogService.addCausesToStack(facetLog.stack, reloadCauses, reloadStartTime); } + facetLog.action = getFacetLogAction(facetIndex, action); - setHasMore(page.hasNext); + // update the filter log info to stack + LogService.updateStackFilterInfo(facetLog.stack, facetReferenceRef.current.filterLogInfo); - page.tuples.forEach(function (tuple: any) { - // if we're showing enough rows - if (updatedRows.length === maxCheckboxLen) { + facetReferenceRef.current.read(FACET_PANEL_DEFAULT_PAGE_SIZE, facetLog, true).then((page: any) => { + // if this is not the result of latest facet change + if (facetReferenceRef.current.uri !== uri) { + resolve(false); return; } - // filter and tuple uniqueId might be different - const value = getFilterUniqueId(tuple, columnName); - - const i = updatedRows.findIndex(function (row) { - // ermrestjs always returns a string for uniqueId, but internally we don't - // eslint-disable-next-line eqeqeq - return row.uniqueId == value && !row.isNotNull; + setHasMore(page.hasNext); + + page.tuples.forEach(function (tuple: any) { + // if we're showing enough rows + if (updatedRows.length === maxCheckboxLen) { + return; + } + + // filter and tuple uniqueId might be different + const value = getFilterUniqueId(tuple, columnName); + + const i = updatedRows.findIndex(function (row) { + // ermrestjs always returns a string for uniqueId, but internally we don't + // eslint-disable-next-line eqeqeq + return row.uniqueId == value && !row.isNotNull; + }); + + // it's already selected + if (i !== -1) { + return; + } + + updatedRows.push({ + selected: false, + uniqueId: value, + displayname: tuple.displayname, + tuple: tuple + }); }); - // it's already selected - if (i !== -1) { + return processFavorites(updatedRows); + }).then((result: boolean) => { + // if this is not the result of latest facet change + if (facetReferenceRef.current.uri !== uri) { + resolve(false); return; } - updatedRows.push({ - selected: false, - uniqueId: value, - displayname: tuple.displayname, - tuple: tuple - }); - }); - - return processFavorites(updatedRows); - }).then((result: any) => { - // if this is not the result of latest facet change - if (facetReferenceRef.current.uri !== uri) { - defer.resolve(false); - return defer.promise; - } - - setCheckboxRows(updatedRows); - - defer.resolve(result); - }).catch(function (err: any) { - defer.reject(err); - }); - })(facetReferenceRef.current.uri); + setCheckboxRows(updatedRows); - return defer.promise; + resolve(result); + }).catch((err: any) => { + reject(err); + }); + })(facetReferenceRef.current.uri); + }); }; /** * The registered callback to get the selected filters */ - const getAppliedFilters = () => { + const getAppliedFilters = (): FacetCheckBoxRow[] => { return checkboxRowsRef.current.filter((cbr: FacetCheckBoxRow) => cbr.selected); }; /** * The registered callback to remove all the selected filters */ - const removeAppliedFilters = () => { + const removeAppliedFilters = (): void => { setCheckboxRows((prev: FacetCheckBoxRow[]) => { return prev.map((curr: FacetCheckBoxRow) => { return { ...curr, selected: false } @@ -404,12 +409,11 @@ const FacetChoicePicker = ({ return tuple.uniqueId; } - const processFavorites = (rows: any) => { - const defer = Q.defer(); - // TODO favorites - defer.resolve(true); - - return defer.promise; + const processFavorites = (rows: FacetCheckBoxRow[]): Promise => { + return new Promise((resolve) => { + // TODO favorites + resolve(true); + }); }; //------------------- UI related callbacks: --------------------// @@ -437,18 +441,17 @@ const FacetChoicePicker = ({ } const openRecordsetModal = () => { + const uiContextTitles = recordsetUIContextTitles ? [...recordsetUIContextTitles] : []; + const recordsetConfig: RecordsetConfig = { viewable: false, editable: false, deletable: false, sortable: true, selectMode: RecordsetSelectMode.MULTI_SELECT, - showFaceting: false, - disableFaceting: true, - // NOTE: can be uncommented for testing popups: - // showFaceting: true, - // disableFaceting: !facetColumn.isEntityMode, + disableFaceting: !facetColumn.isEntityMode, displayMode: RecordsetDisplayMode.FACET_POPUP, + facetDepthLevel: recordsetFacetDepthLevel + 1 // TODO // enableFavorites }; @@ -485,12 +488,18 @@ const FacetChoicePicker = ({ // if url limitation alert exists, remove it. removeURLLimitAlert(); + + uiContextTitles.push( + { displayname: facetColumn.displayname, comment: facetColumn.comment } + ) + setRecordsetModalProps({ initialReference: facetReferenceRef.current, initialPageLimit: RECORDSET_DEFAULT_PAGE_SIZE, config: recordsetConfig, logInfo, - initialSelectedRows + initialSelectedRows, + uiContextTitles }); }; @@ -602,6 +611,14 @@ const FacetChoicePicker = ({ i >= maxCheckboxLen && r.selected )).length; + const recordsetModalClassName = [ + 'faceting-show-details-popup', + `faceting-show-details-popup-depth-${recordsetFacetDepthLevel}` + ]; + if (!facetColumn.isEntityMode) { + recordsetModalClassName.push('scalar-show-details-popup'); + } + const renderPickerContainer = () => { const useShowMore = (hasMore || showFindMore); @@ -701,7 +718,7 @@ const FacetChoicePicker = ({ { recordsetModalProps && FacetCheckBoxRow[][], + removeAppliedFilters: (index?: number | 'filters' | 'cfacets') => void, + focusOnFacet: (index: number, dontUpdate?: boolean) => void + ) => void, /** * the recordset's log stack path */ @@ -51,13 +56,19 @@ type FacetingProps = { * callback that should be called when we're ready to initalize the data */ setReadyToInitialize: () => void, + + + recordsetFacetDepthLevel: number, + recordsetUIContextTitles?: TitleProps[] } const Faceting = ({ facetPanelOpen, registerRecordsetCallbacks, recordsetLogStackPath, - setReadyToInitialize + setReadyToInitialize, + recordsetUIContextTitles, + recordsetFacetDepthLevel }: FacetingProps) => { const { dispatchError } = useError(); @@ -388,8 +399,13 @@ const Faceting = ({ * Register the facet functions used for flow-control and recordset communication * When all the facets have called this function, it will ask flow-control to initialize data */ - const registerFacet = (index: number, processFacet: Function, preprocessFacet: Function, - getAppliedFilters: Function, removeAppliedFilters: Function) => { + const registerFacet = ( + index: number, + processFacet: (reloadCauses: string[], reloadStartTime: number) => Promise, + preprocessFacet: () => Promise, + getAppliedFilters: () => FacetCheckBoxRow[], + removeAppliedFilters: () => void + ) => { facetRequestModels.current[index].processFacet = processFacet; facetRequestModels.current[index].preProcessFacet = preprocessFacet; @@ -472,7 +488,7 @@ const Faceting = ({ const getFacetLogStack = (index: number, extraInfo?: any): any => { return getLogStack(facetRequestModels.current[index].logStackNode, extraInfo); - } + }; //------------------- callbacks that recordset will call: ----------------// /** @@ -720,6 +736,8 @@ const Faceting = ({ dispatchFacetUpdate={dispatchFacetUpdate} checkReferenceURL={checkReferenceURL} facetPanelOpen={facetPanelOpen} getFacetLogAction={getFacetLogAction} getFacetLogStack={getFacetLogStack} + recordsetUIContextTitles={recordsetUIContextTitles} + recordsetFacetDepthLevel={recordsetFacetDepthLevel} /> } }; diff --git a/src/components/input-switch/foreignkey-field.tsx b/src/components/input-switch/foreignkey-field.tsx index 61ae5733e..e49d307e4 100644 --- a/src/components/input-switch/foreignkey-field.tsx +++ b/src/components/input-switch/foreignkey-field.tsx @@ -134,7 +134,6 @@ const ForeignkeyField = (props: ForeignkeyFieldProps): JSX.Element => { deletable: false, sortable: true, selectMode: RecordsetSelectMode.SINGLE_SELECT, - showFaceting: true, disableFaceting: false, displayMode: (props.appMode === appModes.EDIT) ? RecordsetDisplayMode.FK_POPUP_EDIT : RecordsetDisplayMode.FK_POPUP_CREATE, }; @@ -219,7 +218,7 @@ const ForeignkeyField = (props: ForeignkeyFieldProps): JSX.Element => { } - diff --git a/src/components/modals/recordset-modal.tsx b/src/components/modals/recordset-modal.tsx index da46f9c9c..9dad5d04f 100644 --- a/src/components/modals/recordset-modal.tsx +++ b/src/components/modals/recordset-modal.tsx @@ -4,7 +4,7 @@ import Spinner from 'react-bootstrap/Spinner'; import ChaiseTooltip from '@isrd-isi-edu/chaise/src/components/tooltip'; import DisplayValue from '@isrd-isi-edu/chaise/src/components/display-value'; import Recordset from '@isrd-isi-edu/chaise/src/components/recordset/recordset'; -import Title from '@isrd-isi-edu/chaise/src/components/title'; +import Title, { TitleProps } from '@isrd-isi-edu/chaise/src/components/title'; import ChaiseSpinner from '@isrd-isi-edu/chaise/src/components/spinner'; // hooks @@ -205,6 +205,7 @@ const RecordsetModal = ({ // get the modal elements based on the available ref const modalContainerEl = modalContainer.current ? modalContainer.current.dialog.querySelector('.modal-content') as HTMLDivElement : undefined; const modalHeaderEl = modalHeader.current ? modalHeader.current : undefined; + const showUIContextTitles = displayMode === RecordsetDisplayMode.FACET_POPUP && recordsetProps.uiContextTitles; /** * figure out the modal size. @@ -214,7 +215,7 @@ const RecordsetModal = ({ */ let modalSize: undefined | 'lg' | 'xl'; let numCols = recordsetProps.initialReference.columns.length; - if (recordsetProps.config.showFaceting) { + if (!recordsetProps.config.disableFaceting && recordsetProps.initialReference.display.showFaceting) { numCols++; } if (numCols > 3) { @@ -252,84 +253,96 @@ const RecordsetModal = ({ break; } - const renderTitle = () => { - switch (displayMode) { - case RecordsetDisplayMode.FK_POPUP_CREATE: - // select for new - return ( -
- Select - - {recordsetProps.parentReference && - <span> - <span> for new </span> - <Title reference={recordsetProps.parentReference} /> - </span> - } - </div> - ); - case RecordsetDisplayMode.FK_POPUP_EDIT: - // select <col-displayname> for <parent-displayname>:<parent-tuple> - return ( - <div> - <span>Select </span> - <Title displayname={displayname} /> - {recordsetProps.parentReference && - <span> - <span> for </span> - <Title reference={recordsetProps.parentReference} /> - {recordsetProps.parentTuple && - <span>: <Title displayname={recordsetProps.parentTuple.displayname}> - } - - } -
- ); - case RecordsetDisplayMode.PURE_BINARY_POPUP_ADD: - return ( -
- Link - - <span> to </span> - <Title reference={recordsetProps.parentReference} /><span>: </span> - <Title displayname={recordsetProps.parentTuple?.displayname} /> - </div> - ); - case RecordsetDisplayMode.PURE_BINARY_POPUP_UNLINK: - return ( - <div> - <span>Unlink </span> - <Title displayname={displayname} comment={comment} /> - <span> from </span> - <Title reference={recordsetProps.parentReference} /><span>: </span> - <Title displayname={recordsetProps.parentTuple?.displayname} /> - </div> - ); - case RecordsetDisplayMode.FACET_POPUP: - return ( - <div> - <span>Search by </span> - <Title displayname={displayname} comment={comment} /> - </div>); - case RecordsetDisplayMode.SAVED_QUERY_POPUP: - return ( - <div> - <span>Saved search criteria for table </span> - <Title reference={recordsetProps.parentReference} /> - </div> - ); - default: - return ( - <div><Title addLink={false} reference={recordsetProps.initialReference} /></div> - ) - break; - } + let uiContextTitles: TitleProps[] | undefined, // the ui contexts that should be passed to recordset for the next level + titleEl: JSX.Element; // the modal title element. + switch (displayMode) { + case RecordsetDisplayMode.FK_POPUP_CREATE: + // select <col-displayname> for new <parent-displayname> + uiContextTitles = [{ displayname: displayname }]; + titleEl = ( + <div> + <span>Select </span> + <Title displayname={displayname} /> + {recordsetProps.parentReference && + <span> + <span> for new </span> + <Title reference={recordsetProps.parentReference} /> + </span> + } + </div> + ); + break; + case RecordsetDisplayMode.FK_POPUP_EDIT: + // select <col-displayname> for <parent-displayname>:<parent-tuple> + uiContextTitles = [{ displayname: displayname }]; + titleEl = ( + <div> + <span>Select </span> + <Title displayname={displayname} /> + {recordsetProps.parentReference && + <span> + <span> for </span> + <Title reference={recordsetProps.parentReference} /> + {recordsetProps.parentTuple && + <span>: <Title displayname={recordsetProps.parentTuple.displayname}> + } + + } +
+ ); + break; + case RecordsetDisplayMode.PURE_BINARY_POPUP_ADD: + uiContextTitles = [{ displayname: displayname }]; + titleEl = ( +
+ Link + + <span> to </span> + <Title reference={recordsetProps.parentReference} /><span>: </span> + <Title displayname={recordsetProps.parentTuple?.displayname} /> + </div> + ); + break; + case RecordsetDisplayMode.PURE_BINARY_POPUP_UNLINK: + uiContextTitles = [{ displayname: displayname }]; + titleEl = ( + <div> + <span>Unlink </span> + <Title displayname={displayname} comment={comment} /> + <span> from </span> + <Title reference={recordsetProps.parentReference} /><span>: </span> + <Title displayname={recordsetProps.parentTuple?.displayname} /> + </div> + ); + break; + case RecordsetDisplayMode.FACET_POPUP: + uiContextTitles = recordsetProps.uiContextTitles; + titleEl = ( + <div> + <span>Select </span> + <Title displayname={displayname} comment={comment} /> + </div>); + break; + case RecordsetDisplayMode.SAVED_QUERY_POPUP: + uiContextTitles = [{ reference: recordsetProps.parentReference }]; + titleEl = ( + <div> + <span>Saved search criteria for table </span> + <Title reference={recordsetProps.parentReference} /> + </div> + ); + break; + default: + titleEl = ( + <div><Title addLink={false} reference={recordsetProps.initialReference} /></div> + ) + break; } return ( <Modal - backdropClassName={`search-popup-backdrop ${modalBackdropClassName}`} - className={`search-popup ${modalClassName}`} + backdropClassName={`search-popup-backdrop ${modalBackdropClassName ? modalBackdropClassName : ''}`} + className={`search-popup ${modalClassName ? modalClassName : ''}`} size={modalSize} show={true} onHide={onClose} @@ -341,11 +354,21 @@ const RecordsetModal = ({ <ChaiseSpinner className='modal-submit-spinner' message='Saving the changes...' /> </div> } - <Modal.Header ref={modalHeader}> + <Modal.Header ref={modalHeader} className={showUIContextTitles ? 'modal-header-reduced-top-padding' : ''}> <div className='top-panel-container'> <div className='top-flex-panel'> <div className={`top-left-panel also-resizable ${panelClassName}`}></div> <div className='top-right-panel'> + {showUIContextTitles && recordsetProps.uiContextTitles && + <h4 className='modal-header-context'>{ + // the last one is the current context which we don't want to show here + recordsetProps.uiContextTitles.map((titleProps, i, arr) => ((i !== arr.length - 1) && <span key={i}> + {i > 0 && <i className='fa-solid fa-chevron-right modal-header-context-separator'></i>} + {<Title {...titleProps} />} + {i === arr.length - 2 && <span className='modal-header-context-colon'>:</span>} + </span>)) + }</h4> + } <div className='recordset-title-container title-container'> <div className='search-popup-controls recordset-title-buttons title-buttons'> {selectMode === RecordsetSelectMode.MULTI_SELECT && @@ -379,9 +402,7 @@ const RecordsetModal = ({ </button> </ChaiseTooltip> </div> - <h2 className='modal-title'> - {renderTitle()} - </h2> + <h2 className='modal-title'>{titleEl}</h2> </div> </div> </div> @@ -391,6 +412,7 @@ const RecordsetModal = ({ {showRecordset && <Recordset {...recordsetProps} + uiContextTitles={uiContextTitles} onSelectedRowsChanged={onSelectedRowsChangedWrapper} parentContainer={modalContainerEl} parentStickyArea={modalHeaderEl} diff --git a/src/components/record/related-table-actions.tsx b/src/components/record/related-table-actions.tsx index 30862337c..57459ab0d 100644 --- a/src/components/record/related-table-actions.tsx +++ b/src/components/record/related-table-actions.tsx @@ -320,7 +320,6 @@ const RelatedTableActions = ({ deletable: false, sortable: true, selectMode: RecordsetSelectMode.MULTI_SELECT, - showFaceting: true, disableFaceting: false, displayMode: RecordsetDisplayMode.PURE_BINARY_POPUP_ADD, }; @@ -478,7 +477,6 @@ const RelatedTableActions = ({ deletable: false, sortable: true, selectMode: RecordsetSelectMode.MULTI_SELECT, - showFaceting: true, disableFaceting: false, displayMode: RecordsetDisplayMode.PURE_BINARY_POPUP_UNLINK, }; diff --git a/src/components/recordedit/resultset-table.tsx b/src/components/recordedit/resultset-table.tsx index 5d8e23923..be3a32330 100644 --- a/src/components/recordedit/resultset-table.tsx +++ b/src/components/recordedit/resultset-table.tsx @@ -32,7 +32,6 @@ const ResultsetTable = ({ deletable: false, sortable: false, selectMode: RecordsetSelectMode.NO_SELECT, - showFaceting: false, disableFaceting: true, displayMode: RecordsetDisplayMode.TABLE } diff --git a/src/components/recordset/filter-chiclet.tsx b/src/components/recordset/filter-chiclet.tsx index 7e7b0cb61..d024c5c41 100644 --- a/src/components/recordset/filter-chiclet.tsx +++ b/src/components/recordset/filter-chiclet.tsx @@ -6,8 +6,9 @@ import ChaiseTooltip from '@isrd-isi-edu/chaise/src/components/tooltip'; type FilterChicletIdentifier = 'filters' | 'cfacets' | number; type FilterChicletProps = { /** - * The type of chiclet (if number, it's a facet) - * the identifier is passed to the onRemove function as well as onFocus + * The type of chiclet (if number, it's a facet). + * + * the identifier is passed to the onRemove and onTitleClick functions */ identifier: FilterChicletIdentifier, /** diff --git a/src/components/recordset/recordset.tsx b/src/components/recordset/recordset.tsx index bed196028..c1c9f7885 100644 --- a/src/components/recordset/recordset.tsx +++ b/src/components/recordset/recordset.tsx @@ -16,7 +16,7 @@ import SearchInput from '@isrd-isi-edu/chaise/src/components/search-input'; import SelectedRows from '@isrd-isi-edu/chaise/src/components/selected-rows'; import SplitView from '@isrd-isi-edu/chaise/src/components/split-view'; import TableHeader from '@isrd-isi-edu/chaise/src/components/recordset/table-header'; -import Title from '@isrd-isi-edu/chaise/src/components/title'; +import Title, { TitleProps } from '@isrd-isi-edu/chaise/src/components/title'; // hooks import React, { useEffect, useRef, useState } from 'react'; @@ -26,7 +26,7 @@ import useRecordset from '@isrd-isi-edu/chaise/src/hooks/recordset'; // models import { CommentDisplayModes } from '@isrd-isi-edu/chaise/src/models/displayname'; import { LogActions, LogReloadCauses, LogStackPaths, LogStackTypes } from '@isrd-isi-edu/chaise/src/models/log'; -import { RecordsetConfig, RecordsetDisplayMode, RecordsetProps, RecordsetSelectMode, SelectedRow } from '@isrd-isi-edu/chaise/src/models/recordset'; +import { FacetCheckBoxRow, RecordsetConfig, RecordsetDisplayMode, RecordsetProps, RecordsetSelectMode, SelectedRow } from '@isrd-isi-edu/chaise/src/models/recordset'; // providers import AlertsProvider from '@isrd-isi-edu/chaise/src/providers/alerts'; @@ -63,7 +63,8 @@ const Recordset = ({ onFacetPanelOpenChanged, parentReference, parentTuple, - savedQueryConfig + savedQueryConfig, + uiContextTitles }: RecordsetProps): JSX.Element => { return ( <AlertsProvider> @@ -88,6 +89,7 @@ const Recordset = ({ parentContainer={parentContainer} parentStickyArea={parentStickyArea} onFacetPanelOpenChanged={onFacetPanelOpenChanged} + uiContextTitles={uiContextTitles} /> </RecordsetProvider> </AlertsProvider> @@ -105,7 +107,8 @@ type RecordsetInnerProps = { }, parentContainer?: HTMLElement, parentStickyArea?: HTMLElement, - onFacetPanelOpenChanged?: (newState: boolean) => void + onFacetPanelOpenChanged?: (newState: boolean) => void, + uiContextTitles?: TitleProps[] }; /** @@ -119,7 +122,8 @@ const RecordsetInner = ({ logInfo, parentContainer, parentStickyArea, - onFacetPanelOpenChanged + onFacetPanelOpenChanged, + uiContextTitles }: RecordsetInnerProps): JSX.Element => { const { dispatchError, errors } = useError(); @@ -174,9 +178,9 @@ const RecordsetInner = ({ * The callbacks from faceting.tsx that we will use here */ const facetCallbacks = useRef<{ - getAppliedFilters: Function, - removeAppliedFilters: Function, - focusOnFacet: Function, + getAppliedFilters: () => FacetCheckBoxRow[][], + removeAppliedFilters: (index?: number | 'filters' | 'cfacets') => void, + focusOnFacet: (index: number, dontUpdate?: boolean) => void } | null>(null); const clearSearch = useRef<() => void>(null); @@ -518,7 +522,11 @@ const RecordsetInner = ({ /** * The callbacks from faceting.tsx that are used in this component */ - const registerCallbacksFromFaceting = (getAppliedFilters: Function, removeAppliedFilters: Function, focusOnFacet: Function) => { + const registerCallbacksFromFaceting = ( + getAppliedFilters: () => FacetCheckBoxRow[][], + removeAppliedFilters: () => void, + focusOnFacet: (index: number, dontUpdate?: boolean) => void + ) => { facetCallbacks.current = { getAppliedFilters, removeAppliedFilters, focusOnFacet }; } @@ -623,6 +631,9 @@ const RecordsetInner = ({ const panelClassName = facetPanelOpen ? 'open-panel' : 'close-panel'; + const recordsetUIContextTitles = uiContextTitles ? [...uiContextTitles] : [{ reference: initialReference }]; + const recordsetFacetDepthLevel = config.facetDepthLevel !== undefined ? config.facetDepthLevel : 1; + /** * version info */ @@ -726,7 +737,7 @@ const RecordsetInner = ({ valueTooltip={chicletValueTooltip} onRemove={(identifier) => facetCallbacks.current!.removeAppliedFilters(identifier)} // we cannot just pass the callback in the following since it's causing staleness state issue - onTitleClick={(identifier) => facetCallbacks.current!.focusOnFacet(identifier)} + onTitleClick={(identifier) => typeof identifier === 'number' && facetCallbacks.current!.focusOnFacet(identifier)} /> ); }); @@ -754,7 +765,7 @@ const RecordsetInner = ({ } const renderShowFilterPanelBtn = () => { - if (facetPanelOpen || !config.showFaceting || config.disableFaceting) { + if (facetPanelOpen || config.disableFaceting || !reference.display.showFaceting || (recordsetFacetDepthLevel > reference.display.maxFacetDepth)) { return; } return ( @@ -779,6 +790,8 @@ const RecordsetInner = ({ setReadyToInitialize={() => { setFacetsRegistered(true); }} + recordsetUIContextTitles={recordsetUIContextTitles} + recordsetFacetDepthLevel={recordsetFacetDepthLevel} /> </div> } diff --git a/src/components/recordset/saved-query-dropdown.tsx b/src/components/recordset/saved-query-dropdown.tsx index 80220101c..bd061eafb 100644 --- a/src/components/recordset/saved-query-dropdown.tsx +++ b/src/components/recordset/saved-query-dropdown.tsx @@ -521,7 +521,6 @@ const SavedQueryDropdown = ({ selectMode: RecordsetSelectMode.NO_SELECT, // NOTE: when supporting faceting in saved_queries popup // contextualize params.reference to compact/select/saved_queries and check reference.display.facetPanelOpen before setting false - showFaceting: false, disableFaceting: true, // used popup/savedquery so that we can configure which button to show and change the modal title displayMode: RecordsetDisplayMode.SAVED_QUERY_POPUP diff --git a/src/components/title.tsx b/src/components/title.tsx index e9650908a..3077e4344 100644 --- a/src/components/title.tsx +++ b/src/components/title.tsx @@ -8,7 +8,7 @@ import { CommentDisplayModes, CommentType, Displayname as DisplaynameType } from -type TitleProps = { +export type TitleProps = { /** * The reference object. */ diff --git a/src/models/recordset.ts b/src/models/recordset.ts index 3095460c8..705b558c4 100644 --- a/src/models/recordset.ts +++ b/src/models/recordset.ts @@ -3,6 +3,7 @@ import { Displayname } from '@isrd-isi-edu/chaise/src/models/displayname' import { RangeOption } from '@isrd-isi-edu/chaise/src/models/range-picker' import { FlowControlQueueInfo } from '@isrd-isi-edu/chaise/src/models/flow-control'; import { SavedQuery } from '@isrd-isi-edu/chaise/src/utils/config-utils'; +import { TitleProps } from '@isrd-isi-edu/chaise/src/components/title'; export type RecordsetProviderGetDisabledTuples = ( page: any, pageLimit: number, logStack: any, @@ -45,7 +46,14 @@ export type RecordsetProps = { * Currently used in recordset-modal to ensure the modal title's left-panel * is also closed with the panel */ - onFacetPanelOpenChanged?: (newState: boolean) => void + onFacetPanelOpenChanged?: (newState: boolean) => void, + + /** + * The context of the page (the breadcrumb titles displayed above the facet popup). + * + * used by the facet popups to summarize how many level deep we are. + */ + uiContextTitles?: TitleProps[] }; export enum RecordsetSelectMode { @@ -75,7 +83,10 @@ export type RecordsetConfig = { deletable: boolean, sortable: boolean, selectMode: RecordsetSelectMode, - showFaceting: boolean, + /** + * completely disable the faceting feature. + * if this is set to true, then we won't even show the facet chiclets + */ disableFaceting: boolean, displayMode: RecordsetDisplayMode, /** @@ -89,7 +100,19 @@ export type RecordsetConfig = { * limit the number of displayed records in the table (and trigger show more/less logic) * used in recordedit resultset-table */ - maxDisplayedRows?: number + maxDisplayedRows?: number, + + /** + * indicates how deep are we in the faceting feature. + * - 1 would be when we're showing a recordset page with facet (or a link/unlink popup with facet). + * - 2 is when you open the facet popup from the page or component with facetDepthLevel=1 + * - 3 is when you open the facet popup from the page or component with disableFaceting=2 + * - and so on. + * + * default: 1 + */ + facetDepthLevel?: number, + // TODO enable favorites // enableFavorites: boolean } @@ -133,10 +156,10 @@ export type FacetRequestModel = { // TODO why?? // appliedFilters: [], registered: boolean, - processFacet: Function, // TODO - preProcessFacet: Function, //TODO - getAppliedFilters: Function, // TODO - removeAppliedFilters: Function, // TODO + processFacet: (reloadCauses: string[], reloadStartTime: number) => Promise<boolean>, + preProcessFacet: () => Promise<boolean>, + getAppliedFilters: () => FacetCheckBoxRow[], + removeAppliedFilters: () => void, reloadCauses: string[], // why the reload request is being sent to the server (might be empty) reloadStartTime: number, //when the facet became dirty // TODO log stuff diff --git a/src/pages/recordset.tsx b/src/pages/recordset.tsx index b0af201ff..3abe8c5ac 100644 --- a/src/pages/recordset.tsx +++ b/src/pages/recordset.tsx @@ -100,7 +100,6 @@ const RecordsetApp = (): JSX.Element => { const chaiseConfig = ConfigService.chaiseConfig; const modifyEnabled = chaiseConfig.editRecord !== false; const deleteEnabled = chaiseConfig.deleteRecord === true; - const showFaceting = chaiseConfig.showFaceting === true; const recordsetConfig: RecordsetConfig = { viewable: true, @@ -108,7 +107,6 @@ const RecordsetApp = (): JSX.Element => { deletable: modifyEnabled && deleteEnabled, sortable: true, selectMode: RecordsetSelectMode.NO_SELECT, - showFaceting, disableFaceting: false, displayMode: RecordsetDisplayMode.FULLSCREEN, // TODO diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 9fee38287..6b605b851 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -23,7 +23,7 @@ export const CHAISE_CONFIG_PROPERTY_NAMES = [ 'navbarBrandImage', 'logoutURL', 'maxRecordsetRowHeight', 'dataBrowser', 'defaultAnnotationColor', 'confirmDelete', 'hideSearchTextFacet', 'editRecord', 'deleteRecord', 'defaultCatalog', 'defaultTable', 'signUpURL', 'navbarBanner', 'navbarMenu', 'sidebarPosition', 'attributesSidebarHeading', 'userGroups', - 'allowErrorDismissal', 'footerMarkdown', 'showFaceting', 'hideTableOfContents', + 'allowErrorDismissal', 'footerMarkdown', 'hideTableOfContents', 'resolverImplicitCatalog', 'disableDefaultExport', 'exportServicePath', 'assetDownloadPolicyURL', 'includeCanonicalTag', 'systemColumnsDisplayCompact', 'systemColumnsDisplayDetailed', 'systemColumnsDisplayEntry', 'logClientActions', 'disableExternalLinkModal', 'internalHosts', 'hideGoToRID', 'showWriterEmptyRelatedOnLoad', @@ -50,7 +50,6 @@ export const DEFAULT_CHAISE_CONFIG = { deleteRecord: false, signUpURL: '', allowErrorDismissal: false, - showFaceting: false, hideTableOfContents: false, navbarBanner: {}, navbarMenu: {}, diff --git a/src/utils/faceting-utils.ts b/src/utils/faceting-utils.ts index 8bc5fad5d..168605ee0 100644 --- a/src/utils/faceting-utils.ts +++ b/src/utils/faceting-utils.ts @@ -39,7 +39,7 @@ export function getNotNullFacetCheckBoxRow(selected?: boolean): FacetCheckBoxRow * @param initialReference the initial reference object */ export function getInitialFacetPanelOpen(config: RecordsetConfig, initialReference: any): boolean { - if (config.disableFaceting || !config.showFaceting) return false; + if (config.disableFaceting || !initialReference.display.showFaceting) return false; let res = initialReference.display.facetPanelOpen; if (typeof res !== 'boolean') { diff --git a/src/utils/record-utils.ts b/src/utils/record-utils.ts index 30413a80e..a41e70c58 100644 --- a/src/utils/record-utils.ts +++ b/src/utils/record-utils.ts @@ -164,7 +164,6 @@ export function generateRelatedRecordModel(ref: any, index: number, isInline: bo deletable: true, sortable: true, selectMode: RecordsetSelectMode.NO_SELECT, - showFaceting: false, disableFaceting: true, displayMode: isInline ? RecordsetDisplayMode.INLINE : RecordsetDisplayMode.RELATED, containerDetails: { isInline, index } @@ -373,7 +372,7 @@ export function getPrefillCookieObject(ref: any, mainTuple: any): { /** * Takes the displayname for a related table (both inline and related), and tries to find it on the record page. * used for table of contents click event and scrrolling on click of previous/next - * + * * @param displayname the displayname of the column to scroll to * @returns Element | false - returns the related table element to scroll to * - false if no element with displayname is found diff --git a/test/e2e/data_setup/config/parallel-configs/default-config.dev.json b/test/e2e/data_setup/config/parallel-configs/default-config.dev.json index f354823ec..ae82c46fb 100644 --- a/test/e2e/data_setup/config/parallel-configs/default-config.dev.json +++ b/test/e2e/data_setup/config/parallel-configs/default-config.dev.json @@ -11,7 +11,8 @@ "recordedit/null-values.config.json", "recordset/add.config.json", - "recordset/edit.config.json" + "recordset/edit.config.json", + "recordset/facet-within-facet.config.json" ] }, "cleanup" : true diff --git a/test/e2e/data_setup/config/recordset/facet-within-facet.config.json b/test/e2e/data_setup/config/recordset/facet-within-facet.config.json new file mode 100644 index 000000000..421667b76 --- /dev/null +++ b/test/e2e/data_setup/config/recordset/facet-within-facet.config.json @@ -0,0 +1,15 @@ +{ + "catalog": {}, + "schema": { + "name": "facet-within-facet", + "createNew": true, + "path": "test/e2e/data_setup/schema/recordset/facet-within-facet.json" + }, + "tables": { + "createNew": true + }, + "entities": { + "createNew": true, + "path": "test/e2e/data_setup/data/facet-within-facet" + } +} diff --git a/test/e2e/data_setup/config/recordset/facet-within-facet.dev.json b/test/e2e/data_setup/config/recordset/facet-within-facet.dev.json new file mode 100644 index 000000000..89f8c7f1d --- /dev/null +++ b/test/e2e/data_setup/config/recordset/facet-within-facet.dev.json @@ -0,0 +1,9 @@ +{ + "setup": { + "schemaConfigurations": [ + "recordset/facet-within-facet.config.json" + ], + "schema": "facet-within-facet" + }, + "cleanup": true +} diff --git a/test/e2e/data_setup/data/facet-within-facet/facet_2nd_layer_hub.json b/test/e2e/data_setup/data/facet-within-facet/facet_2nd_layer_hub.json new file mode 100644 index 000000000..45c057cbf --- /dev/null +++ b/test/e2e/data_setup/data/facet-within-facet/facet_2nd_layer_hub.json @@ -0,0 +1,77 @@ +[ + { + "id": "facet_2nd_layer_hub_01" + }, + { + "id": "facet_2nd_layer_hub_02", + "facet_2nd_layer_hub_to_main_inbound1_inbound1_fk_col": "main_inbound1_inbound1_01", + "facet_2nd_layer_hub_to_main_inbound1_inbound2_fk_col": "main_inbound1_inbound2_01", + "facet_2nd_layer_hub_to_main_inbound2_inbound1_fk_col": "main_inbound2_inbound1_01", + "facet_2nd_layer_hub_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_01", + "facet_2nd_layer_hub_to_main_inbound3_inbound1_fk_col": "main_inbound3_inbound1_01" + }, + { + "id": "facet_2nd_layer_hub_03", + "facet_2nd_layer_hub_to_main_inbound1_inbound1_fk_col": "main_inbound1_inbound1_02", + "facet_2nd_layer_hub_to_main_inbound1_inbound2_fk_col": "main_inbound1_inbound2_02", + "facet_2nd_layer_hub_to_main_inbound2_inbound1_fk_col": "main_inbound2_inbound1_02", + "facet_2nd_layer_hub_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_02", + "facet_2nd_layer_hub_to_main_inbound3_inbound1_fk_col": "main_inbound3_inbound1_02" + }, + { + "id": "facet_2nd_layer_hub_04", + "facet_2nd_layer_hub_to_main_inbound1_inbound1_fk_col": "main_inbound1_inbound1_03", + "facet_2nd_layer_hub_to_main_inbound1_inbound2_fk_col": "main_inbound1_inbound2_03", + "facet_2nd_layer_hub_to_main_inbound2_inbound1_fk_col": "main_inbound2_inbound1_03", + "facet_2nd_layer_hub_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_03", + "facet_2nd_layer_hub_to_main_inbound3_inbound1_fk_col": "main_inbound3_inbound1_03" + }, + { + "id": "facet_2nd_layer_hub_05", + "facet_2nd_layer_hub_to_main_inbound1_inbound1_fk_col": "main_inbound1_inbound1_04", + "facet_2nd_layer_hub_to_main_inbound1_inbound2_fk_col": "main_inbound1_inbound2_04", + "facet_2nd_layer_hub_to_main_inbound2_inbound1_fk_col": "main_inbound2_inbound1_04", + "facet_2nd_layer_hub_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_04", + "facet_2nd_layer_hub_to_main_inbound3_inbound1_fk_col": "main_inbound3_inbound1_04" + }, + { + "id": "facet_2nd_layer_hub_06", + "facet_2nd_layer_hub_to_main_inbound1_inbound1_fk_col": "main_inbound1_inbound1_05", + "facet_2nd_layer_hub_to_main_inbound1_inbound2_fk_col": "main_inbound1_inbound2_05", + "facet_2nd_layer_hub_to_main_inbound2_inbound1_fk_col": "main_inbound2_inbound1_05", + "facet_2nd_layer_hub_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_05", + "facet_2nd_layer_hub_to_main_inbound3_inbound1_fk_col": "main_inbound3_inbound1_05" + }, + { + "id": "facet_2nd_layer_hub_07", + "facet_2nd_layer_hub_to_main_inbound1_inbound1_fk_col": "main_inbound1_inbound1_06", + "facet_2nd_layer_hub_to_main_inbound1_inbound2_fk_col": "main_inbound1_inbound2_06", + "facet_2nd_layer_hub_to_main_inbound2_inbound1_fk_col": "main_inbound2_inbound1_06", + "facet_2nd_layer_hub_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_06", + "facet_2nd_layer_hub_to_main_inbound3_inbound1_fk_col": "main_inbound3_inbound1_06" + }, + { + "id": "facet_2nd_layer_hub_08", + "facet_2nd_layer_hub_to_main_inbound1_inbound1_fk_col": "main_inbound1_inbound1_07", + "facet_2nd_layer_hub_to_main_inbound1_inbound2_fk_col": "main_inbound1_inbound2_07", + "facet_2nd_layer_hub_to_main_inbound2_inbound1_fk_col": "main_inbound2_inbound1_07", + "facet_2nd_layer_hub_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_07", + "facet_2nd_layer_hub_to_main_inbound3_inbound1_fk_col": "main_inbound3_inbound1_07" + }, + { + "id": "facet_2nd_layer_hub_09", + "facet_2nd_layer_hub_to_main_inbound1_inbound1_fk_col": "main_inbound1_inbound1_08", + "facet_2nd_layer_hub_to_main_inbound1_inbound2_fk_col": "main_inbound1_inbound2_08", + "facet_2nd_layer_hub_to_main_inbound2_inbound1_fk_col": "main_inbound2_inbound1_08", + "facet_2nd_layer_hub_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_08", + "facet_2nd_layer_hub_to_main_inbound3_inbound1_fk_col": "main_inbound3_inbound1_08" + }, + { + "id": "facet_2nd_layer_hub_10", + "facet_2nd_layer_hub_to_main_inbound1_inbound1_fk_col": "main_inbound1_inbound1_09", + "facet_2nd_layer_hub_to_main_inbound1_inbound2_fk_col": "main_inbound1_inbound2_09", + "facet_2nd_layer_hub_to_main_inbound2_inbound1_fk_col": "main_inbound2_inbound1_09", + "facet_2nd_layer_hub_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_09", + "facet_2nd_layer_hub_to_main_inbound3_inbound1_fk_col": "main_inbound3_inbound1_09" + } +] diff --git a/test/e2e/data_setup/data/facet-within-facet/facet_2nd_layer_hub_inbound1.json b/test/e2e/data_setup/data/facet-within-facet/facet_2nd_layer_hub_inbound1.json new file mode 100644 index 000000000..58dfa62ed --- /dev/null +++ b/test/e2e/data_setup/data/facet-within-facet/facet_2nd_layer_hub_inbound1.json @@ -0,0 +1,75 @@ +[ + { + "id": "facet_2nd_layer_hub_inbound1_01", + "facet_col": "one facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound1_02", + "facet_col": "two facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound1_03", + "facet_2nd_layer_hub_inbound1_fk_col": "facet_2nd_layer_hub_01", + "facet_col": "three facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound1_04", + "facet_2nd_layer_hub_inbound1_fk_col": "facet_2nd_layer_hub_01", + "facet_col": "four facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound1_05", + "facet_2nd_layer_hub_inbound1_fk_col": "facet_2nd_layer_hub_01", + "facet_col": "five facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound1_06", + "facet_2nd_layer_hub_inbound1_fk_col": "facet_2nd_layer_hub_02", + "facet_col": "six facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound1_07", + "facet_2nd_layer_hub_inbound1_fk_col": "facet_2nd_layer_hub_02", + "facet_col": "seven facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound1_08", + "facet_2nd_layer_hub_inbound1_fk_col": "facet_2nd_layer_hub_03", + "facet_col": "eight facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound1_09", + "facet_2nd_layer_hub_inbound1_fk_col": "facet_2nd_layer_hub_03", + "facet_col": "nine facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound1_10", + "facet_2nd_layer_hub_inbound1_fk_col": "facet_2nd_layer_hub_04", + "facet_col": "ten facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound1_11", + "facet_2nd_layer_hub_inbound1_fk_col": "facet_2nd_layer_hub_04", + "facet_col": "eleven facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound1_12", + "facet_2nd_layer_hub_inbound1_fk_col": "facet_2nd_layer_hub_05", + "facet_col": "twelve facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound1_13", + "facet_2nd_layer_hub_inbound1_fk_col": "facet_2nd_layer_hub_06", + "facet_col": "twelve facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound1_14", + "facet_2nd_layer_hub_inbound1_fk_col": "facet_2nd_layer_hub_07", + "facet_col": "twelve facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound1_15", + "facet_2nd_layer_hub_inbound1_fk_col": "facet_2nd_layer_hub_08", + "facet_col": "twelve facet_2nd_layer_hub_inbound1" + } +] diff --git a/test/e2e/data_setup/data/facet-within-facet/facet_2nd_layer_hub_inbound2.json b/test/e2e/data_setup/data/facet-within-facet/facet_2nd_layer_hub_inbound2.json new file mode 100644 index 000000000..5bc16e716 --- /dev/null +++ b/test/e2e/data_setup/data/facet-within-facet/facet_2nd_layer_hub_inbound2.json @@ -0,0 +1,75 @@ +[ + { + "id": "facet_2nd_layer_hub_inbound2_01", + "facet_col": "one facet_2nd_layer_hub_inbound2" + }, + { + "id": "facet_2nd_layer_hub_inbound2_02", + "facet_col": "two facet_2nd_layer_hub_inbound2" + }, + { + "id": "facet_2nd_layer_hub_inbound2_03", + "facet_2nd_layer_hub_inbound2_fk_col": "facet_2nd_layer_hub_01", + "facet_col": "three facet_2nd_layer_hub_inbound2" + }, + { + "id": "facet_2nd_layer_hub_inbound2_04", + "facet_2nd_layer_hub_inbound2_fk_col": "facet_2nd_layer_hub_01", + "facet_col": "four facet_2nd_layer_hub_inbound2" + }, + { + "id": "facet_2nd_layer_hub_inbound2_05", + "facet_2nd_layer_hub_inbound2_fk_col": "facet_2nd_layer_hub_01", + "facet_col": "five facet_2nd_layer_hub_inbound2" + }, + { + "id": "facet_2nd_layer_hub_inbound2_06", + "facet_2nd_layer_hub_inbound2_fk_col": "facet_2nd_layer_hub_02", + "facet_col": "six facet_2nd_layer_hub_inbound2" + }, + { + "id": "facet_2nd_layer_hub_inbound2_07", + "facet_2nd_layer_hub_inbound2_fk_col": "facet_2nd_layer_hub_02", + "facet_col": "seven facet_2nd_layer_hub_inbound2" + }, + { + "id": "facet_2nd_layer_hub_inbound2_08", + "facet_2nd_layer_hub_inbound2_fk_col": "facet_2nd_layer_hub_03", + "facet_col": "eight facet_2nd_layer_hub_inbound2" + }, + { + "id": "facet_2nd_layer_hub_inbound2_09", + "facet_2nd_layer_hub_inbound2_fk_col": "facet_2nd_layer_hub_03", + "facet_col": "nine facet_2nd_layer_hub_inbound2" + }, + { + "id": "facet_2nd_layer_hub_inbound2_10", + "facet_2nd_layer_hub_inbound2_fk_col": "facet_2nd_layer_hub_04", + "facet_col": "ten facet_2nd_layer_hub_inbound2" + }, + { + "id": "facet_2nd_layer_hub_inbound2_11", + "facet_2nd_layer_hub_inbound2_fk_col": "facet_2nd_layer_hub_04", + "facet_col": "eleven facet_2nd_layer_hub_inbound2" + }, + { + "id": "facet_2nd_layer_hub_inbound2_12", + "facet_2nd_layer_hub_inbound2_fk_col": "facet_2nd_layer_hub_05", + "facet_col": "twelve facet_2nd_layer_hub_inbound2" + }, + { + "id": "facet_2nd_layer_hub_inbound2_13", + "facet_2nd_layer_hub_inbound2_fk_col": "facet_2nd_layer_hub_06", + "facet_col": "twelve facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound2_14", + "facet_2nd_layer_hub_inbound2_fk_col": "facet_2nd_layer_hub_07", + "facet_col": "twelve facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound2_15", + "facet_2nd_layer_hub_inbound2_fk_col": "facet_2nd_layer_hub_08", + "facet_col": "twelve facet_2nd_layer_hub_inbound1" + } +] diff --git a/test/e2e/data_setup/data/facet-within-facet/facet_2nd_layer_hub_inbound3.json b/test/e2e/data_setup/data/facet-within-facet/facet_2nd_layer_hub_inbound3.json new file mode 100644 index 000000000..fd6d4f627 --- /dev/null +++ b/test/e2e/data_setup/data/facet-within-facet/facet_2nd_layer_hub_inbound3.json @@ -0,0 +1,75 @@ +[ + { + "id": "facet_2nd_layer_hub_inbound3_01", + "facet_col": "one facet_2nd_layer_hub_inbound3" + }, + { + "id": "facet_2nd_layer_hub_inbound3_02", + "facet_col": "two facet_2nd_layer_hub_inbound3" + }, + { + "id": "facet_2nd_layer_hub_inbound3_03", + "facet_2nd_layer_hub_inbound3_fk_col": "facet_2nd_layer_hub_01", + "facet_col": "three facet_2nd_layer_hub_inbound3" + }, + { + "id": "facet_2nd_layer_hub_inbound3_04", + "facet_2nd_layer_hub_inbound3_fk_col": "facet_2nd_layer_hub_01", + "facet_col": "four facet_2nd_layer_hub_inbound3" + }, + { + "id": "facet_2nd_layer_hub_inbound3_05", + "facet_2nd_layer_hub_inbound3_fk_col": "facet_2nd_layer_hub_01", + "facet_col": "five facet_2nd_layer_hub_inbound3" + }, + { + "id": "facet_2nd_layer_hub_inbound3_06", + "facet_2nd_layer_hub_inbound3_fk_col": "facet_2nd_layer_hub_02", + "facet_col": "six facet_2nd_layer_hub_inbound3" + }, + { + "id": "facet_2nd_layer_hub_inbound3_07", + "facet_2nd_layer_hub_inbound3_fk_col": "facet_2nd_layer_hub_02", + "facet_col": "seven facet_2nd_layer_hub_inbound3" + }, + { + "id": "facet_2nd_layer_hub_inbound3_08", + "facet_2nd_layer_hub_inbound3_fk_col": "facet_2nd_layer_hub_03", + "facet_col": "eight facet_2nd_layer_hub_inbound3" + }, + { + "id": "facet_2nd_layer_hub_inbound3_09", + "facet_2nd_layer_hub_inbound3_fk_col": "facet_2nd_layer_hub_03", + "facet_col": "nine facet_2nd_layer_hub_inbound3" + }, + { + "id": "facet_2nd_layer_hub_inbound3_10", + "facet_2nd_layer_hub_inbound3_fk_col": "facet_2nd_layer_hub_04", + "facet_col": "ten facet_2nd_layer_hub_inbound3" + }, + { + "id": "facet_2nd_layer_hub_inbound3_11", + "facet_2nd_layer_hub_inbound3_fk_col": "facet_2nd_layer_hub_04", + "facet_col": "eleven facet_2nd_layer_hub_inbound3" + }, + { + "id": "facet_2nd_layer_hub_inbound3_12", + "facet_2nd_layer_hub_inbound3_fk_col": "facet_2nd_layer_hub_05", + "facet_col": "twelve facet_2nd_layer_hub_inbound3" + }, + { + "id": "facet_2nd_layer_hub_inbound3_13", + "facet_2nd_layer_hub_inbound3_fk_col": "facet_2nd_layer_hub_06", + "facet_col": "twelve facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound3_14", + "facet_2nd_layer_hub_inbound3_fk_col": "facet_2nd_layer_hub_07", + "facet_col": "twelve facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound3_15", + "facet_2nd_layer_hub_inbound3_fk_col": "facet_2nd_layer_hub_08", + "facet_col": "twelve facet_2nd_layer_hub_inbound1" + } +] diff --git a/test/e2e/data_setup/data/facet-within-facet/facet_2nd_layer_hub_inbound4.json b/test/e2e/data_setup/data/facet-within-facet/facet_2nd_layer_hub_inbound4.json new file mode 100644 index 000000000..89d461936 --- /dev/null +++ b/test/e2e/data_setup/data/facet-within-facet/facet_2nd_layer_hub_inbound4.json @@ -0,0 +1,75 @@ +[ + { + "id": "facet_2nd_layer_hub_inbound4_01", + "facet_col": "one facet_2nd_layer_hub_inbound4" + }, + { + "id": "facet_2nd_layer_hub_inbound4_02", + "facet_col": "two facet_2nd_layer_hub_inbound4" + }, + { + "id": "facet_2nd_layer_hub_inbound4_03", + "facet_2nd_layer_hub_inbound4_fk_col": "facet_2nd_layer_hub_01", + "facet_col": "three facet_2nd_layer_hub_inbound4" + }, + { + "id": "facet_2nd_layer_hub_inbound4_04", + "facet_2nd_layer_hub_inbound4_fk_col": "facet_2nd_layer_hub_01", + "facet_col": "four facet_2nd_layer_hub_inbound4" + }, + { + "id": "facet_2nd_layer_hub_inbound4_05", + "facet_2nd_layer_hub_inbound4_fk_col": "facet_2nd_layer_hub_01", + "facet_col": "five facet_2nd_layer_hub_inbound4" + }, + { + "id": "facet_2nd_layer_hub_inbound4_06", + "facet_2nd_layer_hub_inbound4_fk_col": "facet_2nd_layer_hub_02", + "facet_col": "six facet_2nd_layer_hub_inbound4" + }, + { + "id": "facet_2nd_layer_hub_inbound4_07", + "facet_2nd_layer_hub_inbound4_fk_col": "facet_2nd_layer_hub_02", + "facet_col": "seven facet_2nd_layer_hub_inbound4" + }, + { + "id": "facet_2nd_layer_hub_inbound4_08", + "facet_2nd_layer_hub_inbound4_fk_col": "facet_2nd_layer_hub_03", + "facet_col": "eight facet_2nd_layer_hub_inbound4" + }, + { + "id": "facet_2nd_layer_hub_inbound4_09", + "facet_2nd_layer_hub_inbound4_fk_col": "facet_2nd_layer_hub_03", + "facet_col": "nine facet_2nd_layer_hub_inbound4" + }, + { + "id": "facet_2nd_layer_hub_inbound4_10", + "facet_2nd_layer_hub_inbound4_fk_col": "facet_2nd_layer_hub_04", + "facet_col": "ten facet_2nd_layer_hub_inbound4" + }, + { + "id": "facet_2nd_layer_hub_inbound4_11", + "facet_2nd_layer_hub_inbound4_fk_col": "facet_2nd_layer_hub_04", + "facet_col": "eleven facet_2nd_layer_hub_inbound4" + }, + { + "id": "facet_2nd_layer_hub_inbound4_12", + "facet_2nd_layer_hub_inbound4_fk_col": "facet_2nd_layer_hub_05", + "facet_col": "twelve facet_2nd_layer_hub_inbound4" + }, + { + "id": "facet_2nd_layer_hub_inbound4_13", + "facet_2nd_layer_hub_inbound4_fk_col": "facet_2nd_layer_hub_06", + "facet_col": "twelve facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound4_14", + "facet_2nd_layer_hub_inbound4_fk_col": "facet_2nd_layer_hub_07", + "facet_col": "twelve facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound4_15", + "facet_2nd_layer_hub_inbound4_fk_col": "facet_2nd_layer_hub_08", + "facet_col": "twelve facet_2nd_layer_hub_inbound1" + } +] diff --git a/test/e2e/data_setup/data/facet-within-facet/facet_2nd_layer_hub_inbound5.json b/test/e2e/data_setup/data/facet-within-facet/facet_2nd_layer_hub_inbound5.json new file mode 100644 index 000000000..30ba03206 --- /dev/null +++ b/test/e2e/data_setup/data/facet-within-facet/facet_2nd_layer_hub_inbound5.json @@ -0,0 +1,75 @@ +[ + { + "id": "facet_2nd_layer_hub_inbound5_01", + "facet_col": "one facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_02", + "facet_col": "two facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_03", + "facet_2nd_layer_hub_inbound5_fk_col": "facet_2nd_layer_hub_01", + "facet_col": "three facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_04", + "facet_2nd_layer_hub_inbound5_fk_col": "facet_2nd_layer_hub_01", + "facet_col": "four facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_05", + "facet_2nd_layer_hub_inbound5_fk_col": "facet_2nd_layer_hub_01", + "facet_col": "five facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_06", + "facet_2nd_layer_hub_inbound5_fk_col": "facet_2nd_layer_hub_02", + "facet_col": "six facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_07", + "facet_2nd_layer_hub_inbound5_fk_col": "facet_2nd_layer_hub_02", + "facet_col": "seven facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_08", + "facet_2nd_layer_hub_inbound5_fk_col": "facet_2nd_layer_hub_03", + "facet_col": "eight facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_09", + "facet_2nd_layer_hub_inbound5_fk_col": "facet_2nd_layer_hub_03", + "facet_col": "nine facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_10", + "facet_2nd_layer_hub_inbound5_fk_col": "facet_2nd_layer_hub_04", + "facet_col": "ten facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_11", + "facet_2nd_layer_hub_inbound5_fk_col": "facet_2nd_layer_hub_04", + "facet_col": "eleven facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_12", + "facet_2nd_layer_hub_inbound5_fk_col": "facet_2nd_layer_hub_05", + "facet_col": "twelve facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_13", + "facet_2nd_layer_hub_inbound5_fk_col": "facet_2nd_layer_hub_06", + "facet_col": "twelve facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound5_14", + "facet_2nd_layer_hub_inbound5_fk_col": "facet_2nd_layer_hub_07", + "facet_col": "twelve facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound5_15", + "facet_2nd_layer_hub_inbound5_fk_col": "facet_2nd_layer_hub_08", + "facet_col": "twelve facet_2nd_layer_hub_inbound1" + } +] diff --git a/test/e2e/data_setup/data/facet-within-facet/facet_2nd_layer_hub_inbound5_fast_filter.json b/test/e2e/data_setup/data/facet-within-facet/facet_2nd_layer_hub_inbound5_fast_filter.json new file mode 100644 index 000000000..32b30c2da --- /dev/null +++ b/test/e2e/data_setup/data/facet-within-facet/facet_2nd_layer_hub_inbound5_fast_filter.json @@ -0,0 +1,75 @@ +[ + { + "id": "facet_2nd_layer_hub_inbound5_01", + "facet_col": "one facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_02", + "facet_col": "two facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_03", + "facet_2nd_layer_hub_inbound5_fast_filter_fk_col": "facet_2nd_layer_hub_01", + "facet_col": "three facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_04", + "facet_2nd_layer_hub_inbound5_fast_filter_fk_col": "facet_2nd_layer_hub_01", + "facet_col": "four facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_05", + "facet_2nd_layer_hub_inbound5_fast_filter_fk_col": "facet_2nd_layer_hub_01", + "facet_col": "five facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_06", + "facet_2nd_layer_hub_inbound5_fast_filter_fk_col": "facet_2nd_layer_hub_02", + "facet_col": "six facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_07", + "facet_2nd_layer_hub_inbound5_fast_filter_fk_col": "facet_2nd_layer_hub_02", + "facet_col": "seven facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_08", + "facet_2nd_layer_hub_inbound5_fast_filter_fk_col": "facet_2nd_layer_hub_03", + "facet_col": "eight facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_09", + "facet_2nd_layer_hub_inbound5_fast_filter_fk_col": "facet_2nd_layer_hub_03", + "facet_col": "nine facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_10", + "facet_2nd_layer_hub_inbound5_fast_filter_fk_col": "facet_2nd_layer_hub_04", + "facet_col": "ten facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_11", + "facet_2nd_layer_hub_inbound5_fast_filter_fk_col": "facet_2nd_layer_hub_04", + "facet_col": "eleven facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_12", + "facet_2nd_layer_hub_inbound5_fast_filter_fk_col": "facet_2nd_layer_hub_05", + "facet_col": "twelve facet_2nd_layer_hub_inbound5" + }, + { + "id": "facet_2nd_layer_hub_inbound5_13", + "facet_2nd_layer_hub_inbound5_fast_filter_fk_col": "facet_2nd_layer_hub_06", + "facet_col": "twelve facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound5_14", + "facet_2nd_layer_hub_inbound5_fast_filter_fk_col": "facet_2nd_layer_hub_07", + "facet_col": "twelve facet_2nd_layer_hub_inbound1" + }, + { + "id": "facet_2nd_layer_hub_inbound5_15", + "facet_2nd_layer_hub_inbound5_fast_filter_fk_col": "facet_2nd_layer_hub_08", + "facet_col": "twelve facet_2nd_layer_hub_inbound1" + } +] diff --git a/test/e2e/data_setup/data/facet-within-facet/main.json b/test/e2e/data_setup/data/facet-within-facet/main.json new file mode 100644 index 000000000..b72105e33 --- /dev/null +++ b/test/e2e/data_setup/data/facet-within-facet/main.json @@ -0,0 +1,62 @@ +[ + { + "id": "main_01" + }, + { + "id": "main_02" + }, + { + "id": "main_03" + }, + { + "id": "main_04" + }, + { + "id": "main_05" + }, + { + "id": "main_06" + }, + { + "id": "main_07" + }, + { + "id": "main_08" + }, + { + "id": "main_09" + }, + { + "id": "main_10" + }, + { + "id": "main_11" + }, + { + "id": "main_12" + }, + { + "id": "main_13" + }, + { + "id": "main_14" + }, + { + "id": "main_15" + }, + { + "id": "main_16" + }, + { + "id": "main_17" + }, + { + "id": "main_18" + }, + { + "id": "main_19" + }, + { + "id": "main_20" + } +] diff --git a/test/e2e/data_setup/data/facet-within-facet/main_inbound1.json b/test/e2e/data_setup/data/facet-within-facet/main_inbound1.json new file mode 100644 index 000000000..40814790e --- /dev/null +++ b/test/e2e/data_setup/data/facet-within-facet/main_inbound1.json @@ -0,0 +1,65 @@ +[ + { + "id": "main_inbound1_01" + }, + { + "id": "main_inbound1_02", + "main_inbound1_to_main_fk_col": "main_01" + }, + { + "id": "main_inbound1_03", + "main_inbound1_to_main_fk_col": "main_01" + }, + { + "id": "main_inbound1_04", + "main_inbound1_to_main_fk_col": "main_01" + }, + { + "id": "main_inbound1_05", + "main_inbound1_to_main_fk_col": "main_01" + }, + { + "id": "main_inbound1_06", + "main_inbound1_to_main_fk_col": "main_01" + }, + { + "id": "main_inbound1_07", + "main_inbound1_to_main_fk_col": "main_02" + }, + { + "id": "main_inbound1_12", + "main_inbound1_to_main_fk_col": "main_02" + }, + { + "id": "main_inbound1_13", + "main_inbound1_to_main_fk_col": "main_02" + }, + { + "id": "main_inbound1_14", + "main_inbound1_to_main_fk_col": "main_02" + }, + { + "id": "main_inbound1_15", + "main_inbound1_to_main_fk_col": "main_03" + }, + { + "id": "main_inbound1_16", + "main_inbound1_to_main_fk_col": "main_03" + }, + { + "id": "main_inbound1_17", + "main_inbound1_to_main_fk_col": "main_03" + }, + { + "id": "main_inbound1_18", + "main_inbound1_to_main_fk_col": "main_04" + }, + { + "id": "main_inbound1_19", + "main_inbound1_to_main_fk_col": "main_04" + }, + { + "id": "main_inbound1_20", + "main_inbound1_to_main_fk_col": "main_05" + } +] diff --git a/test/e2e/data_setup/data/facet-within-facet/main_inbound1_inbound1.json b/test/e2e/data_setup/data/facet-within-facet/main_inbound1_inbound1.json new file mode 100644 index 000000000..e20a2bf8b --- /dev/null +++ b/test/e2e/data_setup/data/facet-within-facet/main_inbound1_inbound1.json @@ -0,0 +1,76 @@ +[ + { + "id": "main_inbound1_inbound1_01", + "main_inbound1_inbound1_to_main_inbound1_fk_col": "main_inbound1_01", + "facet_col": "one main_inbound1_inbound1", + "timestamptz_col": "2001-01-01T01:01:01-07:00" + }, + { + "id": "main_inbound1_inbound1_02", + "main_inbound1_inbound1_to_main_inbound1_fk_col": "main_inbound1_01", + "facet_col": "two main_inbound1_inbound1", + "timestamptz_col": "2001-01-01T01:01:01-07:00" + }, + { + "id": "main_inbound1_inbound1_03", + "main_inbound1_inbound1_to_main_inbound1_fk_col": "main_inbound1_02", + "facet_col": "three main_inbound1_inbound1", + "timestamptz_col": "2002-02-02T02:02:02-07:00" + }, + { + "id": "main_inbound1_inbound1_04", + "main_inbound1_inbound1_to_main_inbound1_fk_col": "main_inbound1_02", + "facet_col": "four main_inbound1_inbound1", + "timestamptz_col": "2002-02-02T02:02:02-07:00" + }, + { + "id": "main_inbound1_inbound1_05", + "main_inbound1_inbound1_to_main_inbound1_fk_col": "main_inbound1_03", + "facet_col": "five main_inbound1_inbound1", + "timestamptz_col": "2003-03-03T03:03:03-07:00" + }, + { + "id": "main_inbound1_inbound1_06", + "main_inbound1_inbound1_to_main_inbound1_fk_col": "main_inbound1_03", + "facet_col": "six main_inbound1_inbound1", + "timestamptz_col": "2003-03-03T03:03:03-07:00" + }, + { + "id": "main_inbound1_inbound1_07", + "main_inbound1_inbound1_to_main_inbound1_fk_col": "main_inbound1_04", + "facet_col": "seven main_inbound1_inbound1", + "timestamptz_col": "2004-04-04T04:04:04-07:00" + }, + { + "id": "main_inbound1_inbound1_08", + "main_inbound1_inbound1_to_main_inbound1_fk_col": "main_inbound1_04", + "facet_col": "eight main_inbound1_inbound1", + "timestamptz_col": "2004-04-04T04:04:04-07:00" + }, + { + "id": "main_inbound1_inbound1_09", + "main_inbound1_inbound1_to_main_inbound1_fk_col": "main_inbound1_05", + "facet_col": "nine main_inbound1_inbound1", + "timestamptz_col": "2005-05-05T05:05:05-07:00" + }, + { + "id": "main_inbound1_inbound1_10", + "main_inbound1_inbound1_to_main_inbound1_fk_col": "main_inbound1_05", + "facet_col": "ten main_inbound1_inbound1", + "timestamptz_col": "2006-06-06T06:06:06-07:00" + }, + { + "id": "main_inbound1_inbound1_11", + "main_inbound1_inbound1_to_main_inbound1_fk_col": "main_inbound1_06", + "facet_col": "eleven main_inbound1_inbound1", + "timestamptz_col": "2006-06-06T06:06:06-07:00" + }, + { + "id": "main_inbound1_inbound1_12", + "main_inbound1_inbound1_to_main_inbound1_fk_col": "main_inbound1_07", + "facet_col": "twelve main_inbound1_inbound1", + "timestamptz_col": "2007-07-07T07:07:07-07:00" + } + + +] diff --git a/test/e2e/data_setup/data/facet-within-facet/main_inbound1_inbound2.json b/test/e2e/data_setup/data/facet-within-facet/main_inbound1_inbound2.json new file mode 100644 index 000000000..b28bf8fdf --- /dev/null +++ b/test/e2e/data_setup/data/facet-within-facet/main_inbound1_inbound2.json @@ -0,0 +1,64 @@ +[ + { + "id": "main_inbound1_inbound2_01", + "main_inbound1_inbound2_to_main_inbound1_fk_col": "main_inbound1_01", + "facet_col": "one main_inbound1_inbound2" + }, + { + "id": "main_inbound1_inbound2_02", + "main_inbound1_inbound2_to_main_inbound1_fk_col": "main_inbound1_01", + "facet_col": "two main_inbound1_inbound2" + }, + { + "id": "main_inbound1_inbound2_03", + "main_inbound1_inbound2_to_main_inbound1_fk_col": "main_inbound1_01", + "facet_col": "three main_inbound1_inbound2" + }, + { + "id": "main_inbound1_inbound2_04", + "main_inbound1_inbound2_to_main_inbound1_fk_col": "main_inbound1_01", + "facet_col": "four main_inbound1_inbound2" + }, + { + "id": "main_inbound1_inbound2_05", + "main_inbound1_inbound2_to_main_inbound1_fk_col": "main_inbound1_02", + "facet_col": "five main_inbound1_inbound2" + }, + { + "id": "main_inbound1_inbound2_06", + "main_inbound1_inbound2_to_main_inbound1_fk_col": "main_inbound1_02", + "facet_col": "six main_inbound1_inbound2" + }, + { + "id": "main_inbound1_inbound2_07", + "main_inbound1_inbound2_to_main_inbound1_fk_col": "main_inbound1_02", + "facet_col": "seven main_inbound1_inbound2" + }, + { + "id": "main_inbound1_inbound2_08", + "main_inbound1_inbound2_to_main_inbound1_fk_col": "main_inbound1_03", + "facet_col": "eight main_inbound1_inbound2" + }, + { + "id": "main_inbound1_inbound2_09", + "main_inbound1_inbound2_to_main_inbound1_fk_col": "main_inbound1_03", + "facet_col": "nine main_inbound1_inbound2" + }, + { + "id": "main_inbound1_inbound2_10", + "main_inbound1_inbound2_to_main_inbound1_fk_col": "main_inbound1_04", + "facet_col": "ten main_inbound1_inbound2" + }, + { + "id": "main_inbound1_inbound2_11", + "main_inbound1_inbound2_to_main_inbound1_fk_col": "main_inbound1_04", + "facet_col": "eleven main_inbound1_inbound2" + }, + { + "id": "main_inbound1_inbound2_12", + "main_inbound1_inbound2_to_main_inbound1_fk_col": "main_inbound1_05", + "facet_col": "twelve main_inbound1_inbound2" + } + + +] diff --git a/test/e2e/data_setup/data/facet-within-facet/main_inbound2.json b/test/e2e/data_setup/data/facet-within-facet/main_inbound2.json new file mode 100644 index 000000000..9f73faff7 --- /dev/null +++ b/test/e2e/data_setup/data/facet-within-facet/main_inbound2.json @@ -0,0 +1,80 @@ +[ + { + "id": "main_inbound2_01" + }, + { + "id": "main_inbound2_02", + "main_inbound2_to_main_fk_col": "main_01", + "main_inbound2_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_01" + }, + { + "id": "main_inbound2_03", + "main_inbound2_to_main_fk_col": "main_01", + "main_inbound2_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_01" + }, + { + "id": "main_inbound2_04", + "main_inbound2_to_main_fk_col": "main_01", + "main_inbound2_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_01" + }, + { + "id": "main_inbound2_05", + "main_inbound2_to_main_fk_col": "main_01", + "main_inbound2_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_02" + }, + { + "id": "main_inbound2_06", + "main_inbound2_to_main_fk_col": "main_01", + "main_inbound2_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_02" + }, + { + "id": "main_inbound2_07", + "main_inbound2_to_main_fk_col": "main_02", + "main_inbound2_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_03" + }, + { + "id": "main_inbound2_12", + "main_inbound2_to_main_fk_col": "main_02", + "main_inbound2_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_03" + }, + { + "id": "main_inbound2_13", + "main_inbound2_to_main_fk_col": "main_02", + "main_inbound2_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_04" + }, + { + "id": "main_inbound2_14", + "main_inbound2_to_main_fk_col": "main_02", + "main_inbound2_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_04" + }, + { + "id": "main_inbound2_15", + "main_inbound2_to_main_fk_col": "main_03", + "main_inbound2_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_05" + }, + { + "id": "main_inbound2_16", + "main_inbound2_to_main_fk_col": "main_03", + "main_inbound2_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_06" + }, + { + "id": "main_inbound2_17", + "main_inbound2_to_main_fk_col": "main_03", + "main_inbound2_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_07" + }, + { + "id": "main_inbound2_18", + "main_inbound2_to_main_fk_col": "main_04", + "main_inbound2_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_08" + }, + { + "id": "main_inbound2_19", + "main_inbound2_to_main_fk_col": "main_04", + "main_inbound2_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_09" + }, + { + "id": "main_inbound2_20", + "main_inbound2_to_main_fk_col": "main_05", + "main_inbound2_to_main_inbound2_outbound1_fk_col": "main_inbound2_outbound1_10" + } +] diff --git a/test/e2e/data_setup/data/facet-within-facet/main_inbound2_inbound1.json b/test/e2e/data_setup/data/facet-within-facet/main_inbound2_inbound1.json new file mode 100644 index 000000000..85edec7e3 --- /dev/null +++ b/test/e2e/data_setup/data/facet-within-facet/main_inbound2_inbound1.json @@ -0,0 +1,64 @@ +[ + { + "id": "main_inbound2_inbound1_01", + "main_inbound2_inbound1_to_main_inbound2_fk_col": "main_inbound2_01", + "facet_col": "one main_inbound2_inbound1" + }, + { + "id": "main_inbound2_inbound1_02", + "main_inbound2_inbound1_to_main_inbound2_fk_col": "main_inbound2_01", + "facet_col": "two main_inbound2_inbound1" + }, + { + "id": "main_inbound2_inbound1_03", + "main_inbound2_inbound1_to_main_inbound2_fk_col": "main_inbound2_01", + "facet_col": "three main_inbound2_inbound1" + }, + { + "id": "main_inbound2_inbound1_04", + "main_inbound2_inbound1_to_main_inbound2_fk_col": "main_inbound2_01", + "facet_col": "four main_inbound2_inbound1" + }, + { + "id": "main_inbound2_inbound1_05", + "main_inbound2_inbound1_to_main_inbound2_fk_col": "main_inbound2_02", + "facet_col": "five main_inbound2_inbound1" + }, + { + "id": "main_inbound2_inbound1_06", + "main_inbound2_inbound1_to_main_inbound2_fk_col": "main_inbound2_02", + "facet_col": "six main_inbound2_inbound1" + }, + { + "id": "main_inbound2_inbound1_07", + "main_inbound2_inbound1_to_main_inbound2_fk_col": "main_inbound2_02", + "facet_col": "seven main_inbound2_inbound1" + }, + { + "id": "main_inbound2_inbound1_08", + "main_inbound2_inbound1_to_main_inbound2_fk_col": "main_inbound2_03", + "facet_col": "eight main_inbound2_inbound1" + }, + { + "id": "main_inbound2_inbound1_09", + "main_inbound2_inbound1_to_main_inbound2_fk_col": "main_inbound2_03", + "facet_col": "nine main_inbound2_inbound1" + }, + { + "id": "main_inbound2_inbound1_10", + "main_inbound2_inbound1_to_main_inbound2_fk_col": "main_inbound2_04", + "facet_col": "ten main_inbound2_inbound1" + }, + { + "id": "main_inbound2_inbound1_11", + "main_inbound2_inbound1_to_main_inbound2_fk_col": "main_inbound2_04", + "facet_col": "eleven main_inbound2_inbound1" + }, + { + "id": "main_inbound2_inbound1_12", + "main_inbound2_inbound1_to_main_inbound2_fk_col": "main_inbound2_05", + "facet_col": "twelve main_inbound2_inbound1" + } + + +] diff --git a/test/e2e/data_setup/data/facet-within-facet/main_inbound2_outbound1.json b/test/e2e/data_setup/data/facet-within-facet/main_inbound2_outbound1.json new file mode 100644 index 000000000..2e7158b77 --- /dev/null +++ b/test/e2e/data_setup/data/facet-within-facet/main_inbound2_outbound1.json @@ -0,0 +1,52 @@ +[ + { + "id": "main_inbound2_outbound1_01", + "facet_col": "one main_inbound2_outbound1" + }, + { + "id": "main_inbound2_outbound1_02", + "facet_col": "two main_inbound2_outbound1" + }, + { + "id": "main_inbound2_outbound1_03", + "facet_col": "three main_inbound2_outbound1" + }, + { + "id": "main_inbound2_outbound1_04", + "facet_col": "four main_inbound2_outbound1" + }, + { + "id": "main_inbound2_outbound1_05", + "facet_col": "five main_inbound2_outbound1" + }, + { + "id": "main_inbound2_outbound1_06", + "facet_col": "six main_inbound2_outbound1" + }, + { + "id": "main_inbound2_outbound1_07", + "facet_col": "seven main_inbound2_outbound1" + }, + { + "id": "main_inbound2_outbound1_08", + "facet_col": "eight main_inbound2_outbound1" + }, + { + "id": "main_inbound2_outbound1_09", + "facet_col": "nine main_inbound2_outbound1" + }, + { + "id": "main_inbound2_outbound1_10", + "facet_col": "ten main_inbound2_outbound1" + }, + { + "id": "main_inbound2_outbound1_11", + "facet_col": "eleven main_inbound2_outbound1" + }, + { + "id": "main_inbound2_outbound1_12", + "facet_col": "twelve main_inbound2_outbound1" + } + + +] diff --git a/test/e2e/data_setup/data/facet-within-facet/main_inbound3.json b/test/e2e/data_setup/data/facet-within-facet/main_inbound3.json new file mode 100644 index 000000000..7fcaea719 --- /dev/null +++ b/test/e2e/data_setup/data/facet-within-facet/main_inbound3.json @@ -0,0 +1,65 @@ +[ + { + "id": "main_inbound3_01" + }, + { + "id": "main_inbound3_02", + "main_inbound3_to_main_fk_col": "main_01" + }, + { + "id": "main_inbound3_03", + "main_inbound3_to_main_fk_col": "main_01" + }, + { + "id": "main_inbound3_04", + "main_inbound3_to_main_fk_col": "main_01" + }, + { + "id": "main_inbound3_05", + "main_inbound3_to_main_fk_col": "main_01" + }, + { + "id": "main_inbound3_06", + "main_inbound3_to_main_fk_col": "main_01" + }, + { + "id": "main_inbound3_07", + "main_inbound3_to_main_fk_col": "main_02" + }, + { + "id": "main_inbound3_12", + "main_inbound3_to_main_fk_col": "main_02" + }, + { + "id": "main_inbound3_13", + "main_inbound3_to_main_fk_col": "main_02" + }, + { + "id": "main_inbound3_14", + "main_inbound3_to_main_fk_col": "main_02" + }, + { + "id": "main_inbound3_15", + "main_inbound3_to_main_fk_col": "main_03" + }, + { + "id": "main_inbound3_16", + "main_inbound3_to_main_fk_col": "main_03" + }, + { + "id": "main_inbound3_17", + "main_inbound3_to_main_fk_col": "main_03" + }, + { + "id": "main_inbound3_18", + "main_inbound3_to_main_fk_col": "main_04" + }, + { + "id": "main_inbound3_19", + "main_inbound3_to_main_fk_col": "main_04" + }, + { + "id": "main_inbound3_20", + "main_inbound3_to_main_fk_col": "main_05" + } +] diff --git a/test/e2e/data_setup/data/facet-within-facet/main_inbound3_inbound1.json b/test/e2e/data_setup/data/facet-within-facet/main_inbound3_inbound1.json new file mode 100644 index 000000000..bf35da8a8 --- /dev/null +++ b/test/e2e/data_setup/data/facet-within-facet/main_inbound3_inbound1.json @@ -0,0 +1,64 @@ +[ + { + "id": "main_inbound3_inbound1_01", + "main_inbound3_inbound1_to_main_inbound3_fk_col": "main_inbound3_01", + "facet_col": "one main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_02", + "main_inbound3_inbound1_to_main_inbound3_fk_col": "main_inbound3_01", + "facet_col": "two main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_03", + "main_inbound3_inbound1_to_main_inbound3_fk_col": "main_inbound3_01", + "facet_col": "three main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_04", + "main_inbound3_inbound1_to_main_inbound3_fk_col": "main_inbound3_01", + "facet_col": "four main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_05", + "main_inbound3_inbound1_to_main_inbound3_fk_col": "main_inbound3_02", + "facet_col": "five main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_06", + "main_inbound3_inbound1_to_main_inbound3_fk_col": "main_inbound3_02", + "facet_col": "six main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_07", + "main_inbound3_inbound1_to_main_inbound3_fk_col": "main_inbound3_02", + "facet_col": "seven main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_08", + "main_inbound3_inbound1_to_main_inbound3_fk_col": "main_inbound3_03", + "facet_col": "eight main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_09", + "main_inbound3_inbound1_to_main_inbound3_fk_col": "main_inbound3_03", + "facet_col": "nine main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_10", + "main_inbound3_inbound1_to_main_inbound3_fk_col": "main_inbound3_04", + "facet_col": "ten main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_11", + "main_inbound3_inbound1_to_main_inbound3_fk_col": "main_inbound3_04", + "facet_col": "eleven main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_12", + "main_inbound3_inbound1_to_main_inbound3_fk_col": "main_inbound3_05", + "facet_col": "twelve main_inbound3_inbound1" + } + + +] diff --git a/test/e2e/data_setup/data/facet-within-facet/main_inbound3_inbound1_fast_filter.json b/test/e2e/data_setup/data/facet-within-facet/main_inbound3_inbound1_fast_filter.json new file mode 100644 index 000000000..649e0e416 --- /dev/null +++ b/test/e2e/data_setup/data/facet-within-facet/main_inbound3_inbound1_fast_filter.json @@ -0,0 +1,64 @@ +[ + { + "id": "main_inbound3_inbound1_01", + "main_inbound3_inbound1_fast_filter_to_main_inbound3_fk_col": "main_inbound3_01", + "facet_col": "one main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_02", + "main_inbound3_inbound1_fast_filter_to_main_inbound3_fk_col": "main_inbound3_01", + "facet_col": "two main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_03", + "main_inbound3_inbound1_fast_filter_to_main_inbound3_fk_col": "main_inbound3_01", + "facet_col": "three main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_04", + "main_inbound3_inbound1_fast_filter_to_main_inbound3_fk_col": "main_inbound3_01", + "facet_col": "four main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_05", + "main_inbound3_inbound1_fast_filter_to_main_inbound3_fk_col": "main_inbound3_02", + "facet_col": "five main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_06", + "main_inbound3_inbound1_fast_filter_to_main_inbound3_fk_col": "main_inbound3_02", + "facet_col": "six main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_07", + "main_inbound3_inbound1_fast_filter_to_main_inbound3_fk_col": "main_inbound3_02", + "facet_col": "seven main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_08", + "main_inbound3_inbound1_fast_filter_to_main_inbound3_fk_col": "main_inbound3_03", + "facet_col": "eight main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_09", + "main_inbound3_inbound1_fast_filter_to_main_inbound3_fk_col": "main_inbound3_03", + "facet_col": "nine main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_10", + "main_inbound3_inbound1_fast_filter_to_main_inbound3_fk_col": "main_inbound3_04", + "facet_col": "ten main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_11", + "main_inbound3_inbound1_fast_filter_to_main_inbound3_fk_col": "main_inbound3_04", + "facet_col": "eleven main_inbound3_inbound1" + }, + { + "id": "main_inbound3_inbound1_12", + "main_inbound3_inbound1_fast_filter_to_main_inbound3_fk_col": "main_inbound3_05", + "facet_col": "twelve main_inbound3_inbound1" + } + + +] diff --git a/test/e2e/data_setup/data/facet-within-facet/record_main.json b/test/e2e/data_setup/data/facet-within-facet/record_main.json new file mode 100644 index 000000000..bc4b26aa7 --- /dev/null +++ b/test/e2e/data_setup/data/facet-within-facet/record_main.json @@ -0,0 +1 @@ +[{"id": "record_main_01"}] diff --git a/test/e2e/data_setup/data/facet-within-facet/record_main_assoc.json b/test/e2e/data_setup/data/facet-within-facet/record_main_assoc.json new file mode 100644 index 000000000..1e24b3447 --- /dev/null +++ b/test/e2e/data_setup/data/facet-within-facet/record_main_assoc.json @@ -0,0 +1,3 @@ +[ + {"fk_to_main": "main_01", "fk_to_record_main": "record_main_01"} +] diff --git a/test/e2e/data_setup/schema/recordset/active-list.json b/test/e2e/data_setup/schema/recordset/active-list.json index c986b6a2b..b21ce413b 100644 --- a/test/e2e/data_setup/schema/recordset/active-list.json +++ b/test/e2e/data_setup/schema/recordset/active-list.json @@ -548,6 +548,9 @@ "tag:misd.isi.edu,2015:display" : { "hide_row_count": { "*": true + }, + "max_facet_depth": { + "*": 1 } } } diff --git a/test/e2e/data_setup/schema/recordset/facet-within-facet.json b/test/e2e/data_setup/schema/recordset/facet-within-facet.json new file mode 100644 index 000000000..f2885b2a2 --- /dev/null +++ b/test/e2e/data_setup/schema/recordset/facet-within-facet.json @@ -0,0 +1,1526 @@ +{ + "schema_name": "facet-within-facet", + "tables": { + "main": { + "kind": "table", + "schema_name": "facet-within-facet", + "table_name": "main", + "comment": "the main table that will be used for testing the facet within facet", + "keys": [ + { + "unique_columns": [ + "id" + ] + } + ], + "column_definitions": [ + { + "name": "id", + "nullok": false, + "type": { + "typename": "text" + } + } + ], + "annotations": { + "tag:isrd.isi.edu,2021:table-config": { + "aggressive_facet_lookup": true + }, + "tag:isrd.isi.edu,2019:source-definitions": { + "fkeys": true, + "columns": true, + "sources": { + "path_to_main_inbound2": { + "source": [{"inbound": [ "facet-within-facet","main_inbound2_to_main_fk" ]}, "RID"] + } + } + }, + "tag:isrd.isi.edu,2016:visible-columns": { + "*": ["id"], + "filter": { + "and": [ + { + "markdown_name": "Entity path", + "source": [ + {"inbound": [ "facet-within-facet","main_inbound1_to_main_fk" ]}, + {"inbound": [ "facet-within-facet","main_inbound1_inbound1_to_main_inbound1_fk" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "Entity path 2", + "source": [ + {"inbound": [ "facet-within-facet","main_inbound1_to_main_fk" ]}, + {"inbound": [ "facet-within-facet","main_inbound1_inbound2_to_main_inbound1_fk" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "Entity path with filter", + "source": [ + {"inbound": [ "facet-within-facet","main_inbound1_to_main_fk" ]}, + { + "and": [ + {"filter": "RID", "operand_pattern": "::null::"}, + {"filter": "RCB", "operand_pattern": "::null::"} + ], + "negate": true + }, + {"inbound": [ "facet-within-facet","main_inbound1_inbound1_to_main_inbound1_fk" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "Entity path with shared prefix", + "source": [ + {"sourcekey": "path_to_main_inbound2"}, + {"inbound": [ "facet-within-facet","main_inbound2_inbound1_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "Entity path with shared prefix and filter", + "source": [ + {"sourcekey": "path_to_main_inbound2"}, + { + "or": [ + {"operator": "::null::", "filter": "id"}, + {"operator": "::null::", "filter": "RMB"} + ], + "negate": true + }, + {"outbound": [ "facet-within-facet","main_inbound2_to_main_inbound2_outbound1_fk" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "Entity path with fast filter", + "source": [ + {"inbound": [ "facet-within-facet","main_inbound3_fk1" ]}, + {"inbound": [ "facet-within-facet","main_inbound3_inbound1_fk1" ]}, + "id" + ], + "fast_filter_source": [ + {"inbound": [ "facet-within-facet","main_inbound3_fk1" ]}, + {"inbound": [ "facet-within-facet","main_inbound3_inbound1_fast_filter_fk1" ]}, + "id" + ], + "open": true + } + ] + } + } + } + }, + "recordedit_main": { + "kind": "table", + "schema_name": "facet-within-facet", + "table_name": "recordedit_main", + "comment": "has an outbound fk to main table. used for testing the fk popup", + "keys": [{ "unique_columns": ["id"]}], + "foreign_keys": [ + { + "names": [[ "facet-within-facet","recordedit_main_fk1" ]], + "foreign_key_columns": [{ + "column_name": "fk_col", + "table_name": "recordedit_main", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "main", + "schema_name": "facet-within-facet" + }] + } + ], + "column_definitions": [ + { + "name": "id", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "fk_col", + "type": { + "typename": "text" + } + } + ], + "annotations": { + "tag:isrd.isi.edu,2016:visible-columns": { + "entry": [ + "id", + { + "markdown_name": "fk_to_main", + "source": [{"outbound": [ "facet-within-facet","recordedit_main_fk1" ]}, "RID"] + } + ] + } + } + }, + "record_main": { + "kind": "table", + "schema_name": "facet-within-facet", + "table_name": "record_main", + "comment": "has a p&b association to main table. used for testing the p&b popup", + "keys": [{ "unique_columns": ["id"]}], + "column_definitions": [ + { + "name": "id", + "nullok": false, + "type": { + "typename": "text" + } + } + ], + "annotations": { + "tag:isrd.isi.edu,2016:visible-columns": { + "detailed": [ + "id", + { + "markdown_name": "main association", + "source": [ + {"inbound": [ "facet-within-facet","record_main_assoc_fk1" ]}, + {"outbound": [ "facet-within-facet","record_main_assoc_fk2" ]}, + "RID" + ] + } + ] + } + } + }, + "record_main_assoc": { + "kind": "table", + "schema_name": "facet-within-facet", + "table_name": "record_main_assoc", + "comment": "the p&b association between main and record_main", + "keys": [{ "unique_columns": ["fk_to_main", "fk_to_record_main"]}], + "foreign_keys": [ + { + "names": [[ "facet-within-facet","record_main_assoc_fk1" ]], + "foreign_key_columns": [{ + "column_name": "fk_to_record_main", + "table_name": "record_main_assoc", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "record_main", + "schema_name": "facet-within-facet" + }] + }, + { + "names": [[ "facet-within-facet","record_main_assoc_fk2" ]], + "foreign_key_columns": [{ + "column_name": "fk_to_main", + "table_name": "record_main_assoc", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "main", + "schema_name": "facet-within-facet" + }] + } + ], + "column_definitions": [ + { + "name": "fk_to_main", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "fk_to_record_main", + "nullok": false, + "type": { + "typename": "text" + } + } + ] + }, + "main_inbound1": { + "comment": "has inbound fk to main. ", + "kind": "table", + "schema_name": "facet-within-facet", + "table_name": "main_inbound1", + "keys": [{ "unique_columns": ["id"]}], + "foreign_keys": [ + { + "names": [[ "facet-within-facet","main_inbound1_to_main_fk" ]], + "foreign_key_columns": [{ + "column_name": "main_inbound1_to_main_fk_col", + "table_name": "main_inbound1", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "main", + "schema_name": "facet-within-facet" + }] + } + ], + "column_definitions": [ + { + "name": "id", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "main_inbound1_to_main_fk_col", + "type": { + "typename": "text" + } + } + ] + }, + "main_inbound1_inbound1": { + "comment": "has inbound fk to main_inbound1", + "kind": "table", + "table_name": "main_inbound1_inbound1", + "schema_name": "facet-within-facet", + "keys": [{ "unique_columns": ["id"]}], + "foreign_keys": [ + { + "names": [[ "facet-within-facet","main_inbound1_inbound1_to_main_inbound1_fk" ]], + "foreign_key_columns": [{ + "column_name": "main_inbound1_inbound1_to_main_inbound1_fk_col", + "table_name": "main_inbound1_inbound1", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "main_inbound1", + "schema_name": "facet-within-facet" + }] + } + ], + "column_definitions": [ + { + "name": "id", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "main_inbound1_inbound1_to_main_inbound1_fk_col", + "type": { + "typename": "text" + } + }, + { + "name": "facet_col", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "timestamptz_col", + "type": { + "typename": "timestamptz" + } + } + ], + "annotations": { + "tag:isrd.isi.edu,2021:table-config": { + "aggressive_facet_lookup": true + }, + "tag:isrd.isi.edu,2019:source-definitions": { + "fkeys": true, + "columns": true, + "sources": { + "path_to_2nd_layer_hub": { + "source": [{"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound1_inbound1" ]}, "RID"] + } + } + }, + "tag:isrd.isi.edu,2016:visible-columns": { + "*": ["id", "facet_col"], + "filter": { + "and": [ + { + "markdown_name": "2nd layer entity path", + "source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound1_inbound1" ]}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound1_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path 2", + "source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound1_inbound1" ]}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound2_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path with filter", + "source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound1_inbound1" ]}, + { + "and": [ + {"filter": "RID", "operand_pattern": "::null::"}, + {"filter": "RCB", "operand_pattern": "::null::"} + ], + "negate": true + }, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound1_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path with shared prefix", + "source": [ + {"sourcekey": "path_to_2nd_layer_hub"}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound3_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path with shared prefix and filter", + "source": [ + {"sourcekey": "path_to_2nd_layer_hub"}, + { + "or": [ + {"operator": "::null::", "filter": "id"}, + {"operator": "::null::", "filter": "RMB"} + ], + "negate": true + }, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound4_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path with fast filter", + "source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound1_inbound1" ]}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound5_fk1" ]}, + "id" + ], + "fast_filter_source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound1_inbound1" ]}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound5_fast_filter_fk1" ]}, + "id" + ], + "open": true + }, + { + "markdown_name": "2nd layer timestamptz", + "source": "timestamptz_col", + "open": true + } + ] + } + } + } + }, + "main_inbound1_inbound2": { + "comment": "has inbound fk to main_inbound1", + "kind": "table", + "table_name": "main_inbound1_inbound2", + "schema_name": "facet-within-facet", + "keys": [{ "unique_columns": ["id"]}], + "foreign_keys": [ + { + "names": [[ "facet-within-facet","main_inbound1_inbound2_to_main_inbound1_fk" ]], + "foreign_key_columns": [{ + "column_name": "main_inbound1_inbound2_to_main_inbound1_fk_col", + "table_name": "main_inbound1_inbound2", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "main_inbound1", + "schema_name": "facet-within-facet" + }] + } + ], + "column_definitions": [ + { + "name": "id", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "main_inbound1_inbound2_to_main_inbound1_fk_col", + "type": { + "typename": "text" + } + }, + { + "name": "facet_col", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "timestamptz_col", + "type": { + "typename": "timestamptz" + } + } + ], + "annotations": { + "tag:isrd.isi.edu,2019:source-definitions": { + "fkeys": true, + "columns": true, + "sources": { + "path_to_2nd_layer_hub": { + "source": [{"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound1_inbound2" ]}, "RID"] + } + } + }, + "tag:isrd.isi.edu,2016:visible-columns": { + "*": ["id", "facet_col"], + "filter": { + "and": [ + { + "markdown_name": "2nd layer entity path", + "source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound1_inbound2" ]}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound1_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path 2", + "source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound1_inbound2" ]}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound2_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path with filter", + "source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound1_inbound2" ]}, + { + "and": [ + {"filter": "RID", "operand_pattern": "::null::"}, + {"filter": "RCB", "operand_pattern": "::null::"} + ], + "negate": true + }, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound1_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path with shared prefix", + "source": [ + {"sourcekey": "path_to_2nd_layer_hub"}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound3_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path with shared prefix and filter", + "source": [ + {"sourcekey": "path_to_2nd_layer_hub"}, + { + "or": [ + {"operator": "::null::", "filter": "id"}, + {"operator": "::null::", "filter": "RMB"} + ], + "negate": true + }, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound4_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path with fast filter", + "source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound1_inbound2" ]}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound5_fk1" ]}, + "id" + ], + "fast_filter_source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound1_inbound2" ]}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound5_fast_filter_fk1" ]}, + "id" + ], + "open": true + }, + { + "markdown_name": "2nd layer timestamptz", + "source": "timestamptz_col", + "open": true + } + ] + } + } + } + }, + "main_inbound2": { + "comment": "has inbound fk to main.", + "kind": "table", + "schema_name": "facet-within-facet", + "table_name": "main_inbound2", + "keys": [{ "unique_columns": ["id"]}], + "foreign_keys": [ + { + "names": [[ "facet-within-facet","main_inbound2_to_main_fk" ]], + "foreign_key_columns": [{ + "column_name": "main_inbound2_to_main_fk_col", + "table_name": "main_inbound2", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "main", + "schema_name": "facet-within-facet" + }] + }, + { + "names": [[ "facet-within-facet","main_inbound2_to_main_inbound2_outbound1_fk" ]], + "foreign_key_columns": [{ + "column_name": "main_inbound2_to_main_inbound2_outbound1_fk_col", + "table_name": "main_inbound2", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "main_inbound2_outbound1", + "schema_name": "facet-within-facet" + }] + } + ], + "column_definitions": [ + { + "name": "id", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "main_inbound2_to_main_fk_col", + "type": { + "typename": "text" + } + }, + { + "name": "main_inbound2_to_main_inbound2_outbound1_fk_col", + "type": { + "typename": "text" + } + } + ] + }, + "main_inbound2_inbound1": { + "comment": "has inbound fk to main_inbound2", + "kind": "table", + "table_name": "main_inbound2_inbound1", + "schema_name": "facet-within-facet", + "keys": [{ "unique_columns": ["id"]}], + "foreign_keys": [ + { + "names": [[ "facet-within-facet","main_inbound2_inbound1_fk1" ]], + "foreign_key_columns": [{ + "column_name": "main_inbound2_inbound1_to_main_inbound2_fk_col", + "table_name": "main_inbound2_inbound1", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "main_inbound2", + "schema_name": "facet-within-facet" + }] + } + ], + "column_definitions": [ + { + "name": "id", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "main_inbound2_inbound1_to_main_inbound2_fk_col", + "type": { + "typename": "text" + } + }, + { + "name": "facet_col", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "timestamptz_col", + "type": { + "typename": "timestamptz" + } + } + ], + "annotations": { + "tag:isrd.isi.edu,2019:source-definitions": { + "fkeys": true, + "columns": true, + "sources": { + "path_to_2nd_layer_hub": { + "source": [{"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound2_inbound1" ]}, "RID"] + } + } + }, + "tag:isrd.isi.edu,2016:visible-columns": { + "*": ["id", "facet_col"], + "filter": { + "and": [ + { + "markdown_name": "2nd layer entity path", + "source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound2_inbound1" ]}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound1_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path 2", + "source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound2_inbound1" ]}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound2_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path with filter", + "source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound2_inbound1" ]}, + { + "and": [ + {"filter": "RID", "operand_pattern": "::null::"}, + {"filter": "RCB", "operand_pattern": "::null::"} + ], + "negate": true + }, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound1_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path with shared prefix", + "source": [ + {"sourcekey": "path_to_2nd_layer_hub"}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound3_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path with shared prefix and filter", + "source": [ + {"sourcekey": "path_to_2nd_layer_hub"}, + { + "or": [ + {"operator": "::null::", "filter": "id"}, + {"operator": "::null::", "filter": "RMB"} + ], + "negate": true + }, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound4_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path with fast filter", + "source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound2_inbound1" ]}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound5_fk1" ]}, + "id" + ], + "fast_filter_source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound2_inbound1" ]}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound5_fast_filter_fk1" ]}, + "id" + ], + "open": true + }, + { + "markdown_name": "2nd layer timestamptz", + "source": "timestamptz_col", + "open": true + } + ] + } + } + } + }, + "main_inbound2_outbound1": { + "comment": "has inbound fk to main_inbound2", + "kind": "table", + "table_name": "main_inbound2_outbound1", + "schema_name": "facet-within-facet", + "keys": [{ "unique_columns": ["id"]}], + "column_definitions": [ + { + "name": "id", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "facet_col", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "timestamptz_col", + "type": { + "typename": "timestamptz" + } + } + ], + "annotations": { + "tag:isrd.isi.edu,2019:source-definitions": { + "fkeys": true, + "columns": true, + "sources": { + "path_to_2nd_layer_hub": { + "source": [{"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound2_outbound1" ]}, "RID"] + } + } + }, + "tag:isrd.isi.edu,2016:visible-columns": { + "*": ["id", "facet_col"], + "filter": { + "and": [ + { + "markdown_name": "2nd layer entity path", + "source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound2_outbound1" ]}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound1_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path 2", + "source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound2_outbound1" ]}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound2_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path with filter", + "source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound2_outbound1" ]}, + { + "and": [ + {"filter": "RID", "operand_pattern": "::null::"}, + {"filter": "RCB", "operand_pattern": "::null::"} + ], + "negate": true + }, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound1_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path with shared prefix", + "source": [ + {"sourcekey": "path_to_2nd_layer_hub"}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound3_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path with shared prefix and filter", + "source": [ + {"sourcekey": "path_to_2nd_layer_hub"}, + { + "or": [ + {"operator": "::null::", "filter": "id"}, + {"operator": "::null::", "filter": "RMB"} + ], + "negate": true + }, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound4_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path with fast filter", + "source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound2_outbound1" ]}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound5_fk1" ]}, + "id" + ], + "fast_filter_source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound2_outbound1" ]}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound5_fast_filter_fk1" ]}, + "id" + ], + "open": true + }, + { + "markdown_name": "2nd layer timestamptz", + "source": "timestamptz_col", + "open": true + } + ] + } + } + } + }, + "main_inbound3": { + "comment": "has inbound fk to main.", + "kind": "table", + "schema_name": "facet-within-facet", + "table_name": "main_inbound3", + "keys": [{ "unique_columns": ["id"]}], + "foreign_keys": [ + { + "names": [[ "facet-within-facet","main_inbound3_fk1" ]], + "foreign_key_columns": [{ + "column_name": "main_inbound3_to_main_fk_col", + "table_name": "main_inbound3", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "main", + "schema_name": "facet-within-facet" + }] + } + ], + "column_definitions": [ + { + "name": "id", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "main_inbound3_to_main_fk_col", + "type": { + "typename": "text" + } + } + ] + }, + "main_inbound3_inbound1": { + "comment": "has inbound fk to main_inbound3", + "kind": "table", + "table_name": "main_inbound3_inbound1", + "schema_name": "facet-within-facet", + "keys": [{ "unique_columns": ["id"]}], + "foreign_keys": [ + { + "names": [[ "facet-within-facet","main_inbound3_inbound1_fk1" ]], + "foreign_key_columns": [{ + "column_name": "main_inbound3_inbound1_to_main_inbound3_fk_col", + "table_name": "main_inbound3_inbound1", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "main_inbound3", + "schema_name": "facet-within-facet" + }] + } + ], + "column_definitions": [ + { + "name": "id", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "main_inbound3_inbound1_to_main_inbound3_fk_col", + "type": { + "typename": "text" + } + }, + { + "name": "facet_col", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "timestamptz_col", + "type": { + "typename": "timestamptz" + } + } + ], + "annotations": { + "tag:isrd.isi.edu,2019:source-definitions": { + "fkeys": true, + "columns": true, + "sources": { + "path_to_2nd_layer_hub": { + "source": [{"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound3_inbound1" ]}, "RID"] + } + } + }, + "tag:isrd.isi.edu,2016:visible-columns": { + "*": ["id", "facet_col"], + "filter": { + "and": [ + { + "markdown_name": "2nd layer entity path", + "source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound3_inbound1" ]}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound1_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path 2", + "source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound3_inbound1" ]}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound2_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path with filter", + "source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound3_inbound1" ]}, + { + "and": [ + {"filter": "RID", "operand_pattern": "::null::"}, + {"filter": "RCB", "operand_pattern": "::null::"} + ], + "negate": true + }, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound1_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path with shared prefix", + "source": [ + {"sourcekey": "path_to_2nd_layer_hub"}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound3_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path with shared prefix and filter", + "source": [ + {"sourcekey": "path_to_2nd_layer_hub"}, + { + "or": [ + {"operator": "::null::", "filter": "id"}, + {"operator": "::null::", "filter": "RMB"} + ], + "negate": true + }, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound4_fk1" ]}, + "RID" + ], + "open": true + }, + { + "markdown_name": "2nd layer entity path with fast filter", + "source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound3_inbound1" ]}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound5_fk1" ]}, + "id" + ], + "fast_filter_source": [ + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound3_inbound1" ]}, + {"inbound": [ "facet-within-facet","facet_2nd_layer_hub_inbound5_fast_filter_fk1" ]}, + "id" + ], + "open": true + }, + { + "markdown_name": "2nd layer timestamptz", + "source": "timestamptz_col", + "open": true + } + ] + } + } + } + }, + "main_inbound3_inbound1_fast_filter": { + "comment": "has inbound fk to main_inbound3", + "kind": "table", + "table_name": "main_inbound3_inbound1_fast_filter", + "schema_name": "facet-within-facet", + "keys": [{ "unique_columns": ["id"]}], + "foreign_keys": [ + { + "names": [[ "facet-within-facet","main_inbound3_inbound1_fast_filter_fk1" ]], + "foreign_key_columns": [{ + "column_name": "main_inbound3_inbound1_fast_filter_to_main_inbound3_fk_col", + "table_name": "main_inbound3_inbound1_fast_filter", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "main_inbound3", + "schema_name": "facet-within-facet" + }] + } + ], + "column_definitions": [ + { + "name": "id", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "main_inbound3_inbound1_fast_filter_to_main_inbound3_fk_col", + "type": { + "typename": "text" + } + }, + { + "name": "facet_col", + "nullok": false, + "type": { + "typename": "text" + } + } + ] + }, + "facet_2nd_layer_hub": { + "comment": "has inbound to all the entity paths from the layer below. other tables have inbound to it", + "kind": "table", + "table_name": "facet_2nd_layer_hub", + "schema_name": "facet-within-facet", + "keys": [{ "unique_columns": ["id"]}], + "foreign_keys": [ + { + "comment": "fk to main_inbound1_inbound1", + "names": [[ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound1_inbound1" ]], + "foreign_key_columns": [{ + "column_name": "facet_2nd_layer_hub_to_main_inbound1_inbound1_fk_col", + "table_name": "facet_2nd_layer_hub", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "main_inbound1_inbound1", + "schema_name": "facet-within-facet" + }] + }, + { + "comment": "fk to main_inbound1_inbound2", + "names": [[ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound1_inbound2" ]], + "foreign_key_columns": [{ + "column_name": "facet_2nd_layer_hub_to_main_inbound1_inbound2_fk_col", + "table_name": "facet_2nd_layer_hub", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "main_inbound1_inbound2", + "schema_name": "facet-within-facet" + }] + }, + { + "comment": "fk to main_inbound2_inbound1", + "names": [[ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound2_inbound1" ]], + "foreign_key_columns": [{ + "column_name": "facet_2nd_layer_hub_to_main_inbound2_inbound1_fk_col", + "table_name": "facet_2nd_layer_hub", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "main_inbound2_inbound1", + "schema_name": "facet-within-facet" + }] + }, + { + "comment": "fk to main_inbound2_outbound1", + "names": [[ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound2_outbound1" ]], + "foreign_key_columns": [{ + "column_name": "facet_2nd_layer_hub_to_main_inbound2_outbound1_fk_col", + "table_name": "facet_2nd_layer_hub", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "main_inbound2_outbound1", + "schema_name": "facet-within-facet" + }] + }, + { + "comment": "fk to main_inbound3_inbound1", + "names": [[ "facet-within-facet","facet_2nd_layer_hub_fk_to_main_inbound3_inbound1" ]], + "foreign_key_columns": [{ + "column_name": "facet_2nd_layer_hub_to_main_inbound3_inbound1_fk_col", + "table_name": "facet_2nd_layer_hub", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "main_inbound3_inbound1", + "schema_name": "facet-within-facet" + }] + } + ], + "column_definitions": [ + { + "name": "id", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "facet_2nd_layer_hub_to_main_inbound1_inbound1_fk_col", + "type": { + "typename": "text" + } + }, + { + "name": "facet_2nd_layer_hub_to_main_inbound1_inbound2_fk_col", + "type": { + "typename": "text" + } + }, + { + "name": "facet_2nd_layer_hub_to_main_inbound2_inbound1_fk_col", + "type": { + "typename": "text" + } + }, + { + "name": "facet_2nd_layer_hub_to_main_inbound2_outbound1_fk_col", + "type": { + "typename": "text" + } + }, + { + "name": "facet_2nd_layer_hub_to_main_inbound3_inbound1_fk_col", + "type": { + "typename": "text" + } + } + ] + }, + "facet_2nd_layer_hub_inbound1": { + "comment": "has inbound fk to facet_2nd_layer_hub", + "kind": "table", + "table_name": "facet_2nd_layer_hub_inbound1", + "schema_name": "facet-within-facet", + "keys": [{ "unique_columns": ["id"]}], + "foreign_keys": [ + { + "names": [[ "facet-within-facet","facet_2nd_layer_hub_inbound1_fk1" ]], + "foreign_key_columns": [{ + "column_name": "facet_2nd_layer_hub_inbound1_fk_col", + "table_name": "facet_2nd_layer_hub_inbound1", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "facet_2nd_layer_hub", + "schema_name": "facet-within-facet" + }] + } + ], + "column_definitions": [ + { + "name": "id", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "facet_2nd_layer_hub_inbound1_fk_col", + "type": { + "typename": "text" + } + }, + { + "name": "facet_col", + "nullok": false, + "type": { + "typename": "text" + } + } + ] + }, + "facet_2nd_layer_hub_inbound2": { + "comment": "has inbound fk to facet_2nd_layer_hub", + "kind": "table", + "table_name": "facet_2nd_layer_hub_inbound2", + "schema_name": "facet-within-facet", + "keys": [{ "unique_columns": ["id"]}], + "foreign_keys": [ + { + "names": [[ "facet-within-facet","facet_2nd_layer_hub_inbound2_fk1" ]], + "foreign_key_columns": [{ + "column_name": "facet_2nd_layer_hub_inbound2_fk_col", + "table_name": "facet_2nd_layer_hub_inbound2", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "facet_2nd_layer_hub", + "schema_name": "facet-within-facet" + }] + } + ], + "column_definitions": [ + { + "name": "id", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "facet_2nd_layer_hub_inbound2_fk_col", + "type": { + "typename": "text" + } + }, + { + "name": "facet_col", + "nullok": false, + "type": { + "typename": "text" + } + } + ] + }, + "facet_2nd_layer_hub_inbound3": { + "comment": "has inbound fk to facet_2nd_layer_hub", + "kind": "table", + "table_name": "facet_2nd_layer_hub_inbound3", + "schema_name": "facet-within-facet", + "keys": [{ "unique_columns": ["id"]}], + "foreign_keys": [ + { + "names": [[ "facet-within-facet","facet_2nd_layer_hub_inbound3_fk1" ]], + "foreign_key_columns": [{ + "column_name": "facet_2nd_layer_hub_inbound3_fk_col", + "table_name": "facet_2nd_layer_hub_inbound3", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "facet_2nd_layer_hub", + "schema_name": "facet-within-facet" + }] + } + ], + "column_definitions": [ + { + "name": "id", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "facet_2nd_layer_hub_inbound3_fk_col", + "type": { + "typename": "text" + } + }, + { + "name": "facet_col", + "nullok": false, + "type": { + "typename": "text" + } + } + ] + }, + "facet_2nd_layer_hub_inbound4": { + "comment": "has inbound fk to facet_2nd_layer_hub", + "kind": "table", + "table_name": "facet_2nd_layer_hub_inbound4", + "schema_name": "facet-within-facet", + "keys": [{ "unique_columns": ["id"]}], + "foreign_keys": [ + { + "names": [[ "facet-within-facet","facet_2nd_layer_hub_inbound4_fk1" ]], + "foreign_key_columns": [{ + "column_name": "facet_2nd_layer_hub_inbound4_fk_col", + "table_name": "facet_2nd_layer_hub_inbound4", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "facet_2nd_layer_hub", + "schema_name": "facet-within-facet" + }] + } + ], + "column_definitions": [ + { + "name": "id", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "facet_2nd_layer_hub_inbound4_fk_col", + "type": { + "typename": "text" + } + }, + { + "name": "facet_col", + "nullok": false, + "type": { + "typename": "text" + } + } + ] + }, + "facet_2nd_layer_hub_inbound5": { + "comment": "has inbound fk to facet_2nd_layer_hub", + "kind": "table", + "table_name": "facet_2nd_layer_hub_inbound5", + "schema_name": "facet-within-facet", + "keys": [{ "unique_columns": ["id"]}], + "foreign_keys": [ + { + "names": [[ "facet-within-facet","facet_2nd_layer_hub_inbound5_fk1" ]], + "foreign_key_columns": [{ + "column_name": "facet_2nd_layer_hub_inbound5_fk_col", + "table_name": "facet_2nd_layer_hub_inbound5", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "facet_2nd_layer_hub", + "schema_name": "facet-within-facet" + }] + } + ], + "column_definitions": [ + { + "name": "id", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "facet_2nd_layer_hub_inbound5_fk_col", + "type": { + "typename": "text" + } + }, + { + "name": "facet_col", + "nullok": false, + "type": { + "typename": "text" + } + } + ] + }, + "facet_2nd_layer_hub_inbound5_fast_filter": { + "comment": "has inbound fk to facet_2nd_layer_hub (it should be the same as inbound5)", + "kind": "table", + "table_name": "facet_2nd_layer_hub_inbound5_fast_filter", + "schema_name": "facet-within-facet", + "keys": [{ "unique_columns": ["id"]}], + "foreign_keys": [ + { + "names": [[ "facet-within-facet","facet_2nd_layer_hub_inbound5_fast_filter_fk1" ]], + "foreign_key_columns": [{ + "column_name": "facet_2nd_layer_hub_inbound5_fast_filter_fk_col", + "table_name": "facet_2nd_layer_hub_inbound5_fast_filter", + "schema_name": "facet-within-facet" + }], + "referenced_columns": [{ + "column_name": "id", + "table_name": "facet_2nd_layer_hub", + "schema_name": "facet-within-facet" + }] + } + ], + "column_definitions": [ + { + "name": "id", + "nullok": false, + "type": { + "typename": "text" + } + }, + { + "name": "facet_2nd_layer_hub_inbound5_fast_filter_fk_col", + "type": { + "typename": "text" + } + }, + { + "name": "facet_col", + "nullok": false, + "type": { + "typename": "text" + } + } + ] + } + }, + "annotations": { + "tag:misd.isi.edu,2015:display" : { + "max_facet_depth": { + "*": 2 + } + } + } +} diff --git a/test/e2e/locators/modal.ts b/test/e2e/locators/modal.ts index 356a98d36..40ee715a2 100644 --- a/test/e2e/locators/modal.ts +++ b/test/e2e/locators/modal.ts @@ -24,6 +24,15 @@ export default class ModalLocators { return page.locator('.scalar-show-details-popup'); } + static getFacetPopup(page: Page, depth?: number): Locator { + depth = typeof depth === 'number' ? depth : 1; + return page.locator(`.faceting-show-details-popup-depth-${depth}`); + } + + static getAddPureBinaryPopup(page: Page): Locator { + return page.locator('.add-pure-and-binary-popup'); + } + static getForeignKeyPopup(page: Page): Locator { return page.locator('.foreignkey-popup'); } @@ -103,6 +112,12 @@ export default class ModalLocators { return modal.locator('.error-details'); } + // ------------- recordset modal functions -------------- // + + static getModalHeaderContext(modal: Locator): Locator { + return modal.locator('.modal-header-context'); + } + // --------- share cite related functions ------------ // static async waitForCitation(modal: Locator, timeout?: number): Promise<void> { diff --git a/test/e2e/locators/recordset.ts b/test/e2e/locators/recordset.ts index 55818761d..abdd0c5c1 100644 --- a/test/e2e/locators/recordset.ts +++ b/test/e2e/locators/recordset.ts @@ -47,8 +47,8 @@ export default class RecordsetLocators { await expect.soft(container.locator('.table-column-spinner')).toHaveCount(0); } - static async waitForFacets(container: Page | Locator, timeout?: number): Promise<void> { - return container.locator('.facet-spinner').waitFor({ state: 'hidden', timeout }); + static async waitForFacets(container: Page | Locator): Promise<void> { + await expect.soft(container.locator('.facet-spinner')).toHaveCount(0); } static getPageTitleElement(container: Page | Locator): Locator { diff --git a/test/e2e/setup/playwright.configuration.ts b/test/e2e/setup/playwright.configuration.ts index 34df3dd96..67812bad4 100644 --- a/test/e2e/setup/playwright.configuration.ts +++ b/test/e2e/setup/playwright.configuration.ts @@ -76,7 +76,10 @@ const getConfig = (options: TestOptions) => { trace: 'on-first-retry', // screenshots will be added to the playwright-report folder - screenshot: 'only-on-failure' + screenshot: 'only-on-failure', + + // set the timezone to Los Angeles + timezoneId: 'America/Los_Angeles' }, // Configure projects for major browsers. projects: [ diff --git a/test/e2e/specs/all-features-confirmation/chaise-config.js b/test/e2e/specs/all-features-confirmation/chaise-config.js index 469b11b85..c1e50845c 100644 --- a/test/e2e/specs/all-features-confirmation/chaise-config.js +++ b/test/e2e/specs/all-features-confirmation/chaise-config.js @@ -19,6 +19,9 @@ var chaiseConfig = { disableExternalLinkModal: true, logClientActions: false, hideRecordeditLeaveAlert: true, + facetPanelDisplay: { + maxFacetDepth: 0 + }, footerMarkdown:"**Please check** [Privacy Policy](/privacy-policy/){target='_blank'}", defaultTable: { "schema": "product-recordset", diff --git a/test/e2e/specs/all-features-confirmation/recordset/presentation.spec.ts b/test/e2e/specs/all-features-confirmation/recordset/presentation.spec.ts index c7653527f..3a33bfc79 100644 --- a/test/e2e/specs/all-features-confirmation/recordset/presentation.spec.ts +++ b/test/e2e/specs/all-features-confirmation/recordset/presentation.spec.ts @@ -302,6 +302,12 @@ test.describe('View recordset', () => { await testTotalCount(page, `Displaying all${data.length}records`) }); + await test.step('should honor the max_facet_depth of table and ignore the chaise-config setting', async () => { + await expect.soft(RecordsetLocators.getSidePanel(page)).toBeVisible(); + await expect.soft(RecordsetLocators.getHideFilterPanelBtn(page)).toBeVisible(); + await expect.soft(RecordsetLocators.getAllFacets(page)).toHaveCount(16); + }); + await test.step('should show correct table rows.', async () => { await testRecordsetTableRowValues(page, data, true); }); @@ -324,6 +330,12 @@ test.describe('View recordset', () => { await RecordsetLocators.waitForRecordsetAggregates(page); }); + await test.step('should not display facets if maxFacetDepth is 0 in the chaise-config', async () => { + await expect.soft(RecordsetLocators.getSidePanel(page)).not.toBeVisible(); + await expect.soft(RecordsetLocators.getShowFilterPanelBtn(page)).not.toBeVisible(); + await expect.soft(RecordsetLocators.getHideFilterPanelBtn(page)).not.toBeVisible(); + }); + await test.step('presentation of the recordset page', async () => { if (!process.env.CI) { await test.step('delete files that may have been downloaded before', async () => { diff --git a/test/e2e/specs/all-features/chaise-config.js b/test/e2e/specs/all-features/chaise-config.js index 909cb5720..c1739efd5 100644 --- a/test/e2e/specs/all-features/chaise-config.js +++ b/test/e2e/specs/all-features/chaise-config.js @@ -15,7 +15,6 @@ var chaiseConfig = { disableDefaultExport: true, disableExternalLinkModal: true, showWriterEmptyRelatedOnLoad: false, - showFaceting: true, facetPanelDisplay: { open: ["compact/select/association"] }, diff --git a/test/e2e/specs/default-config/recordset/add.spec.ts b/test/e2e/specs/default-config/recordset/add.spec.ts index 806a7245d..a90cfab9f 100644 --- a/test/e2e/specs/default-config/recordset/add.spec.ts +++ b/test/e2e/specs/default-config/recordset/add.spec.ts @@ -35,6 +35,11 @@ test('Recordset add record', async ({ page, baseURL }, testInfo) => { await expect.soft(RecordsetLocators.getPageTitleInlineComment(page)).toHaveText('Recordset inline comment'); }); + await test.step('the facet panel should be displayed by default if maxFacetDepth is missing from chaise-config', async () => { + await expect.soft(RecordsetLocators.getSidePanel(page)).toBeVisible(); + await expect.soft(RecordsetLocators.getAllFacets(page)).toHaveCount(7); + }); + await test.step('verify the text is truncated and "... more" is showing', async () => { firstRow = RecordsetLocators.getRows(page).nth(0); testCell = RecordsetLocators.getRowCells(firstRow).nth(4); diff --git a/test/e2e/specs/default-config/recordset/facet-within-facet.config.ts b/test/e2e/specs/default-config/recordset/facet-within-facet.config.ts new file mode 100644 index 000000000..8c7cd8a9c --- /dev/null +++ b/test/e2e/specs/default-config/recordset/facet-within-facet.config.ts @@ -0,0 +1,8 @@ +import getConfig from '@isrd-isi-edu/chaise/test/e2e/setup/playwright.configuration'; + +export default getConfig({ + testName: 'default-config/recordset/facet-within-facet', + configFileName: 'recordset/facet-within-facet.dev.json', + mainSpecName: 'default-config', + testMatch: [ 'facet-within-facet.spec.ts' ] +}); diff --git a/test/e2e/specs/default-config/recordset/facet-within-facet.spec.ts b/test/e2e/specs/default-config/recordset/facet-within-facet.spec.ts new file mode 100644 index 000000000..500512bbb --- /dev/null +++ b/test/e2e/specs/default-config/recordset/facet-within-facet.spec.ts @@ -0,0 +1,779 @@ +import { test, expect, TestInfo, Page, Locator } from '@playwright/test'; + +import ModalLocators from '@isrd-isi-edu/chaise/test/e2e/locators/modal'; +import RecordeditLocators from '@isrd-isi-edu/chaise/test/e2e/locators/recordedit'; +import RecordLocators from '@isrd-isi-edu/chaise/test/e2e/locators/record'; +import RecordsetLocators from '@isrd-isi-edu/chaise/test/e2e/locators/recordset'; + +import { + clearRangeInput, + fillRangeInput, + testClearAllFilters, testDisplayedFacets, testSelectFacetOption, +} from '@isrd-isi-edu/chaise/test/e2e/utils/recordset-utils'; +import { APP_NAMES } from '@isrd-isi-edu/chaise/test/e2e/utils/constants'; +import { generateChaiseURL } from '@isrd-isi-edu/chaise/test/e2e/utils/page-utils'; + +/** + * first layer facets: + * + * main + * <-- main_inbound1 + * <-- main_inbound1_inbound1 : "Entity path" and "Entity path with filter" facets + * <-- main_inbound1_inbound2: "Entity path 2" facet + * <-- main_inbound2 + * <-- main_inbound2_inbound1 : "Entity path with shared prefix" + * --> main_inbound2_outbound1: "Entity path with shared prefix and filter" + * <-- main_inbound3 + * <-- main_inbound3_inbound1: "Entity Path with fast filter" + * <-- main_inbound3_inbound1_fast_filter: the fast_fitler_source of prev facet + * + * To simplify the second layer facets, I added a facet_2nd_layer_hub which has fk to all the tables above, + * and other new tables have inbound to them to be displayed as facets. so regardless of which facet we opened + * for the first layer, the second layer facets all look the same in UI but they have different paths to the main table. + * + * facet_2nd_layer_hub + * --> main_inbound1_inbound1 + * --> main_inbound_1_inbound2 + * --> main_inbound2_inbound1 + * --> main_inbound2_outbound1 + * --> main_inbound3_inbound1 + * <-- facet_2nd_layer_hub_inbound1: "2nd layer Entity path" and "2nd layer Entity path with filter" facets + * <-- facet_2nd_layer_hub_inbound2: "2nd layer Entity path 2" facet + * <-- facet_2nd_layer_hub_inbound3: "2nd layer Entity path with shared prefix" + * <-- facet_2nd_layer_hub_inbound4: "2nd layer Entity path with shared prefix and filter" + * <-- facet_2nd_layer_hub_inbound5: "2nd layer Entity Path with fast filter" + * <-- facet_2nd_layer_hub_inbound5_fast_filter: the fast_fitler_source of prev facet + * + */ + +type FacetParamType = { + /** + * facet index + */ + index: number, + name: string, + /** + * description of the config + */ + description: string, + /** + * if defined, we will first select the option defined here. + */ + otherFacet?: { + index: number, + option: number, + numRows: number, + /** + * how many filters are visible after selection (default: 1) + */ + numFacetFilters: number + }[], + popup: { + uiContext: string, + title: string, + facetNames: string[], + numRows: number, + facets: { + index: number, + name: string, + options: string[], + /** + * if defined, selection is done proior to opening the popup. + */ + select?: { + option: number, + numRows: number, + /** + * the name that appears above the table summarizing the selected filters + */ + filterName?: string, + /** + * how many filters are visible after selection, default=1 + */ + numFacetFilters?: number + }[], + selectDateTime?: { + min?: { date: string, time: string }, + max?: { date: string, time: string }, + numRows: number, + }[], + + popup?: { + uiContext: string, + title: string, + numRows: number, + /** + * list of selected items + */ + selectedChiclets?: string[] + }, + /** + * useful if you want to select something without affecting other facets. + */ + clearAll?: boolean + }[] + } + +} + +const popupFacetNames = [ + '2nd layer entity path', '2nd layer entity path 2', '2nd layer entity path with filter', '2nd layer entity path with shared prefix', + '2nd layer entity path with shared prefix and filter', '2nd layer entity path with fast filter', '2nd layer timestamptz' +] + +const getTestParams = (rootUIContext: string): { + facets: FacetParamType[] +} => { + return { + facets: [ + { + index: 0, + name: 'Entity path', + description: 'general case without any selection', + popup: { + uiContext: rootUIContext + ':', + title: 'Select Entity path', + facetNames: popupFacetNames, + numRows: 10, + facets: [ + { + index: 0, + name: popupFacetNames[0], + options: [ + 'All records with value', 'No value', + 'facet_2nd_layer_hub_inbound1_10', 'facet_2nd_layer_hub_inbound1_11', 'facet_2nd_layer_hub_inbound1_12', + 'facet_2nd_layer_hub_inbound1_13', 'facet_2nd_layer_hub_inbound1_14', 'facet_2nd_layer_hub_inbound1_15' + ], + popup: { + uiContext: rootUIContext + 'Entity path:', + title: 'Select 2nd layer entity path', + numRows: 6 + } + }, + { + index: 1, + name: popupFacetNames[1], + options: [ + 'All records with value', 'No value', + 'facet_2nd_layer_hub_inbound2_10', 'facet_2nd_layer_hub_inbound2_11', 'facet_2nd_layer_hub_inbound2_12', + 'facet_2nd_layer_hub_inbound2_13', 'facet_2nd_layer_hub_inbound2_14', 'facet_2nd_layer_hub_inbound2_15' + ], + popup: { + uiContext: rootUIContext + 'Entity path:', + title: 'Select 2nd layer entity path 2', + numRows: 6 + } + }, + { + index: 2, + name: popupFacetNames[2], + options: [ + 'All records with value', + 'facet_2nd_layer_hub_inbound1_10', 'facet_2nd_layer_hub_inbound1_11', 'facet_2nd_layer_hub_inbound1_12', + 'facet_2nd_layer_hub_inbound1_13', 'facet_2nd_layer_hub_inbound1_14', 'facet_2nd_layer_hub_inbound1_15' + ], + popup: { + uiContext: rootUIContext + 'Entity path:', + title: 'Select 2nd layer entity path with filter', + numRows: 6 + } + }, + { + index: 3, + name: popupFacetNames[3], + options: [ + 'All records with value', 'No value', + 'facet_2nd_layer_hub_inbound3_10', 'facet_2nd_layer_hub_inbound3_11', 'facet_2nd_layer_hub_inbound3_12', + 'facet_2nd_layer_hub_inbound3_13', 'facet_2nd_layer_hub_inbound3_14', 'facet_2nd_layer_hub_inbound3_15' + ], + popup: { + uiContext: rootUIContext + 'Entity path:', + title: 'Select 2nd layer entity path with shared prefix', + numRows: 6 + } + }, + { + index: 4, + name: popupFacetNames[4], + options: [ + 'All records with value', + 'facet_2nd_layer_hub_inbound4_10', 'facet_2nd_layer_hub_inbound4_11', 'facet_2nd_layer_hub_inbound4_12', + 'facet_2nd_layer_hub_inbound4_13', 'facet_2nd_layer_hub_inbound4_14', 'facet_2nd_layer_hub_inbound4_15' + ], + popup: { + uiContext: rootUIContext + 'Entity path:', + title: 'Select 2nd layer entity path with shared prefix and filter', + numRows: 6 + } + }, + { + index: 5, + name: popupFacetNames[5], + options: [ + 'All records with value', 'No value', + 'facet_2nd_layer_hub_inbound5_10', 'facet_2nd_layer_hub_inbound5_11', 'facet_2nd_layer_hub_inbound5_12', + 'facet_2nd_layer_hub_inbound5_13', 'facet_2nd_layer_hub_inbound5_14', 'facet_2nd_layer_hub_inbound5_15' + ], + popup: { + uiContext: rootUIContext + 'Entity path:', + title: 'Select 2nd layer entity path with fast filter', + numRows: 6 + } + }, + ] + } + }, + { + index: 1, + name: 'Entity path 2', + description: 'selection at the root', + otherFacet: [{ + index: 0, + option: 1, // null + numRows: 18, + numFacetFilters: 1 + }, { + index: 0, + option: 2, + numRows: 19, + numFacetFilters: 1 + }], + popup: { + uiContext: rootUIContext + ':', + title: 'Select Entity path 2', + facetNames: popupFacetNames, + numRows: 8, + facets: [ + { + index: 0, + name: popupFacetNames[0], + options: [ + 'All records with value', 'facet_2nd_layer_hub_inbound1_13', + 'facet_2nd_layer_hub_inbound1_14', 'facet_2nd_layer_hub_inbound1_15' + ], + popup: { + uiContext: rootUIContext + 'Entity path 2:', + title: 'Select 2nd layer entity path', + numRows: 3 + } + }, + { + index: 1, + name: popupFacetNames[1], + options: [ + 'All records with value', 'facet_2nd_layer_hub_inbound2_13', + 'facet_2nd_layer_hub_inbound2_14', 'facet_2nd_layer_hub_inbound2_15' + ], + popup: { + uiContext: rootUIContext + 'Entity path 2:', + title: 'Select 2nd layer entity path 2', + numRows: 3 + } + }, + { + index: 2, + name: popupFacetNames[2], + options: [ + 'All records with value', 'facet_2nd_layer_hub_inbound1_13', + 'facet_2nd_layer_hub_inbound1_14', 'facet_2nd_layer_hub_inbound1_15' + ], + popup: { + uiContext: rootUIContext + 'Entity path 2:', + title: 'Select 2nd layer entity path with filter', + numRows: 3 + } + }, + { + index: 3, + name: popupFacetNames[3], + options: [ + 'All records with value', 'facet_2nd_layer_hub_inbound3_13', + 'facet_2nd_layer_hub_inbound3_14', 'facet_2nd_layer_hub_inbound3_15' + ], + popup: { + uiContext: rootUIContext + 'Entity path 2:', + title: 'Select 2nd layer entity path with shared prefix', + numRows: 3 + } + }, + { + index: 4, + name: popupFacetNames[4], + options: [ + 'All records with value', 'facet_2nd_layer_hub_inbound4_13', + 'facet_2nd_layer_hub_inbound4_14', 'facet_2nd_layer_hub_inbound4_15' + ], + popup: { + uiContext: rootUIContext + 'Entity path 2:', + title: 'Select 2nd layer entity path with shared prefix and filter', + numRows: 3 + } + }, + { + index: 5, + name: popupFacetNames[5], + options: [ + 'All records with value', 'facet_2nd_layer_hub_inbound5_13', + 'facet_2nd_layer_hub_inbound5_14', 'facet_2nd_layer_hub_inbound5_15' + ], + popup: { + uiContext: rootUIContext + 'Entity path 2:', + title: 'Select 2nd layer entity path with fast filter', + numRows: 3 + } + }, + ] + } + }, + { + index: 2, + name: 'Entity path with filter', + description: 'path with filter, selection on the popup', + popup: { + uiContext: rootUIContext + ':', + title: 'Select Entity path with filter', + facetNames: popupFacetNames, + numRows: 10, + facets: [ + { + index: 0, + name: popupFacetNames[0], + options: [ + 'All records with value', 'No value', + 'facet_2nd_layer_hub_inbound1_10', 'facet_2nd_layer_hub_inbound1_11', 'facet_2nd_layer_hub_inbound1_12', + 'facet_2nd_layer_hub_inbound1_13', 'facet_2nd_layer_hub_inbound1_14', 'facet_2nd_layer_hub_inbound1_15' + ], + select: [{ + option: 1, // null + numRows: 5, + }, { + option: 2, + numRows: 6, + filterName: '2nd layer entity pathNo value , facet_2nd_layer_hub_inbound1_10' + }] + }, + { + index: 1, + name: popupFacetNames[1], + options: ['All records with value', 'facet_2nd_layer_hub_inbound2_10', 'facet_2nd_layer_hub_inbound2_11'] + }, + { + index: 2, + name: popupFacetNames[2], + options: ['All records with value', 'facet_2nd_layer_hub_inbound1_10', 'facet_2nd_layer_hub_inbound1_11'], + popup: { + uiContext: rootUIContext + 'Entity path with filter:', + title: 'Select 2nd layer entity path with filter', + numRows: 2 + } + }, + { + index: 3, + name: popupFacetNames[3], + options: ['All records with value', 'facet_2nd_layer_hub_inbound3_10', 'facet_2nd_layer_hub_inbound3_11'] + }, + { + index: 4, + name: popupFacetNames[4], + options: ['All records with value', 'facet_2nd_layer_hub_inbound4_10', 'facet_2nd_layer_hub_inbound4_11'] + }, + { + index: 5, + name: popupFacetNames[5], + options: ['All records with value', 'facet_2nd_layer_hub_inbound5_10', 'facet_2nd_layer_hub_inbound5_11'] + }, + { + index: 6, + name: popupFacetNames[6], + options: ['All records with value', 'No value'], + selectDateTime: [{ + min: { date: '2006-06-06', time: '00:00:00' }, + numRows: 3 + }] + } + ] + } + }, + { + index: 3, + name: 'Entity path with shared prefix', + description: 'select filters for itself and see it has no effect on the popup. shared prefix filter on popup', + otherFacet: [{ + index: 3, + option: 1, // null + numRows: 19, + numFacetFilters: 1 + }, { + index: 3, + option: 2, + numRows: 20, + numFacetFilters: 1 + }], + popup: { + uiContext: rootUIContext + ':', + title: 'Select Entity path with shared prefix', + facetNames: popupFacetNames, + numRows: 8, + facets: [ + { + index: 0, + name: popupFacetNames[0], + options: [ + 'All records with value', 'No value', 'facet_2nd_layer_hub_inbound1_13', + 'facet_2nd_layer_hub_inbound1_14', 'facet_2nd_layer_hub_inbound1_15' + ], + popup: { + uiContext: rootUIContext + 'Entity path with shared prefix:', + title: 'Select 2nd layer entity path', + numRows: 3 + } + }, + { + index: 1, + name: popupFacetNames[1], + options: [ + 'All records with value', 'No value', 'facet_2nd_layer_hub_inbound2_13', + 'facet_2nd_layer_hub_inbound2_14', 'facet_2nd_layer_hub_inbound2_15' + ] + }, + { + index: 2, + name: popupFacetNames[2], + options: [ + 'All records with value', 'facet_2nd_layer_hub_inbound1_13', + 'facet_2nd_layer_hub_inbound1_14', 'facet_2nd_layer_hub_inbound1_15' + ] + }, + { + index: 3, + name: popupFacetNames[3], + options: [ + 'All records with value', 'No value', 'facet_2nd_layer_hub_inbound3_13', + 'facet_2nd_layer_hub_inbound3_14', 'facet_2nd_layer_hub_inbound3_15' + ], + select: [{ + option: 4, + numRows: 1, + }, { + option: 1, // null + numRows: 6, + }], + popup: { + uiContext: rootUIContext + 'Entity path with shared prefix:', + title: 'Select 2nd layer entity path with shared prefix', + numRows: 3, + selectedChiclets: ['No value', 'facet_2nd_layer_hub_inbound3_15'] + } + }, + { + index: 4, + name: popupFacetNames[4], + options: ['All records with value', 'facet_2nd_layer_hub_inbound4_15'], + popup: { + uiContext: rootUIContext + 'Entity path with shared prefix:', + title: 'Select 2nd layer entity path with shared prefix and filter', + numRows: 1 + } + }, + { + index: 5, + name: popupFacetNames[5], + options: ['All records with value', 'facet_2nd_layer_hub_inbound5_15'] + }, + ] + } + }, + { + index: 4, + name: 'Entity path with shared prefix and filter', + description: 'shared prefix facet interactions', + popup: { + uiContext: rootUIContext + ':', + title: 'Select Entity path with shared prefix and filter', + facetNames: popupFacetNames, + numRows: 10, + facets: [ + { + index: 3, + name: popupFacetNames[3], + options: [ + 'All records with value', 'No value', 'facet_2nd_layer_hub_inbound3_06', + 'facet_2nd_layer_hub_inbound3_07', 'facet_2nd_layer_hub_inbound3_08', 'facet_2nd_layer_hub_inbound3_09', + 'facet_2nd_layer_hub_inbound3_10', 'facet_2nd_layer_hub_inbound3_11', 'facet_2nd_layer_hub_inbound3_12', + 'facet_2nd_layer_hub_inbound3_13', 'facet_2nd_layer_hub_inbound3_14', 'facet_2nd_layer_hub_inbound3_15' + ], + select: [{ + option: 3, + numRows: 1 + }, { + option: 4, + numRows: 2, + numFacetFilters: 1 + }] + }, + { + index: 4, + name: popupFacetNames[4], + options: [ + 'All records with value', 'facet_2nd_layer_hub_inbound4_06', 'facet_2nd_layer_hub_inbound4_07', + 'facet_2nd_layer_hub_inbound4_08', 'facet_2nd_layer_hub_inbound4_09' + ], + select: [{ + option: 1, + numRows: 1, + numFacetFilters: 2 + }], + popup: { + uiContext: rootUIContext + 'Entity path with shared prefix and filter:', + title: 'Select 2nd layer entity path with shared prefix and filter', + numRows: 4, + selectedChiclets: ['facet_2nd_layer_hub_inbound4_06'] + } + } + ] + } + }, + { + index: 5, + name: 'Select 2nd layer entity path with fast filter', + description: 'fast filter', + popup: { + uiContext: rootUIContext + ':', + title: 'Select Entity path with fast filter', + facetNames: popupFacetNames, + numRows: 8, + facets: [ + { + index: 5, + name: popupFacetNames[5], + options: [ + 'All records with value', 'No value', 'facet_2nd_layer_hub_inbound5_13', + 'facet_2nd_layer_hub_inbound5_14', 'facet_2nd_layer_hub_inbound5_15' + ], + select: [{ + option: 1, + numRows: 5 + }, { + option: 2, + numRows: 6 + }], + popup: { + uiContext: rootUIContext + 'Entity path with fast filter:', + title: 'Select 2nd layer entity path with fast filter', + numRows: 3, + selectedChiclets: ['No value', 'facet_2nd_layer_hub_inbound5_13'] + } + }, + // open another one and make sure it works + { + index: 0, + name: popupFacetNames[0], + options: ['All records with value', 'facet_2nd_layer_hub_inbound1_13'], + popup: { + uiContext: rootUIContext + 'Entity path with fast filter:', + title: 'Select 2nd layer entity path', + numRows: 1, + selectedChiclets: [] + } + } + ] + } + } + ] + } +} + +/******************** helpers ************************/ + +/** + * This function must be defined before the test blocks. + * @param rootUIContext the ui context of the page (depends on where the recordset instance is) + * @param initialPageLoad the initial operation to load the recordset instance. it should return the container of recordset instance + */ +const testFacetWithinFacet = ( + rootUIContext: string, + initialPageLoad: (page: Page, baseURL: string | undefined, testInfo: TestInfo) => Promise<Page | Locator> +) => { + + // make sure facet within facet works for all the different types of entity facets we have (shared prefix, with filter, etc) + const testParams = getTestParams(rootUIContext) + for (const firstLevelProps of testParams.facets) { + test(`first level: ${firstLevelProps.name}`, async ({ page, baseURL }, testInfo) => { + let container: Page | Locator; + + await test.step('open the recordset instance', async () => { + container = await initialPageLoad(page, baseURL, testInfo); + }); + + if (Array.isArray(firstLevelProps.otherFacet) && firstLevelProps.otherFacet.length > 0) { + await test.step('select an option in one of the facets', async () => { + for await (const item of firstLevelProps.otherFacet!) { + const f = RecordsetLocators.getFacetById(container, item.index); + await expect.soft(f).toBeVisible(); + await testSelectFacetOption(container, f, item.option, item.numRows, item.numFacetFilters); + } + }); + } + + await test.step('facet popup', async () => { + const firstLevelModal = ModalLocators.getFacetPopup(page, 1); + const secondLevelModal = ModalLocators.getFacetPopup(page, 2); + + await test.step('display title, ui context, and number of rows', async () => { + const f = RecordsetLocators.getFacetById(container, firstLevelProps.index); + await RecordsetLocators.getShowMore(f).click(); + await expect.soft(firstLevelModal).toBeVisible(); + await RecordsetLocators.waitForRecordsetPageReady(firstLevelModal); + + await expect.soft(ModalLocators.getModalHeaderContext(firstLevelModal)).toHaveText(firstLevelProps.popup.uiContext); + await expect.soft(ModalLocators.getModalTitle(firstLevelModal)).toHaveText(firstLevelProps.popup.title); + await expect.soft(RecordsetLocators.getRows(firstLevelModal)).toHaveCount(firstLevelProps.popup.numRows); + }); + + await test.step('display facet options', async () => { + const showBtn = RecordsetLocators.getShowFilterPanelBtn(firstLevelModal); + await expect.soft(showBtn).toBeVisible(); + await showBtn.click(); + // all of them are open based on the annotation + await testDisplayedFacets(firstLevelModal, firstLevelProps.popup.facetNames, firstLevelProps.popup.facetNames); + }); + + for await (const secondLevelProps of firstLevelProps.popup.facets) { + await test.step(`second level: ${secondLevelProps.name}`, async () => { + const popupFacetEl = RecordsetLocators.getFacetById(firstLevelModal, secondLevelProps.index); + + await test.step('display facet options', async () => { + // wait for list to be fully visible + await expect.soft(RecordsetLocators.getList(popupFacetEl)).toBeVisible(); + // wait for facet checkboxes to load + await expect.soft(RecordsetLocators.getFacetOptions(popupFacetEl)).toHaveText(secondLevelProps.options); + }); + + if (Array.isArray(secondLevelProps.select) && secondLevelProps.select.length > 0) { + await test.step('selecting facet option(s)', async () => { + for await (const item of secondLevelProps.select!) { + await testSelectFacetOption(firstLevelModal, popupFacetEl, item.option, item.numRows, item.numFacetFilters); + if (item.filterName) { + await expect.soft(RecordsetLocators.getFacetFilters(firstLevelModal).nth(0)).toHaveText(item.filterName); + } + } + }); + } + + if (Array.isArray(secondLevelProps.selectDateTime) && secondLevelProps.selectDateTime.length > 0) { + await test.step('selecting datetime facet(s)', async () => { + for await (const item of secondLevelProps.selectDateTime!) { + const rangeInputs = RecordsetLocators.getFacetRangeTimestampInputs(popupFacetEl); + await clearRangeInput(rangeInputs.minDateInput); + await clearRangeInput(rangeInputs.minTimeInput); + await clearRangeInput(rangeInputs.maxDateInput); + await clearRangeInput(rangeInputs.maxTimeInput); + + if (item.min) { + await fillRangeInput(rangeInputs.minDateInput, item.min.date); + await fillRangeInput(rangeInputs.minTimeInput, item.min.time); + } + + if (item.max) { + await fillRangeInput(rangeInputs.minDateInput, item.max.date); + await fillRangeInput(rangeInputs.minTimeInput, item.max.time); + } + + await rangeInputs.submit.click(); + await expect.soft(RecordsetLocators.getRangeInputValidationError(popupFacetEl)).not.toBeVisible(); + await expect.soft(RecordsetLocators.getRows(firstLevelModal)).toHaveCount(item.numRows); + } + }); + } + + if (secondLevelProps.popup) { + await test.step('facet popup', async () => { + const showMore = RecordsetLocators.getShowMore(popupFacetEl); + await expect.soft(showMore).toBeVisible(); + await RecordsetLocators.getShowMore(popupFacetEl).click(); + await expect.soft(secondLevelModal).toBeVisible(); + await RecordsetLocators.waitForRecordsetPageReady(secondLevelModal); + + await expect.soft(RecordsetLocators.getShowFilterPanelBtn(secondLevelModal)).not.toBeVisible(); + await expect.soft(ModalLocators.getModalHeaderContext(secondLevelModal)).toHaveText(secondLevelProps.popup!.uiContext); + await expect.soft(ModalLocators.getModalTitle(secondLevelModal)).toHaveText(secondLevelProps.popup!.title); + await expect.soft(RecordsetLocators.getRows(secondLevelModal)).toHaveCount(secondLevelProps.popup!.numRows); + + const chiclets = secondLevelProps.popup!.selectedChiclets; + if (chiclets) { + await expect.soft(RecordsetLocators.getSelectedRowsFilters(secondLevelModal)).toHaveCount(chiclets.length); + await expect.soft(RecordsetLocators.getSelectedRowsFilters(secondLevelModal)).toHaveText(chiclets); + } + + await ModalLocators.getCloseBtn(secondLevelModal).click(); + await expect.soft(secondLevelModal).not.toBeAttached(); + }); + } + + if (secondLevelProps.clearAll) { + await test.step('clear all facetes', async () => { + await testClearAllFilters(firstLevelModal, firstLevelProps.popup.numRows); + }); + } + }); + } + }); + + }) + + } +} + +/******************** tests ************************/ + + +test.describe('facet within facet', () => { + test.describe.configure({ mode: 'parallel' }); + + test.describe('recordset page', () => { + testFacetWithinFacet( + 'main', + async (page, baseURL, testInfo) => { + await page.goto(generateChaiseURL(APP_NAMES.RECORDSET, 'facet-within-facet', 'main', testInfo, baseURL)); + await RecordsetLocators.waitForRecordsetPageReady(page); + return page; + } + ) + }); + + test.describe('record link popup', () => { + testFacetWithinFacet( + 'main association', + async (page, baseURL, testInfo) => { + await page.goto(generateChaiseURL(APP_NAMES.RECORD, 'facet-within-facet', 'record_main', testInfo, baseURL) + '/id=record_main_01'); + await RecordLocators.waitForRecordPageReady(page); + const modal = ModalLocators.getAddPureBinaryPopup(page); + await RecordLocators.getRelatedTableAddButton(page, 'main association', true).click(); + await expect(modal).toBeVisible(); + // open the facet panel + await expect.soft(RecordsetLocators.getShowFilterPanelBtn(modal)).toBeVisible(); + await RecordsetLocators.getShowFilterPanelBtn(modal).click(); + await expect.soft(RecordsetLocators.getSidePanel(modal)).toHaveAttribute('class', /open-panel/); + return modal; + } + ) + }); + + test.describe('recoredit fk popup', () => { + testFacetWithinFacet( + 'fk_to_main', + async (page, baseURL, testInfo) => { + await page.goto(generateChaiseURL(APP_NAMES.RECORDEDIT, 'facet-within-facet', 'recordedit_main', testInfo, baseURL)); + await RecordeditLocators.waitForRecordeditPageReady(page); + const modal = ModalLocators.getForeignKeyPopup(page); + await RecordeditLocators.getForeignKeyInputButton(page, 'fk_to_main', 1).click(); + await expect(modal).toBeVisible(); + // open the facet panel + await expect.soft(RecordsetLocators.getShowFilterPanelBtn(modal)).toBeVisible(); + await RecordsetLocators.getShowFilterPanelBtn(modal).click(); + await expect.soft(RecordsetLocators.getSidePanel(modal)).toHaveAttribute('class', /open-panel/); + return modal; + } + ) + }); +}); diff --git a/test/e2e/specs/delete-prohibited/chaise-config.js b/test/e2e/specs/delete-prohibited/chaise-config.js index ccd1d69ed..bab76a43c 100644 --- a/test/e2e/specs/delete-prohibited/chaise-config.js +++ b/test/e2e/specs/delete-prohibited/chaise-config.js @@ -4,7 +4,9 @@ var chaiseConfig = { name: "Delete Prohibited", editRecord: true, deleteRecord: false, - showFaceting: true, + facetPanelDisplay: { + maxFacetDepth: 1 + }, navbarBrandText: 'test123', navbarBrandImage: '../images/genetic-data.png', maxRecordsetRowHeight: 100, diff --git a/test/e2e/specs/delete-prohibited/recordset/reorder-facet.spec.ts b/test/e2e/specs/delete-prohibited/recordset/reorder-facet.spec.ts index 52b1fddb5..dfe5e528d 100644 --- a/test/e2e/specs/delete-prohibited/recordset/reorder-facet.spec.ts +++ b/test/e2e/specs/delete-prohibited/recordset/reorder-facet.spec.ts @@ -6,7 +6,8 @@ import RecordsetLocators from '@isrd-isi-edu/chaise/test/e2e/locators/recordset' // utils import { getCatalogID } from '@isrd-isi-edu/chaise/test/e2e/utils/catalog-utils'; import { - openRecordsetAndResetFacetState, TestIndividualFacetParams, testIndividualFacet, resetFacetState + openRecordsetAndResetFacetState, TestIndividualFacetParams, testIndividualFacet, resetFacetState, + testDisplayedFacets } from '@isrd-isi-edu/chaise/test/e2e/utils/recordset-utils'; import { dragAndDropWithScroll } from '@isrd-isi-edu/chaise/test/e2e/utils/page-utils'; @@ -231,18 +232,6 @@ const getURL = (testInfo: TestInfo, baseURL?: string) => { return `${baseURL}/recordset/#${getCatalogID(testInfo.project.name)}/${testParams.schema_name}:${testParams.table_name}${testParams.sort}`; } -const testDisplayedFacets = async (page: Page, facetNames: string[], openFacetNames?: string[]) => { - await expect.soft(RecordsetLocators.getAllFacets(page)).toHaveCount(facetNames.length); - await expect.soft(RecordsetLocators.getFacetTitles(page)).toHaveText(facetNames); - - if (openFacetNames) { - const openedFacets = RecordsetLocators.getOpenFacetTitles(page); - await expect.soft(openedFacets).toHaveCount(openFacetNames.length); - await expect.soft(openedFacets).toHaveText(openFacetNames); - } -} - - /** * This function will move a facet to the original positon of the destination facet. * Since moving the facet will also change the position of all the other facets (including destination facet), diff --git a/test/e2e/utils/page-utils.ts b/test/e2e/utils/page-utils.ts index 5d2034d43..cbdf5377b 100644 --- a/test/e2e/utils/page-utils.ts +++ b/test/e2e/utils/page-utils.ts @@ -1,4 +1,4 @@ -import { expect, Locator, Page, test } from '@playwright/test'; +import { expect, Locator, Page, test, TestInfo } from '@playwright/test'; import fs from 'fs'; // Locators @@ -11,6 +11,7 @@ import RecordeditLocators from '@isrd-isi-edu/chaise/test/e2e/locators/recordedi // utils import { APP_NAMES, DOWNLOAD_FOLDER } from '@isrd-isi-edu/chaise/test/e2e/utils/constants'; +import { getCatalogID } from '@isrd-isi-edu/chaise/test/e2e/utils/catalog-utils'; export async function getClipboardContent(page: Page): Promise<string> { return await page.evaluate('navigator.clipboard.readText()'); @@ -32,6 +33,16 @@ export async function getPageId(page: Page): Promise<string> { }); } +/** + * generate a url to the chaise app. + * + * Notes: + * - The URL doesn't have any trailing `/`. if you need to append filter or facets, make sure to start with a `/`. + */ +export function generateChaiseURL(appName: APP_NAMES, schemaName: string, tableName: string, testInfo: TestInfo, baseURL?: string) : string { + return `${baseURL ? baseURL : ''}/${appName}/#${getCatalogID(testInfo.project.name)}/${schemaName}:${tableName}`; +} + /** * click on the given link and return the opened page instance. * diff --git a/test/e2e/utils/record-utils.ts b/test/e2e/utils/record-utils.ts index 83cde375e..92a58b362 100644 --- a/test/e2e/utils/record-utils.ts +++ b/test/e2e/utils/record-utils.ts @@ -611,7 +611,7 @@ type AddAssociationTableParams = { export const testAddAssociationTable = async (page: Page, params: AddAssociationTableParams) => { await test.step('link feature', async () => { - const rsModal = ModalLocators.getRecordsetSearchPopup(page); + const rsModal = ModalLocators.getAddPureBinaryPopup(page); await test.step('clicking on `Link` button should open up a modal.', async () => { const addBtn = RecordLocators.getRelatedTableAddButton(page, params.displayname, params.isInline); diff --git a/test/e2e/utils/recordset-utils.ts b/test/e2e/utils/recordset-utils.ts index 798e4a138..f715219fb 100644 --- a/test/e2e/utils/recordset-utils.ts +++ b/test/e2e/utils/recordset-utils.ts @@ -39,6 +39,23 @@ export type TotalCountParts = { totalText: string } +/** + * make sure the list of facets is correct. + * @param container the element or page the facet panel belongs to + * @param facetNames list of facet names + * @param openFacetNames the open facet names (optional) + */ +export async function testDisplayedFacets (container: Page | Locator, facetNames: string[], openFacetNames?: string[]) { + await expect.soft(RecordsetLocators.getAllFacets(container)).toHaveCount(facetNames.length); + await expect.soft(RecordsetLocators.getFacetTitles(container)).toHaveText(facetNames); + + if (openFacetNames) { + const openedFacets = RecordsetLocators.getOpenFacetTitles(container); + await expect.soft(openedFacets).toHaveCount(openFacetNames.length); + await expect.soft(openedFacets).toHaveText(openFacetNames); + } +} + /** * * @param container Page or recordset container (if recordset is showing in a modal or we are testing a related section) @@ -110,17 +127,21 @@ export async function openFacetAndTestFilterOptions(page: Page, facet: Locator, * Selects a facet option and verifies the row count and number of recordset filters * @param optionIdx facet option index to click * @param numRows number of recordset rows after clicking facet option - * @param numFilters number of recordset filters after clicking facet option + * @param numFilters number of recordset filters after clicking facet option (default: 1) */ -export async function testSelectFacetOption(page: Page | Locator, facet: Locator, optionIdx: number, numRows: number, numFilters: number) { +export async function testSelectFacetOption(container: Page | Locator, facet: Locator, optionIdx: number, numRows: number, numFilters?: number) { // open facets show a spinner in the header when the rows are being fetched and is hidden when code execution is finished await expect.soft(RecordsetLocators.getFacetSpinner(facet)).not.toBeVisible(); await RecordsetLocators.getFacetOption(facet, optionIdx).check(); // wait for request to return - await expect.soft(RecordsetLocators.getClearAllFilters(page)).toBeVisible(); - await expect.soft(RecordsetLocators.getRows(page)).toHaveCount(numRows); - await expect.soft(RecordsetLocators.getFacetFilters(page)).toHaveCount(numFilters); + await expect.soft(RecordsetLocators.getClearAllFilters(container)).toBeVisible(); + await expect.soft(RecordsetLocators.getRows(container)).toHaveCount(numRows); + + if (typeof numFilters !== 'number') { + numFilters = 1; + } + await expect.soft(RecordsetLocators.getFacetFilters(container)).toHaveCount(numFilters); } /** @@ -128,11 +149,11 @@ export async function testSelectFacetOption(page: Page | Locator, facet: Locator * @param optionIdx facet option index to check is unchecked * @param pageSize the recordset page size for comparing with after clear */ -export async function testClearAllFilters(page: Page, pageSize: number, facet?: Locator, optionIdx?: number) { - const clearAll = RecordsetLocators.getClearAllFilters(page); +export async function testClearAllFilters(container: Page | Locator, pageSize: number, facet?: Locator, optionIdx?: number) { + const clearAll = RecordsetLocators.getClearAllFilters(container); await clearAll.click(); await expect.soft(clearAll).not.toBeVisible(); - await expect.soft(RecordsetLocators.getRows(page)).toHaveCount(pageSize); + await expect.soft(RecordsetLocators.getRows(container)).toHaveCount(pageSize); if (facet && optionIdx) await expect.soft(RecordsetLocators.getFacetOption(facet, optionIdx)).not.toBeChecked(); } @@ -235,13 +256,13 @@ export async function testSubmitModalSelection(page: Page, facet: Locator, modal * @param pageSize the recordset page size for comparing with after clear */ // eslint-disable-next-line max-len -export async function testSelectFacetOptionThenClear(page: Page, facetIdx: number, filterIdx: number, filterName: string, numRowsAfter: number, pageSize: number) { - const facet = RecordsetLocators.getFacetById(page, facetIdx); - await testSelectFacetOption(page, facet, filterIdx, numRowsAfter, 1); +export async function testSelectFacetOptionThenClear(container: Page | Locator, facetIdx: number, filterIdx: number, filterName: string, numRowsAfter: number, pageSize: number) { + const facet = RecordsetLocators.getFacetById(container, facetIdx); + await testSelectFacetOption(container, facet, filterIdx, numRowsAfter, 1); - await expect.soft(RecordsetLocators.getFacetFilters(page).nth(0)).toHaveText(filterName); + await expect.soft(RecordsetLocators.getFacetFilters(container).nth(0)).toHaveText(filterName); - await testClearAllFilters(page, pageSize, facet, filterIdx); + await testClearAllFilters(container, pageSize, facet, filterIdx); }; /**