diff --git a/.eslintrc.js b/.eslintrc.js
index 882170b64..a481dad4b 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -1,54 +1,55 @@
module.exports = {
- env: {
- es6: true,
- node: true,
- },
- extends: [
- 'eslint:recommended',
- 'plugin:@typescript-eslint/recommended',
- 'plugin:import/recommended',
- 'plugin:import/typescript',
- 'prettier',
- ],
- parser: '@typescript-eslint/parser',
- parserOptions: {
- ecmaVersion: 'latest',
- },
- plugins: ['@typescript-eslint', 'prettier'],
- root: true,
- rules: {
- '@typescript-eslint/no-empty-interface': [
- 'warn',
- {
- allowSingleExtends: false,
- },
- ],
- '@typescript-eslint/no-explicit-any': 'off',
- '@typescript-eslint/no-var-requires': 'off',
- 'import/first': ['warn', 'absolute-first'],
- 'import/order': [
- 'warn',
- {
- groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
- 'newlines-between': 'always',
- warnOnUnassignedImports: true,
- },
- ],
- 'import/newline-after-import': 'warn',
- 'prettier/prettier': [
- 'error',
- {
- printWidth: 100,
- semi: true,
- singleQuote: true,
- trailingComma: 'all',
- },
- ],
- },
- settings: {
- 'import/resolver': {
- 'babel-module': { allowExistingDirectories: true },
- },
- 'import/internal-regex': '^@/',
- },
+ env: {
+ es6: true,
+ node: true,
+ },
+ extends: [
+ 'eslint:recommended',
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:import/recommended',
+ 'plugin:import/typescript',
+ 'prettier',
+ ],
+ parser: '@typescript-eslint/parser',
+ parserOptions: {
+ ecmaVersion: 'latest',
+ },
+ plugins: ['@typescript-eslint', 'prettier'],
+ root: true,
+ rules: {
+ '@typescript-eslint/no-empty-interface': [
+ 'warn',
+ {
+ allowSingleExtends: false,
+ },
+ ],
+ '@typescript-eslint/no-explicit-any': 'off',
+ '@typescript-eslint/no-var-requires': 'off',
+ 'import/first': ['warn', 'absolute-first'],
+ 'import/order': [
+ 'warn',
+ {
+ groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
+ 'newlines-between': 'always',
+ warnOnUnassignedImports: true,
+ },
+ ],
+ 'import/newline-after-import': 'warn',
+ 'prettier/prettier': [
+ 'error',
+ {
+ printWidth: 100,
+ trailingComma: 'all',
+ semi: true,
+ singleQuote: true,
+ useTabs: true,
+ },
+ ],
+ },
+ settings: {
+ 'import/resolver': {
+ 'babel-module': { allowExistingDirectories: true },
+ },
+ 'import/internal-regex': '^@/',
+ },
};
diff --git a/.gitignore b/.gitignore
index b2731d18e..eac182ba1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,5 @@ lerna-debug.log
**/.DS_Store
**/*.env*
!**/.env.schema
+
+.vscode/*log
diff --git a/Jenkinsfile b/Jenkinsfile
index 87bbe94f8..464f4d619 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -132,6 +132,13 @@ pipeline {
}
stage('Build images') {
+ when {
+ anyOf {
+ branch 'develop'
+ branch 'main'
+ branch 'test'
+ }
+ }
steps {
container('docker') {
sh "DOCKER_BUILDKIT=1 \
diff --git a/modules/components/.eslintrc.js b/modules/components/.eslintrc.js
index a0412a2ff..80511aa09 100644
--- a/modules/components/.eslintrc.js
+++ b/modules/components/.eslintrc.js
@@ -20,6 +20,7 @@ module.exports = {
'@emotion/pkg-renaming': 'error',
'@emotion/styled-import': 'error',
'jsx-a11y/href-no-hash': 'off',
+ 'react/no-unknown-property': ['error', { ignore: ['css'] }],
'react/prop-types': 'off',
},
settings: {
diff --git a/modules/components/package-lock.json b/modules/components/package-lock.json
index 4df22bb12..d875f929f 100644
--- a/modules/components/package-lock.json
+++ b/modules/components/package-lock.json
@@ -91,6 +91,7 @@
"storybook-router": "^0.3.3",
"ts-jest": "^29.0.3",
"ttypescript": "^1.5.13",
+ "type-fest": "^3.0.0",
"typescript-transform-paths": "^3.3.1"
},
"peerDependencies": {
@@ -4221,6 +4222,18 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/ansi-escapes/node_modules/type-fest": {
+ "version": "0.21.3",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
+ "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/ansi-html-community": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz",
@@ -22806,12 +22819,12 @@
}
},
"node_modules/type-fest": {
- "version": "0.21.3",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
- "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.0.0.tgz",
+ "integrity": "sha512-MINvUN5ug9u+0hJDzSZNSnuKXI8M4F5Yvb6SQZ2CYqe7SgKXKOosEcU5R7tRgo85I6eAVBbkVF7TCvB4AUK2xQ==",
"dev": true,
"engines": {
- "node": ">=10"
+ "node": ">=14.16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -27585,6 +27598,14 @@
"dev": true,
"requires": {
"type-fest": "^0.21.3"
+ },
+ "dependencies": {
+ "type-fest": {
+ "version": "0.21.3",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
+ "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
+ "dev": true
+ }
}
},
"ansi-html-community": {
@@ -42549,9 +42570,9 @@
"dev": true
},
"type-fest": {
- "version": "0.21.3",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
- "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.0.0.tgz",
+ "integrity": "sha512-MINvUN5ug9u+0hJDzSZNSnuKXI8M4F5Yvb6SQZ2CYqe7SgKXKOosEcU5R7tRgo85I6eAVBbkVF7TCvB4AUK2xQ==",
"dev": true
},
"type-is": {
diff --git a/modules/components/package.json b/modules/components/package.json
index bab6846f5..cac0e6344 100644
--- a/modules/components/package.json
+++ b/modules/components/package.json
@@ -71,6 +71,7 @@
"storybook-router": "^0.3.3",
"ts-jest": "^29.0.3",
"ttypescript": "^1.5.13",
+ "type-fest": "^3.0.0",
"typescript-transform-paths": "^3.3.1"
},
"peerDependencies": {
@@ -135,9 +136,10 @@
},
"prettier": {
"printWidth": 100,
+ "trailingComma": "all",
"semi": true,
"singleQuote": true,
- "trailingComma": "all"
+ "useTabs": true
},
"husky": {
"hooks": {
diff --git a/modules/components/src/Aggs/DatesAgg.js b/modules/components/src/Aggs/DatesAgg.js
index 23be108f2..6e51dbd04 100644
--- a/modules/components/src/Aggs/DatesAgg.js
+++ b/modules/components/src/Aggs/DatesAgg.js
@@ -6,9 +6,9 @@ import 'react-datepicker/dist/react-datepicker.css';
import { removeSQON, replaceSQON } from '@/SQONViewer/utils';
import { withTheme } from '@/ThemeContext';
+import { emptyObj } from '@/utils/noops';
import AggsWrapper from './AggsWrapper';
-import { emptyObj } from '@/utils/noops';
const dateFromSqon = (dateString) => new Date(dateString);
const toSqonDate = (date) => date.valueOf();
@@ -26,12 +26,13 @@ class DatesAgg extends React.Component {
this.setState(this.initializeState(nextProps));
}
- initializeState = ({ stats = {}, getActiveValue = () => null }) => {
- const { field } = this.props;
+ initializeState = ({ getActiveValue = () => null, stats = {}, enforceStatsMax = false }) => {
+ const { fieldName } = this.props;
const minDate = stats.min && subDays(stats.min, 1);
- const maxDate = stats.max && addDays(stats.max, 1);
- const startFromSqon = getActiveValue({ op: '>=', field });
- const endFromSqon = getActiveValue({ op: '<=', field });
+ const statsMax = stats.max && addDays(stats.max, 1);
+ const maxDate = enforceStatsMax ? statsMax : Math.max(Date.now(), statsMax);
+ const startFromSqon = getActiveValue({ op: '>=', fieldName });
+ const endFromSqon = getActiveValue({ op: '<=', fieldName });
return {
minDate,
@@ -43,15 +44,15 @@ class DatesAgg extends React.Component {
updateSqon = () => {
const { startDate, endDate } = this.state;
- const { field, handleDateChange } = this.props;
- if (handleDateChange && field) {
+ const { fieldName, handleDateChange } = this.props;
+ if (handleDateChange && fieldName) {
const content = [
...(startDate
? [
{
op: '>=',
content: {
- field,
+ fieldName,
value: toSqonDate(startOfDay(startDate)),
},
},
@@ -62,7 +63,7 @@ class DatesAgg extends React.Component {
{
op: '<=',
content: {
- field,
+ fieldName,
value: toSqonDate(endOfDay(endDate)),
},
},
@@ -70,10 +71,10 @@ class DatesAgg extends React.Component {
: []),
];
handleDateChange({
- field,
+ fieldName,
value: content,
generateNextSQON: (sqon) =>
- replaceSQON(content.length ? { op: 'and', content } : null, removeSQON(field, sqon)),
+ replaceSQON(content.length ? { op: 'and', content } : null, removeSQON(fieldName, sqon)),
});
}
};
@@ -87,7 +88,7 @@ class DatesAgg extends React.Component {
collapsible = true,
displayName = 'Date Range',
facetView = false,
- field,
+ fieldName,
theme: {
colors,
components: {
@@ -106,7 +107,7 @@ class DatesAgg extends React.Component {
const hasData = minDate && maxDate;
const dataFields = {
- ...(field && { 'data-field': field }),
+ ...(fieldName && { 'data-fieldname': fieldName }),
...(type && { 'data-type': type }),
};
@@ -120,14 +121,65 @@ class DatesAgg extends React.Component {
justify-content: space-around;
padding-left: 5px;
- .react-datepicker__current-month,
+ .react-datepicker__current-month {
+ display: none;
+ }
+
.react-datepicker-time__header,
.react-datepicker-year-header {
color: ${colors?.grey?.[700]};
}
+ .react-datepicker__day-name,
+ .react-datepicker__day,
+ .react-datepicker__time-name {
+ line-height: 1.4rem;
+ width: 1.5rem;
+ }
+
+ .react-datepicker__header__dropdown {
+ display: flex;
+ justify-content: center;
+ }
+
.react-datepicker__input-container {
width: 100%;
+
+ .react-datepicker__close-icon::after {
+ align-items: center;
+ background-color: ${colors?.grey?.[500]};
+ border-radius: 30%;
+ display: flex;
+ font-size: 14px;
+ justify-content: center;
+ height: 10px;
+ line-height: 0;
+ padding: 0.1rem;
+ width: 10px;
+ }
+ }
+
+ .react-datepicker__month-option--selected {
+ left: 10px;
+ }
+
+ .react-datepicker__month-read-view,
+ .react-datepicker__year-read-view {
+ border: none;
+ visibility: visible !important;
+ /* ^^ otherwise the current becomes invisible when dropdown is displayed */
+ width: fit-content;
+ }
+
+ .react-datepicker__month-read-view--down-arrow,
+ .react-datepicker__year-read-view--down-arrow {
+ display: none;
+ }
+
+ .react-datepicker__month-read-view--selected-month,
+ .react-datepicker__year-read-view--selected-year {
+ font-size: 0.9rem;
+ font-weight: bold;
}
.react-datepicker-wrapper input {
@@ -138,32 +190,13 @@ class DatesAgg extends React.Component {
padding: 6px 5px 5px 7px;
width: 100%;
}
-
- .react-datepicker__input-container .react-datepicker__close-icon::after {
- align-items: center;
- background-color: ${colors?.grey?.[500]};
- border-radius: 30%;
- display: flex;
- font-size: 14px;
- justify-content: center;
- height: 10px;
- line-height: 0;
- padding: 0.1rem;
- width: 10px;
- }
-
- .react-datepicker__day-name,
- .react-datepicker__day,
- .react-datepicker__time-name {
- line-height: 1.4rem;
- width: 1.5rem;
- }
`}
>
) : (
diff --git a/modules/components/src/DataContext/index.tsx b/modules/components/src/DataContext/index.tsx
index 1263d3095..1b67c04cc 100644
--- a/modules/components/src/DataContext/index.tsx
+++ b/modules/components/src/DataContext/index.tsx
@@ -1,7 +1,9 @@
import { ComponentType, createContext, ReactElement, useContext, useEffect, useState } from 'react';
+import { isEqual } from 'lodash';
import { ThemeProvider } from '@/ThemeContext';
import defaultApiFetcher from '@/utils/api';
+import { ARRANGER_API, DEBUG } from '@/utils/config';
import getComponentDisplayName from '@/utils/getComponentDisplayName';
import missingProviderHandler from '@/utils/missingProvider';
import { emptyObj } from '@/utils/noops';
@@ -23,18 +25,21 @@ export const DataContext = createContext({
* @param {string} [url] customises where requests should be made by the data fetcher.
*/
export const DataProvider = ({
+ apiUrl = ARRANGER_API,
children,
customFetcher: apiFetcher = defaultApiFetcher,
documentType,
legacyProps,
theme,
- url,
}: DataProviderProps): ReactElement => {
const [sqon, setSQON] = useState(null);
useEffect(() => {
- setSQON(legacyProps?.sqon);
- }, [legacyProps?.sqon]);
+ if (legacyProps?.sqon && !isEqual(legacyProps.sqon, sqon)) {
+ DEBUG && console.log('setting sqon from legacyProps');
+ setSQON(legacyProps?.sqon);
+ }
+ }, [legacyProps?.sqon, sqon]);
const {
documentMapping,
@@ -51,13 +56,15 @@ export const DataProvider = ({
const fetchData = useDataFetcher({
apiFetcher,
documentType,
- keyField: tableConfigs?.keyField,
+ keyFieldName: tableConfigs?.keyFieldName,
sqon,
- url,
+ url: apiUrl,
});
const contextValues = {
...legacyProps,
+ apiFetcher,
+ apiUrl,
documentMapping,
downloadsConfigs,
extendedMapping,
@@ -83,6 +90,7 @@ export const DataProvider = ({
* @returns {DataContextInterface} data object
*/
export const useDataContext = ({
+ apiUrl: localApiUrl,
callerName,
customFetcher: localFetcher,
}: UseDataContextProps = emptyObj): DataContextInterface => {
@@ -92,6 +100,7 @@ export const useDataContext = ({
return {
...defaultContext,
+ apiUrl: localApiUrl || defaultContext?.apiUrl,
fetchData: localFetcher || defaultContext?.fetchData,
};
};
diff --git a/modules/components/src/DataContext/types.ts b/modules/components/src/DataContext/types.ts
index a93f8f25e..6add3b0a3 100644
--- a/modules/components/src/DataContext/types.ts
+++ b/modules/components/src/DataContext/types.ts
@@ -5,17 +5,17 @@ import SQON from 'sqon-builder';
// TODO: This legacyProps import will fail when is deprecated
// Should be safe to remove afterwards, if the migration path worked out
import { legacyProps } from '@/Arranger/Arranger';
-import { CustomThemeType, BaseThemeInterface } from '@/ThemeContext/types';
+import { CustomThemeType, ThemeOptions } from '@/ThemeContext/types';
export type DisplayType = 'all' | 'bits' | 'boolean' | 'bytes' | 'date' | 'list' | 'number';
export interface ColumnMappingInterface {
accessor: string;
canChangeShow: boolean;
- displayFormat?: string;
+ displayFormat?: string | null;
displayName?: string;
displayValues?: Record;
- field: string;
+ fieldName: string;
id: string;
isArray?: boolean;
jsonPath?: string | null;
@@ -27,13 +27,13 @@ export interface ColumnMappingInterface {
export interface ColumnSortingInterface {
desc: boolean;
- field: string;
+ fieldName: string;
}
export interface TableConfigsInterface {
columns: ColumnMappingInterface[];
defaultSorting: ColumnSortingInterface[];
- keyField: string;
+ keyFieldName: string;
}
export interface ExtendedMappingInterface {
@@ -41,7 +41,7 @@ export interface ExtendedMappingInterface {
displayName: string;
displayType: string;
displayValues: Record;
- field: string;
+ fieldName: string;
isArray: boolean;
primaryKey: boolean;
quickSearchEnabled: boolean;
@@ -73,19 +73,21 @@ export type FetchDataFn = (options?: {
queryName?: string;
}) => Promise<{ total?: number; data?: any } | void>;
-export interface DataProviderProps {
+export interface DataProviderProps {
+ apiUrl: string;
children?: React.ReactNode;
configs?: ConfigsInterface;
customFetcher?: APIFetcherFn;
documentType: string;
legacyProps?: typeof legacyProps; // TODO: deprecate along with
- url?: string;
theme?: CustomThemeType;
}
export type SQONType = typeof SQON | null;
export interface DataContextInterface {
+ apiFetcher: APIFetcherFn;
+ apiUrl: string;
documentType: string;
extendedMapping: ExtendedMappingInterface[];
fetchData: FetchDataFn;
@@ -97,6 +99,7 @@ export interface DataContextInterface {
}
export interface UseDataContextProps {
+ apiUrl?: string;
callerName?: string;
customFetcher?: FetchDataFn;
}
diff --git a/modules/components/src/DataTable/DataTable.js b/modules/components/src/DataTable/DataTable.js
index 28c5f1775..b30a87fe8 100644
--- a/modules/components/src/DataTable/DataTable.js
+++ b/modules/components/src/DataTable/DataTable.js
@@ -3,10 +3,9 @@ import { isEqual } from 'lodash';
import urlJoin from 'url-join';
import { withData } from '@/DataContext';
+import { ARRANGER_API } from '@/utils/config';
import noopFn from '@/utils/noops';
-import { ARRANGER_API } from '../utils/config';
-
import { Table, TableToolbar } from './';
const STORED_PROPS = {
@@ -86,6 +85,7 @@ class DataTableWithToolbar extends React.Component {
allowTogglingColumns = true,
allowTSVExport = true,
alwaysSorted = [],
+ apiUrl = ARRANGER_API,
columnDropdownText,
config,
customActions = null,
@@ -123,7 +123,7 @@ class DataTableWithToolbar extends React.Component {
} = this.props;
const { page, pageSize, sorted, total } = this.state;
- const url = downloadUrl || urlJoin(ARRANGER_API, 'download');
+ const url = downloadUrl || urlJoin(apiUrl, 'download');
return (
<>
diff --git a/modules/components/src/DataTable/Table/style.js b/modules/components/src/DataTable/Table/style.js
index ce2c0266b..9d4e25f1e 100644
--- a/modules/components/src/DataTable/Table/style.js
+++ b/modules/components/src/DataTable/Table/style.js
@@ -4,6 +4,7 @@ export default ({ scrollbarSize: { scrollbarWidth } } = {}) => css`
&.ReactTable .rt-thead.-header {
padding-right: ${scrollbarWidth}px;
}
+
&.ReactTable {
width: 100%;
box-sizing: border-box;
@@ -12,10 +13,12 @@ export default ({ scrollbarSize: { scrollbarWidth } } = {}) => css`
overflow-x: hidden;
}
}
+
.-pageJump {
border: solid 1px lightgrey;
border-radius: 5px;
}
+
.ReactTable .-pagination_button {
cursor: pointer;
padding-left: 10px;
@@ -23,8 +26,51 @@ export default ({ scrollbarSize: { scrollbarWidth } } = {}) => css`
color: grey;
user-select: none;
}
+
.ReactTable .-pagination_button.-current {
background: lightgrey;
color: #f0f1f6;
}
+
+ ul.list-values {
+ margin: 0;
+ padding-left: 1rem;
+
+ > li {
+ line-height: 1rem;
+ margin-bottom: 0.3rem;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ &.none {
+ list-style: none;
+ padding: 0;
+ }
+
+ &.commas {
+ display: flex;
+ flex-wrap: wrap;
+ list-style: none;
+ padding: 0;
+
+ > li:not(:last-of-type)::after {
+ content: ', ';
+ margin-right: 0.2rem;
+ }
+ }
+
+ &.letters {
+ list-style: lower-alpha;
+ }
+
+ &.numbers {
+ list-style: decimal;
+ }
+
+ &.roman {
+ list-style: upper-roman;
+ }
+ }
`;
diff --git a/modules/components/src/DataTable/columnTypes.js b/modules/components/src/DataTable/columnTypes.js
index 2cf593b80..14fde2910 100644
--- a/modules/components/src/DataTable/columnTypes.js
+++ b/modules/components/src/DataTable/columnTypes.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import cx from 'classnames';
import { format, isValid, parseISO } from 'date-fns';
import filesize from 'filesize';
import jsonPath from 'jsonpath/jsonpath.min';
@@ -8,7 +8,7 @@ import { getSingleValue } from './utils';
const STANDARD_DATE = 'yyyy-MM-dd';
-const dateHandler = ({ value, ...props }) => {
+const dateHandler = ({ value, ...props } = {}) => {
switch (true) {
case isNil(value):
return '';
@@ -35,15 +35,33 @@ const FileSize = ({ options = {}, ...props }) => (
);
export default {
- bits: ({ value, ...props }) => ,
- boolean: ({ value }) => (isNil(value) ? '' : `${value}`),
+ bits: ({ value = 0, ...props } = {}) => ,
+ boolean: ({ value = undefined } = {}) => (isNil(value) ? '' : `${value}`),
bytes: (props) => ,
date: dateHandler,
- list: (props) => {
- const values = jsonPath.query(props.original, props.column.jsonPath);
- const total = values.length;
- const firstValue = getSingleValue(values[0]);
- return [firstValue || '', ...(total > 1 ? [
, '...'] : [])];
+ list: ({ column, id, original }) => {
+ const valuesArr = jsonPath.query(original, column.jsonPath ?? column.fieldName)?.[0];
+ const arrHasValues = Array.isArray(valuesArr) && valuesArr?.filter((v) => v).length > 0; // table shouldn't display Nulls
+
+ if (Array.isArray(valuesArr)) {
+ if (column.isArray && arrHasValues) {
+ return (
+
+ {valuesArr.map((value, index) => (
+ -
+ {value}
+
+ ))}
+
+ );
+ }
+
+ const total = valuesArr.length;
+ const firstValue = getSingleValue(valuesArr[0]);
+ return [firstValue || '', ...(total > 1 ? [
, '...'] : [])];
+ }
+
+ return valuesArr;
},
number: Number,
};
diff --git a/modules/components/src/DataTable/utils.js b/modules/components/src/DataTable/utils.js
index 811e1cb42..7006b4781 100644
--- a/modules/components/src/DataTable/utils.js
+++ b/modules/components/src/DataTable/utils.js
@@ -1,7 +1,8 @@
-import columnTypes from './columnTypes';
import { withProps } from 'recompose';
import { isNil, sortBy } from 'lodash';
+import columnTypes from './columnTypes';
+
export function getSingleValue(data) {
if (typeof data === 'object' && data) {
return getSingleValue(Object.values(data)[0]);
@@ -28,8 +29,8 @@ export function normalizeColumns({
return {
...column,
- show: typeof column.show === 'boolean' ? column.show : true,
- Cell: column.Cell || types[column.type],
+ show: typeof column.show === 'boolean' ? column.show : false,
+ Cell: column.Cell || types[column.isArray ? 'list' : column.type],
hasCustomType: isNil(column.hasCustomType)
? !!(customTypes || {})[column.type]
: column.hasCustomType,
diff --git a/modules/components/src/SQONViewer/helpers.tsx b/modules/components/src/SQONViewer/helpers.tsx
index 80e507cde..cde3540be 100644
--- a/modules/components/src/SQONViewer/helpers.tsx
+++ b/modules/components/src/SQONViewer/helpers.tsx
@@ -49,8 +49,8 @@ export const Bubble = ({ children, className, theme, ...props }: BubbleProps) =>
);
};
-export const Field = ({ children, className, ...props }: BubbleProps) => (
-
+export const FieldName = ({ children, className, ...props }: BubbleProps) => (
+
{children}
);
@@ -81,8 +81,8 @@ export const useDataBubbles = ({
colors,
components: {
SQONViewer: {
- SQONClear: themeSQONClearProps = emptyObj,
- SQONField: themeSQONFieldProps = emptyObj,
+ SQONClear: { label: themeSQONClearLabel = 'Clear', ...themeSQONClearProps } = emptyObj,
+ SQONFieldName: themeSQONFieldNameProps = emptyObj,
SQONLessOrMore: themeSQONLessOrMoreProps = emptyObj,
SQONValue: {
characterLimit: themeCharacterLimit = 30,
@@ -101,7 +101,8 @@ export const useDataBubbles = ({
const { extendedMapping } = useDataContext({ callerName: 'SQONViewer - useDataBubbles' });
const findExtendedMappingForField = useCallback(
- (wantedField: string) => extendedMapping.find((mapping) => mapping.field === wantedField),
+ (wantedFieldName: string) =>
+ extendedMapping.find((mapping) => mapping.fieldName === wantedFieldName),
[extendedMapping],
);
@@ -125,18 +126,18 @@ export const useDataBubbles = ({
...themeSQONClearProps,
}}
>
- Clear
+ {themeSQONClearLabel}
);
- const FieldCrumb = ({ field, ...fieldProps }: { field: string }) => (
- (
+
- {findExtendedMappingForField(field)?.displayName || field}
-
+ {findExtendedMappingForField(fieldName)?.displayName || fieldName}
+
);
const lessOrMoreClickHandler = useCallback(
@@ -161,19 +162,19 @@ export const useDataBubbles = ({
const ValueCrumb = ({
css: customCSS,
- field,
+ fieldName,
nextSQON,
value,
...valueProps
}: {
- field: string;
+ fieldName: string;
nextSQON: GroupSQONInterface;
value: any;
} & ThemeCommon.CustomCSS) => {
const displayValue = translateSQONValue(
internalTranslateSQONValue(
- (findExtendedMappingForField(field)?.type === 'date' && format(value, dateFormat)) ||
- (findExtendedMappingForField(field)?.displayValues || {})[value] ||
+ (findExtendedMappingForField(fieldName)?.type === 'date' && format(value, dateFormat)) ||
+ (findExtendedMappingForField(fieldName)?.displayValues || {})[value] ||
value,
),
);
diff --git a/modules/components/src/SQONViewer/types.ts b/modules/components/src/SQONViewer/types.ts
index 02e0b5d72..e6f49c3d0 100644
--- a/modules/components/src/SQONViewer/types.ts
+++ b/modules/components/src/SQONViewer/types.ts
@@ -5,8 +5,10 @@ import { GenericFn } from '@/utils/noops';
export interface SQONViewerThemeProps {
EmptyMessage: ThemeCommon.NonButtonThemeProps;
SQONBubble: ThemedButtonProps;
- SQONClear: ThemedButtonProps;
- SQONField: ThemedButtonProps;
+ SQONClear: {
+ label?: string;
+ } & ThemedButtonProps;
+ SQONFieldName: ThemedButtonProps;
SQONGroup: ThemeCommon.NonButtonThemeProps;
SQONLessOrMore: ThemedButtonProps;
SQONOp: ThemeCommon.NonButtonThemeProps;
@@ -42,7 +44,7 @@ export type ArrayFieldValue = Array | string;
export type ScalarFieldValue = number;
export interface FilterField {
- fields: string[];
+ fieldNames: string[];
value: ArrayFieldValue;
}
@@ -52,12 +54,12 @@ export interface FilterFieldOperator {
}
export interface ArrayField {
- field: string;
+ fieldName: string;
value: ArrayFieldValue;
}
export interface ScalarField {
- field: string;
+ fieldName: string;
value: ScalarFieldValue;
}
@@ -82,8 +84,8 @@ export type ValueOpTypes = ArrayFieldKeys & CombinationKeys & ScalarFieldKeys;
export interface ValueContentInterface {
entity?: string;
- field: string;
- fields?: string[];
+ fieldName: string;
+ fieldNames?: string[];
value: any | any[];
}
@@ -115,4 +117,4 @@ export interface GroupSQONInterface {
// export type TFilterByWhitelist = (o?: TRawQuery, w?: Array) => TRawQuery;
-// export type TRemoveSQON = (field: string, query: TGroupSQON) => TGroupSQON | void;
+// export type TRemoveSQON = (fieldName: string, query: TGroupSQON) => TGroupSQON | void;
diff --git a/modules/components/src/Table/DownloadButton/DownloadButton.tsx b/modules/components/src/Table/DownloadButton/DownloadButton.tsx
index 4c7ead58f..8b4d99fb5 100644
--- a/modules/components/src/Table/DownloadButton/DownloadButton.tsx
+++ b/modules/components/src/Table/DownloadButton/DownloadButton.tsx
@@ -3,6 +3,7 @@ import { merge } from 'lodash';
import urlJoin from 'url-join';
import { TransparentButton } from '@/Button';
+import { useDataContext } from '@/DataContext';
import { SQONType } from '@/DataContext/types';
import MultiSelectDropDown from '@/DropDown/MultiSelectDropDown';
import MetaMorphicChild from '@/MetaMorphicChild';
@@ -24,8 +25,10 @@ import { ProcessedExporterDetailsInterface, DownloadButtonProps } from './types'
*
* Either case must follow the following pattern (all params are optional):
*
- * @param {string[]} columns
+ * @param {string[] | { fieldName }} columns
* Columns passed here override the ones currently being displayed in the table.
+ * the format for these is always an array, which could consist of one of the following types:
+ * accessor strings, or objects with a "fieldName" and any other properties as functions or their desired values.
* If columns is missing or `null`, the exporter will use all columns shown in the table.
* Bonus: if an empty array is given, the exporter will use every (showable) column declared in the config.
* @param {ExporterFn} exporterFn
@@ -51,6 +54,7 @@ const DownloadButton = ({
...customThemeProps
} = emptyObj,
}: DownloadButtonProps) => {
+ const { apiUrl = ARRANGER_API } = useDataContext();
const {
allColumnsDict,
currentColumnsDict,
@@ -71,7 +75,7 @@ const DownloadButton = ({
DownloadButton: {
customExporters: themeCustomExporters,
disableRowSelection: themeDisableRowSelection,
- downloadUrl: themeDownloadUrl = urlJoin(ARRANGER_API, 'download'),
+ downloadUrl: themeDownloadUrl = urlJoin(apiUrl, 'download'),
label: themeDownloadButtonLabel = 'Download',
maxRows: themeMaxRows = 100,
exportSelectedRowsField = 'file_autocomplete',
@@ -109,15 +113,15 @@ const DownloadButton = ({
exporterColumns,
exporterDownloadUrl = downloadUrl,
exporterFileName,
- exporterFn,
+ exporterFunction,
exporterLabel,
exporterMaxRows = maxRows,
exporterRequiresRowSelection,
}: ProcessedExporterDetailsInterface) =>
- (exporterFn && exporterRequiresRowSelection && !hasSelectedRows) || !exporterFn
+ (exporterFunction && exporterRequiresRowSelection && !hasSelectedRows) || !exporterFunction
? undefined
: () =>
- exporterFn?.(
+ exporterFunction?.(
{
files: [
{
diff --git a/modules/components/src/Table/DownloadButton/helpers.ts b/modules/components/src/Table/DownloadButton/helpers.ts
index c191e576b..8d560015f 100644
--- a/modules/components/src/Table/DownloadButton/helpers.ts
+++ b/modules/components/src/Table/DownloadButton/helpers.ts
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';
-import { ColumnMappingInterface } from '@/DataContext/types';
+import { ColumnMappingInterface, ExtendedMappingInterface } from '@/DataContext/types';
import download from '@/utils/download';
import { emptyObj } from '@/utils/noops';
@@ -9,42 +9,72 @@ import {
CustomExportersInput,
ExporterDetailsInterface,
ExporterFileInterface,
- ExporterFnProps,
+ ExporterFunctionProps,
ProcessedExporterDetailsInterface,
ProcessedExporterList,
} from './types';
+const useCustomisers =
+ (extendedColumn: ExtendedMappingInterface) =>
+ ([customiserLabel, customiserValue]): Partial => {
+ console.log('extendedColumn', extendedColumn);
+ return (
+ customiserValue && {
+ [customiserLabel]:
+ typeof customiserValue === 'function' ? customiserValue(extendedColumn) : customiserValue,
+ }
+ );
+ };
export const saveTSV = async ({
fileName = '',
files = [],
options = {},
url = '',
-}: ExporterFnProps) =>
+}: ExporterFunctionProps) =>
download({
url,
method: 'POST',
+ ...options,
params: {
fileName,
files: files.map(
- ({ allColumnsDict, columns, exporterColumns, ...file }: ExporterFileInterface) => ({
+ ({ allColumnsDict, columns, exporterColumns = null, ...file }: ExporterFileInterface) => ({
...file,
columns: exporterColumns // if the component gave you custom columns to show
? Object.values(
exporterColumns.length > 0 // if they ask for any specific columns
- ? exporterColumns
- .map(
- (fieldName) =>
- allColumnsDict[fieldName] || // get the column data from the extended configs
- // or let the user know if the column isn't valid
- console.info('Could not include a column into the file:', fieldName),
- )
- .filter((column) => column) // and then, use the valid ones
+ ? // use them
+ exporterColumns.map((column) => {
+ switch (typeof column) {
+ // checking if each column is customised
+ case 'object': {
+ const extendedColumn = allColumnsDict[column.fieldName];
+ const useExtendedCustomisers = useCustomisers(extendedColumn);
+
+ return {
+ ...extendedColumn,
+ ...Object.entries(column).reduce(
+ (customisers, customiser: ColumnCustomiserTuple) => ({
+ ...customisers,
+ ...useExtendedCustomisers(customiser),
+ }),
+ {},
+ ),
+ };
+ }
+
+ // or not
+ case 'string':
+ default:
+ return allColumnsDict[column];
+ }
+ })
: allColumnsDict, // else, they're asking for all the columns
)
- : columns.filter((column: ColumnMappingInterface) => column.show), // no custom columns, use admin's
+ : columns.filter((column) => column.show), // no custom columns, use admin's
}),
),
- ...options,
+ ...options.params,
},
});
@@ -62,13 +92,13 @@ const processExporter = (
item = 'saveTSV' as any as CustomExportersInput,
): ProcessedExporterDetailsInterface =>
(item as any) === 'saveTSV' ||
- item?.fn === 'saveTSV' ||
+ item?.function === 'saveTSV' ||
// or if they give us a filename without giving us a function
('fileName' in item && !('fn' in item))
? {
...(item?.columns && Array.isArray(item.columns) && { exporterColumns: item?.columns }),
exporterFileName: item?.fileName || 'unnamed.tsv',
- exporterFn: saveTSV,
+ exporterFunction: saveTSV,
exporterLabel: item?.label || 'Export TSV',
exporterMaxRows: item?.maxRows || 0,
exporterRequiresRowSelection: item?.requiresRowSelection || false,
diff --git a/modules/components/src/Table/DownloadButton/types.ts b/modules/components/src/Table/DownloadButton/types.ts
index 03210d879..ef978553f 100644
--- a/modules/components/src/Table/DownloadButton/types.ts
+++ b/modules/components/src/Table/DownloadButton/types.ts
@@ -1,12 +1,13 @@
import { ComponentType } from 'react';
+import type { Merge } from 'type-fest';
-import { ColumnMappingInterface, SQONType } from '@/DataContext/types';
+import { ColumnMappingInterface, ExtendedMappingInterface, SQONType } from '@/DataContext/types';
import { DropDownThemeProps } from '@/DropDown/types';
import { ColumnsDictionary, FieldList } from '@/Table/types';
import { ThemeCommon } from '@/ThemeContext/types';
-import { PrefixKeys } from '@/utils/types';
+import { PrefixKeys, WithFunctionOptions } from '@/utils/types';
-export type DownloadFn = (options: {
+export type DownloadFunction = (options: {
url: any;
params: any;
method?: string;
@@ -17,34 +18,46 @@ export interface ExporterFileInterface {
allColumnsDict: ColumnsDictionary;
columns: ColumnMappingInterface[];
documentType: string;
- exporterColumns?: string[];
+ exporterColumns?: FieldList | ColumnMappingInterface[] | null;
fileName: string;
fileType: 'tsv' | string;
maxRows: number;
sqon: SQONType;
}
-export interface ExporterFnProps {
+export interface ExporterFunctionProps {
fileName?: string;
files: ExporterFileInterface[];
options?: Record;
- selectedRows?: string[];
+ selectedRows: string[];
url: string;
}
-export type ExporterFn = (exporter: ExporterFnProps, downloadFn?: DownloadFn) => void;
+export type ExporterFunction = (
+ exporter: ExporterFunctionProps,
+ downloadFunction?: DownloadFunction,
+) => void;
+
+export type CustomColumnMappingInterface = WithFunctionOptions>;
+// export type CustomColumnMappingInterface = WithFunctionOptions>;
export interface ExporterDetailsInterface {
- columns?: FieldList | null;
+ columns?: (string | CustomColumnMappingInterface)[] | null;
downloadUrl?: string;
fileName?: string;
- fn?: ExporterFn;
+ function?: ExporterFunction;
label?: ComponentType | string;
maxRows?: number;
requiresRowSelection?: boolean;
+ valueWhenEmpty?: unknown;
}
-export type CustomExportersInput = ExporterDetailsInterface & { fn?: ExporterFn | 'saveTSV' };
+export type CustomExportersInput = Merge<
+ ExporterDetailsInterface,
+ {
+ function?: ExporterFunction | 'saveTSV';
+ }
+>;
export type ProcessedExporterDetailsInterface = PrefixKeys;
diff --git a/modules/components/src/Table/HeaderRow.tsx b/modules/components/src/Table/HeaderRow.tsx
index 22b30e803..ef0c7f7c3 100644
--- a/modules/components/src/Table/HeaderRow.tsx
+++ b/modules/components/src/Table/HeaderRow.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/react';
-import { HeaderGroup } from '@tanstack/react-table';
+import { flexRender, HeaderGroup } from '@tanstack/react-table';
import cx from 'classnames';
import { get } from 'lodash';
@@ -96,7 +96,9 @@ const TableHeaderRow = ({
key={headerObj.id}
title={label}
>
- {headerObj.isPlaceholder ? null : headerObj.renderHeader()}
+ {headerObj.isPlaceholder
+ ? null
+ : flexRender(headerObj.column.columnDef.header, headerObj.getContext())}
);
})}
diff --git a/modules/components/src/Table/Row.tsx b/modules/components/src/Table/Row.tsx
index 4b7b43c04..bfb544717 100644
--- a/modules/components/src/Table/Row.tsx
+++ b/modules/components/src/Table/Row.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/react';
-import { Row } from '@tanstack/react-table';
+import { flexRender, Row } from '@tanstack/react-table';
import cx from 'classnames';
import MetaMorphicChild from '@/MetaMorphicChild';
@@ -19,7 +19,7 @@ const TableRow = ({
padding?: string;
textOverflow?: string;
};
-} & Partial>>) => {
+} & Partial>) => {
const {
colors,
components: {
@@ -85,7 +85,7 @@ const TableRow = ({
>
{hasVisibleCells ? (
visibleCells?.map((cellObj) => {
- const value = getDisplayValue(cellObj?.row?.original, cellObj.column);
+ const value = getDisplayValue(cellObj?.row?.original, cellObj.column.columnDef);
return (
- {cellObj.renderCell()}
+ {flexRender(cellObj.column.columnDef.cell, cellObj.getContext())}
|
);
})
diff --git a/modules/components/src/Table/helpers/cells.tsx b/modules/components/src/Table/helpers/cells.tsx
index 9e2d530be..0b13dc36f 100644
--- a/modules/components/src/Table/helpers/cells.tsx
+++ b/modules/components/src/Table/helpers/cells.tsx
@@ -8,13 +8,17 @@ import { get, isNil } from 'lodash';
import dateFormatter from '@/utils/dates';
import { emptyObj } from '@/utils/noops';
+import { getSingleValue } from '.';
+
export const getCellValue = (
- row = emptyObj,
+ row = emptyObj as unknown,
{ accessor = '', id = '', jsonPath = '' } = emptyObj,
): string =>
- jsonPath ? JSONPath({ json: row, path: jsonPath }) : get(row, (id || accessor).split('.'), '');
+ jsonPath
+ ? JSONPath({ json: row as Record, path: jsonPath })
+ : get(row, (id || accessor).split('.'), '');
-export const getDisplayValue = (row = emptyObj, column = emptyObj): string => {
+export const getDisplayValue = (row = emptyObj as unknown, column = emptyObj): string => {
const value = getCellValue(row, column);
switch (column.type) {
case 'date':
@@ -34,25 +38,36 @@ const Number = (props = emptyObj) => (
{props.value?.toLocaleString('en-CA')}
);
+
const FileSize = ({ options = emptyObj, value = 0 }) => {filesize(value, options)};
export const defaultCellTypes = {
- bits: ({ value = 0, ...props } = emptyObj) => ,
- boolean: ({ value } = emptyObj) => (isNil(value) ? '' : `${value}`),
+ bits: ({ value = 0, ...props } = {}) => ,
+ boolean: ({ value = undefined } = {}) => (isNil(value) ? '' : `${value}`),
bytes: (props = emptyObj) => ,
date: ({ value, ...props } = emptyObj) => dateFormatter(value, props),
- list: ({ column, id, value: valuesArr, ...props } = emptyObj) => {
- return Array.isArray(valuesArr) ? (
-
- {valuesArr.map((value: ReactNode, index: number) => (
- -
- {value}
-
- ))}
-
- ) : (
- valuesArr
- );
+ list: ({ column, id, value: valuesArr } = emptyObj) => {
+ const arrHasValues = Array.isArray(valuesArr) && valuesArr?.filter((v) => v).length > 0; // table shouldn't display Nulls
+
+ if (Array.isArray(valuesArr)) {
+ if (column.isArray && arrHasValues) {
+ return (
+
+ {valuesArr.map((value: ReactNode, index) => (
+ -
+ {value}
+
+ ))}
+
+ );
+ }
+
+ const total = valuesArr.length;
+ const firstValue = getSingleValue(valuesArr[0]);
+ return [firstValue || '', ...(total > 1 ? [
, '...'] : [])];
+ }
+
+ return valuesArr;
},
number: Number,
};
diff --git a/modules/components/src/Table/helpers/columns.tsx b/modules/components/src/Table/helpers/columns.tsx
index e357ae043..11801c1b6 100644
--- a/modules/components/src/Table/helpers/columns.tsx
+++ b/modules/components/src/Table/helpers/columns.tsx
@@ -1,5 +1,5 @@
import { HTMLAttributes, useEffect, useRef } from 'react';
-import { Table } from '@tanstack/react-table';
+import { createColumnHelper } from '@tanstack/react-table';
import { mergeWith } from 'lodash';
import { ColumnMappingInterface } from '@/DataContext/types';
@@ -64,16 +64,15 @@ function IndeterminateCheckbox({
export const makeTableColumns = ({
allowRowSelection,
columnTypes: customColumnTypes = emptyObj,
- table,
total,
visibleColumns = [],
}: {
allowRowSelection?: boolean;
columnTypes?: Partial;
- table: Table;
total: number;
visibleColumns: ColumnMappingInterface[];
}) => {
+ const columnHelper = createColumnHelper();
const hasData = total > 0;
const columnTypes = mergeWith(customColumnTypes, defaultCellTypes, (objValue, srcValue) => ({
...objValue,
@@ -84,11 +83,11 @@ export const makeTableColumns = ({
const columnType = mergeWith(
{},
columnTypes.all,
- columnTypes[visibleColumn?.isArray ? 'list' : visibleColumn?.type],
- columnTypes[visibleColumn?.accessor],
+ columnTypes[visibleColumn.isArray ? 'list' : visibleColumn.type],
+ columnTypes[visibleColumn.accessor],
);
- return table.createDataColumn((row) => getCellValue(row, visibleColumn), {
+ return columnHelper.accessor((row) => getCellValue(row, visibleColumn), {
...visibleColumn,
cell: ({ getValue, cell }) => {
const cellType = columnType?.cellValue;
@@ -131,15 +130,15 @@ export const makeTableColumns = ({
return allowRowSelection
? [
- table.createDisplayColumn({
+ columnHelper.display({
id: 'select',
- header: ({ instance }) => (
+ header: ({ table }) => (
),
@@ -155,6 +154,7 @@ export const makeTableColumns = ({
),
}),
- ].concat(tableColumns)
+ ...tableColumns,
+ ]
: tableColumns;
};
diff --git a/modules/components/src/Table/helpers/context.tsx b/modules/components/src/Table/helpers/context.tsx
index 688fad57f..7a40c7212 100644
--- a/modules/components/src/Table/helpers/context.tsx
+++ b/modules/components/src/Table/helpers/context.tsx
@@ -64,7 +64,7 @@ export const TableContextProvider = ({
useThemeContext({ callerName: 'TableContextProvider' });
useEffect(() => {
- if (isLoadingConfigs) {
+ if (tableConfigs?.columns && Object.values(allColumnsDict).length === 0) {
const columns = aggregateCustomColumns(customColumns, tableConfigs?.columns);
setAllColumnsDict(columnsArrayToDictionary(columns)); // these will be the default to fallback to
diff --git a/modules/components/src/Table/helpers/index.ts b/modules/components/src/Table/helpers/index.ts
index 9f902ead5..71eb21618 100644
--- a/modules/components/src/Table/helpers/index.ts
+++ b/modules/components/src/Table/helpers/index.ts
@@ -1,5 +1,14 @@
-import { useEffect, useState } from 'react';
-import { createTable, useTableInstance, ColumnDef, getCoreRowModel } from '@tanstack/react-table';
+import { ReactNode, useEffect, useState } from 'react';
+import { useReactTable, ColumnDef, getCoreRowModel } from '@tanstack/react-table';
+/* Column,
+ Table as ReactTable,
+ PaginationState,
+ getCoreRowModel,
+ getFilteredRowModel,
+ getPaginationRowModel,
+ ColumnDef,
+ OnChangeFn,
+ flexRender, */
import { UseTableDataProps } from '@/Table/types';
import { useThemeContext } from '@/ThemeContext';
@@ -8,7 +17,13 @@ import { emptyObj } from '@/utils/noops';
import { makeTableColumns } from './columns';
import { useTableContext } from './context';
-const table = createTable();
+export const getSingleValue = (data: Record | ReactNode): ReactNode => {
+ if (typeof data === 'object' && data) {
+ return getSingleValue(Object.values(data)[0]);
+ } else {
+ return data;
+ }
+};
export const useTableData = ({
columnTypes: customColumnTypes,
@@ -39,7 +54,7 @@ export const useTableData = ({
} = useThemeContext({ callerName: 'Table - useTableData' });
const allowRowSelection = !(customDisableRowSelection || themeDisableRowSelection);
- const [tableColumns, setTableColumns] = useState[]>([]);
+ const [tableColumns, setTableColumns] = useState[]>([]);
useEffect(() => {
const visibleColumns = Object.values(visibleColumnsDict);
@@ -52,14 +67,13 @@ export const useTableData = ({
...customColumnTypes, // then prioritise the ones given directly into the table
// this is useful if there are multiple sibling tables with different "settings"
},
- table,
total,
visibleColumns,
}),
);
}, [customColumnTypes, allowRowSelection, themeColumnTypes, visibleColumnsDict, total]);
- const tableInstance = useTableInstance(table, {
+ const tableInstance = useReactTable({
columns: tableColumns,
data: tableData,
getCoreRowModel: getCoreRowModel(),
diff --git a/modules/components/src/Table/types.ts b/modules/components/src/Table/types.ts
index a5fbdf5f3..b348adc0a 100644
--- a/modules/components/src/Table/types.ts
+++ b/modules/components/src/Table/types.ts
@@ -63,14 +63,15 @@ type TableBoxModelProperties = Omit &
type TableInnerBoxModelProperties = Omit;
/** Table Component types */
-export type TableCellProps = Cell & {
+export type TableCellProps = Cell & {
column: Column & ColumnMappingInterface;
value: any;
};
type TableCellComponent = ReactNode | ((cell: TableCellProps) => ReactNode);
-export type TableHeaderProps = Header & ColumnMappingInterface & { disabled?: boolean };
+export type TableHeaderProps = Header &
+ ColumnMappingInterface & { disabled?: boolean };
type TableHeaderComponent = ReactNode | ((header: TableHeaderProps) => ReactNode);
diff --git a/modules/components/src/ThemeContext/types/index.ts b/modules/components/src/ThemeContext/types/index.ts
index fa745d71e..6beda5f79 100644
--- a/modules/components/src/ThemeContext/types/index.ts
+++ b/modules/components/src/ThemeContext/types/index.ts
@@ -36,13 +36,13 @@ export type ThemeAggregatorFn = (
partial: CustomThemeType | CustomThemeType[],
) => ThemeOptions;
-export interface ThemeContextInterface {
+export interface ThemeContextInterface {
aggregateTheme: ThemeAggregatorFn;
missingProvider?: string;
theme: Theme;
}
-export interface ThemeProviderProps {
+export interface ThemeProviderProps {
children?: React.ReactNode;
location?: string; // helpful for troubleshooting multiple theme providers
theme?: CustomThemeType;
@@ -53,7 +53,7 @@ export type UseThemeContextProps = CustomThemeType & {
callerName?: string;
};
-export interface WithThemeProps {
+export interface WithThemeProps {
theme?: Theme;
}
diff --git a/modules/components/src/index.js b/modules/components/src/index.js
index 830087c28..79a78317d 100644
--- a/modules/components/src/index.js
+++ b/modules/components/src/index.js
@@ -3,7 +3,7 @@ export {
DataContext as ArrangerDataContext,
DataProvider as ArrangerDataProvider,
useDataContext as useArrangerData,
- withTheme as withArrangerTheme,
+ withData as withArrangerData,
} from './DataContext';
// TODO: Deprecate "CurrentSQON" component name as unsemantical,
// remove SQONView (duplicate of CurrentSQON to produce the same log warning)
@@ -22,6 +22,7 @@ export {
ThemeContext as ArrangerThemeContext,
ThemeProvider as ArrangerThemeProvider,
useThemeContext as useArrangerTheme,
+ withTheme as withArrangerTheme,
} from './ThemeContext';
export { default as apiFetcher, addHeaders } from './utils/api';
export { default as Query, withQuery } from './Query';
diff --git a/modules/components/src/utils/dates.ts b/modules/components/src/utils/dates.ts
index 1f07a3581..4405357e8 100644
--- a/modules/components/src/utils/dates.ts
+++ b/modules/components/src/utils/dates.ts
@@ -3,7 +3,8 @@ import { isNil } from 'lodash';
export const STANDARD_DATE = 'yyyy-MM-dd';
-const displayFormatter = (value: string, { displayFormat = STANDARD_DATE, ...props }: any) => {
+const displayFormatter = (value: string, { displayFormat, ...props }: any) => {
+ displayFormat ??= STANDARD_DATE; // handle `null`
switch (true) {
case isNil(value):
return '';
diff --git a/modules/components/src/utils/types.ts b/modules/components/src/utils/types.ts
index 9c46f6ed2..eaccb2057 100644
--- a/modules/components/src/utils/types.ts
+++ b/modules/components/src/utils/types.ts
@@ -13,3 +13,7 @@ export type RecursivePartial = {
export type PrefixKeys = {
[P in keyof T as `${Prefix}${Capitalize}`]: T[P];
};
+
+export type WithFunctionOptions = {
+ [key in keyof T]: T[key] | ((input: Input) => T[key]);
+};
diff --git a/modules/server/package-lock.json b/modules/server/package-lock.json
index d87ac99e2..902fb0961 100644
--- a/modules/server/package-lock.json
+++ b/modules/server/package-lock.json
@@ -28,6 +28,7 @@
"graphql-middleware": "^6.1.33",
"graphql-playground-middleware-express": "^1.7.23",
"graphql-scalars": "^1.19.0",
+ "graphql-tools": "^8.3.8",
"graphql-type-json": "^0.3.2",
"jsonpath": "^1.1.1",
"lodash": "^4.17.21",
@@ -55,6 +56,7 @@
"@babel/preset-typescript": "^7.18.6",
"@babel/register": "^7.18.9",
"@types/convert-units": "^2.3.5",
+ "@types/graphql-fields": "^1.3.4",
"@types/jest": "^29.1.2",
"@types/lodash": "^4.14.186",
"@types/morgan": "^1.9.3",
@@ -85,6 +87,48 @@
"node": ">=6.0.0"
}
},
+ "node_modules/@apollo/client": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.7.1.tgz",
+ "integrity": "sha512-xu5M/l7p9gT9Fx7nF3AQivp0XukjB7TM7tOd5wifIpI8RskYveL4I+rpTijzWrnqCPZabkbzJKH7WEAKdctt9w==",
+ "optional": true,
+ "dependencies": {
+ "@graphql-typed-document-node/core": "^3.1.1",
+ "@wry/context": "^0.7.0",
+ "@wry/equality": "^0.5.0",
+ "@wry/trie": "^0.3.0",
+ "graphql-tag": "^2.12.6",
+ "hoist-non-react-statics": "^3.3.2",
+ "optimism": "^0.16.1",
+ "prop-types": "^15.7.2",
+ "response-iterator": "^0.2.6",
+ "symbol-observable": "^4.0.0",
+ "ts-invariant": "^0.10.3",
+ "tslib": "^2.3.0",
+ "zen-observable-ts": "^1.2.5"
+ },
+ "peerDependencies": {
+ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0",
+ "graphql-ws": "^5.5.5",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "subscriptions-transport-ws": "^0.9.0 || ^0.11.0"
+ },
+ "peerDependenciesMeta": {
+ "graphql-ws": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ },
+ "subscriptions-transport-ws": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@apollo/protobufjs": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/@apollo/protobufjs/-/protobufjs-1.2.6.tgz",
@@ -2132,6 +2176,15 @@
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
}
},
+ "node_modules/@graphql-typed-document-node/core": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz",
+ "integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==",
+ "optional": true,
+ "peerDependencies": {
+ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
+ }
+ },
"node_modules/@istanbuljs/load-nyc-config": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@@ -3114,6 +3167,24 @@
"@types/node": "*"
}
},
+ "node_modules/@types/graphql-fields": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/@types/graphql-fields/-/graphql-fields-1.3.4.tgz",
+ "integrity": "sha512-McLJaAaqY7lk9d9y7E61iQrj0AwcEjSb8uHlPh7KgYV+XX1MSLlSt/alhd5k2BPRE8gy/f4lnkLGb5ke3iG66Q==",
+ "dev": true,
+ "dependencies": {
+ "graphql": "^15.3.0"
+ }
+ },
+ "node_modules/@types/graphql-fields/node_modules/graphql": {
+ "version": "15.8.0",
+ "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.8.0.tgz",
+ "integrity": "sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.x"
+ }
+ },
"node_modules/@types/istanbul-lib-coverage": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
@@ -3257,6 +3328,42 @@
"integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==",
"dev": true
},
+ "node_modules/@wry/context": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.7.0.tgz",
+ "integrity": "sha512-LcDAiYWRtwAoSOArfk7cuYvFXytxfVrdX7yxoUmK7pPITLk5jYh2F8knCwS7LjgYL8u1eidPlKKV6Ikqq0ODqQ==",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.3.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@wry/equality": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.5.3.tgz",
+ "integrity": "sha512-avR+UXdSrsF2v8vIqIgmeTY0UR91UT+IyablCyKe/uk22uOJ8fusKZnH9JH9e1/EtLeNJBtagNmL3eJdnOV53g==",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.3.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@wry/trie": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.3.2.tgz",
+ "integrity": "sha512-yRTyhWSls2OY/pYLfwff867r8ekooZ4UI+/gxot5Wj8EFwSf2rG+n+Mo/6LoLQm1TKA4GRj2+LCpbfS937dClQ==",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.3.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@@ -5172,6 +5279,58 @@
"graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
}
},
+ "node_modules/graphql-tools": {
+ "version": "8.3.8",
+ "resolved": "https://registry.npmjs.org/graphql-tools/-/graphql-tools-8.3.8.tgz",
+ "integrity": "sha512-syDJ6hzlqm+DoiX+v8k0kogyYfdvPlpoZ+L76OD1d4Ll0qPCeZG41NzHBUJIzWWBz+Kq942m3ilEey/xCML8LQ==",
+ "dependencies": {
+ "@graphql-tools/schema": "9.0.6",
+ "tslib": "^2.4.0"
+ },
+ "optionalDependencies": {
+ "@apollo/client": "~3.2.5 || ~3.3.0 || ~3.4.0 || ~3.5.0 || ~3.6.0 || ~3.7.0"
+ },
+ "peerDependencies": {
+ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
+ }
+ },
+ "node_modules/graphql-tools/node_modules/@graphql-tools/merge": {
+ "version": "8.3.8",
+ "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.3.8.tgz",
+ "integrity": "sha512-L9YE8OpxSlzADcdrc4IG7/33H/iWVXTJXX2ie67cWAb5MFN2t3JBdQMa0bnBcAoOrKB7A8g2+dIp8oXTpdzxjg==",
+ "dependencies": {
+ "@graphql-tools/utils": "8.13.1",
+ "tslib": "^2.4.0"
+ },
+ "peerDependencies": {
+ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
+ }
+ },
+ "node_modules/graphql-tools/node_modules/@graphql-tools/schema": {
+ "version": "9.0.6",
+ "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-9.0.6.tgz",
+ "integrity": "sha512-/aznltpnVrurfWqXB4chWtaNmBFSk9v/KEJSpvas2fnlwwS9QnzWh6Sm/hsybWesirn5J2w60LLjMrrcCd58UA==",
+ "dependencies": {
+ "@graphql-tools/merge": "8.3.8",
+ "@graphql-tools/utils": "8.13.1",
+ "tslib": "^2.4.0",
+ "value-or-promise": "1.0.11"
+ },
+ "peerDependencies": {
+ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
+ }
+ },
+ "node_modules/graphql-tools/node_modules/@graphql-tools/utils": {
+ "version": "8.13.1",
+ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.13.1.tgz",
+ "integrity": "sha512-qIh9yYpdUFmctVqovwMdheVNJqFh+DQNWIhX87FJStfXYnmweBUDATok9fWPleKeFwxnW8IapKmY8m8toJEkAw==",
+ "dependencies": {
+ "tslib": "^2.4.0"
+ },
+ "peerDependencies": {
+ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
+ }
+ },
"node_modules/graphql-type-json": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/graphql-type-json/-/graphql-type-json-0.3.2.tgz",
@@ -5222,6 +5381,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/hoist-non-react-statics": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+ "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+ "optional": true,
+ "dependencies": {
+ "react-is": "^16.7.0"
+ }
+ },
"node_modules/hpagent": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/hpagent/-/hpagent-0.1.2.tgz",
@@ -7400,7 +7568,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
+ "devOptional": true
},
"node_modules/js-yaml": {
"version": "3.14.1",
@@ -7717,6 +7885,18 @@
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
},
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "optional": true,
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
@@ -8121,6 +8301,28 @@
"opencollective-postinstall": "index.js"
}
},
+ "node_modules/optimism": {
+ "version": "0.16.1",
+ "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.16.1.tgz",
+ "integrity": "sha512-64i+Uw3otrndfq5kaoGNoY7pvOhSsjFEN4bdEFh80MWVk/dbgJfMv7VFDeCT8LxNAlEVhQmdVEbfE7X2nWNIIg==",
+ "optional": true,
+ "dependencies": {
+ "@wry/context": "^0.6.0",
+ "@wry/trie": "^0.3.0"
+ }
+ },
+ "node_modules/optimism/node_modules/@wry/context": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.6.1.tgz",
+ "integrity": "sha512-LOmVnY1iTU2D8tv4Xf6MVMZZ+juIJ87Kt/plMijjN20NMAXGmH4u8bS1t0uT74cZ5gwpocYueV58YwyI8y+GKw==",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.3.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/optionator": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
@@ -8507,6 +8709,17 @@
"node": ">= 6"
}
},
+ "node_modules/prop-types": {
+ "version": "15.8.1",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
+ "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
+ "optional": true,
+ "dependencies": {
+ "loose-envify": "^1.4.0",
+ "object-assign": "^4.1.1",
+ "react-is": "^16.13.1"
+ }
+ },
"node_modules/proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@@ -8575,6 +8788,12 @@
"node": ">= 0.8"
}
},
+ "node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "optional": true
+ },
"node_modules/readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
@@ -8747,6 +8966,15 @@
"node": ">=10"
}
},
+ "node_modules/response-iterator": {
+ "version": "0.2.6",
+ "resolved": "https://registry.npmjs.org/response-iterator/-/response-iterator-0.2.6.tgz",
+ "integrity": "sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw==",
+ "optional": true,
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
"node_modules/retry": {
"version": "0.13.1",
"resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
@@ -9128,6 +9356,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/symbol-observable": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz",
+ "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==",
+ "optional": true,
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
"node_modules/tar-stream": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
@@ -9217,6 +9454,18 @@
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
+ "node_modules/ts-invariant": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.10.3.tgz",
+ "integrity": "sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/ts-jest": {
"version": "29.0.3",
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz",
@@ -9761,6 +10010,21 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/zen-observable": {
+ "version": "0.8.15",
+ "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz",
+ "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==",
+ "optional": true
+ },
+ "node_modules/zen-observable-ts": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.2.5.tgz",
+ "integrity": "sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg==",
+ "optional": true,
+ "dependencies": {
+ "zen-observable": "0.8.15"
+ }
+ },
"node_modules/zlib": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/zlib/-/zlib-1.0.5.tgz",
@@ -9781,6 +10045,27 @@
"@jridgewell/trace-mapping": "^0.3.0"
}
},
+ "@apollo/client": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.7.1.tgz",
+ "integrity": "sha512-xu5M/l7p9gT9Fx7nF3AQivp0XukjB7TM7tOd5wifIpI8RskYveL4I+rpTijzWrnqCPZabkbzJKH7WEAKdctt9w==",
+ "optional": true,
+ "requires": {
+ "@graphql-typed-document-node/core": "^3.1.1",
+ "@wry/context": "^0.7.0",
+ "@wry/equality": "^0.5.0",
+ "@wry/trie": "^0.3.0",
+ "graphql-tag": "^2.12.6",
+ "hoist-non-react-statics": "^3.3.2",
+ "optimism": "^0.16.1",
+ "prop-types": "^15.7.2",
+ "response-iterator": "^0.2.6",
+ "symbol-observable": "^4.0.0",
+ "ts-invariant": "^0.10.3",
+ "tslib": "^2.3.0",
+ "zen-observable-ts": "^1.2.5"
+ }
+ },
"@apollo/protobufjs": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/@apollo/protobufjs/-/protobufjs-1.2.6.tgz",
@@ -11218,6 +11503,13 @@
"tslib": "^2.4.0"
}
},
+ "@graphql-typed-document-node/core": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz",
+ "integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==",
+ "optional": true,
+ "requires": {}
+ },
"@istanbuljs/load-nyc-config": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@@ -12018,6 +12310,23 @@
"@types/node": "*"
}
},
+ "@types/graphql-fields": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/@types/graphql-fields/-/graphql-fields-1.3.4.tgz",
+ "integrity": "sha512-McLJaAaqY7lk9d9y7E61iQrj0AwcEjSb8uHlPh7KgYV+XX1MSLlSt/alhd5k2BPRE8gy/f4lnkLGb5ke3iG66Q==",
+ "dev": true,
+ "requires": {
+ "graphql": "^15.3.0"
+ },
+ "dependencies": {
+ "graphql": {
+ "version": "15.8.0",
+ "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.8.0.tgz",
+ "integrity": "sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw==",
+ "dev": true
+ }
+ }
+ },
"@types/istanbul-lib-coverage": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
@@ -12161,6 +12470,33 @@
"integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==",
"dev": true
},
+ "@wry/context": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.7.0.tgz",
+ "integrity": "sha512-LcDAiYWRtwAoSOArfk7cuYvFXytxfVrdX7yxoUmK7pPITLk5jYh2F8knCwS7LjgYL8u1eidPlKKV6Ikqq0ODqQ==",
+ "optional": true,
+ "requires": {
+ "tslib": "^2.3.0"
+ }
+ },
+ "@wry/equality": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.5.3.tgz",
+ "integrity": "sha512-avR+UXdSrsF2v8vIqIgmeTY0UR91UT+IyablCyKe/uk22uOJ8fusKZnH9JH9e1/EtLeNJBtagNmL3eJdnOV53g==",
+ "optional": true,
+ "requires": {
+ "tslib": "^2.3.0"
+ }
+ },
+ "@wry/trie": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.3.2.tgz",
+ "integrity": "sha512-yRTyhWSls2OY/pYLfwff867r8ekooZ4UI+/gxot5Wj8EFwSf2rG+n+Mo/6LoLQm1TKA4GRj2+LCpbfS937dClQ==",
+ "optional": true,
+ "requires": {
+ "tslib": "^2.3.0"
+ }
+ },
"abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@@ -13611,6 +13947,46 @@
"tslib": "^2.1.0"
}
},
+ "graphql-tools": {
+ "version": "8.3.8",
+ "resolved": "https://registry.npmjs.org/graphql-tools/-/graphql-tools-8.3.8.tgz",
+ "integrity": "sha512-syDJ6hzlqm+DoiX+v8k0kogyYfdvPlpoZ+L76OD1d4Ll0qPCeZG41NzHBUJIzWWBz+Kq942m3ilEey/xCML8LQ==",
+ "requires": {
+ "@apollo/client": "~3.2.5 || ~3.3.0 || ~3.4.0 || ~3.5.0 || ~3.6.0 || ~3.7.0",
+ "@graphql-tools/schema": "9.0.6",
+ "tslib": "^2.4.0"
+ },
+ "dependencies": {
+ "@graphql-tools/merge": {
+ "version": "8.3.8",
+ "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.3.8.tgz",
+ "integrity": "sha512-L9YE8OpxSlzADcdrc4IG7/33H/iWVXTJXX2ie67cWAb5MFN2t3JBdQMa0bnBcAoOrKB7A8g2+dIp8oXTpdzxjg==",
+ "requires": {
+ "@graphql-tools/utils": "8.13.1",
+ "tslib": "^2.4.0"
+ }
+ },
+ "@graphql-tools/schema": {
+ "version": "9.0.6",
+ "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-9.0.6.tgz",
+ "integrity": "sha512-/aznltpnVrurfWqXB4chWtaNmBFSk9v/KEJSpvas2fnlwwS9QnzWh6Sm/hsybWesirn5J2w60LLjMrrcCd58UA==",
+ "requires": {
+ "@graphql-tools/merge": "8.3.8",
+ "@graphql-tools/utils": "8.13.1",
+ "tslib": "^2.4.0",
+ "value-or-promise": "1.0.11"
+ }
+ },
+ "@graphql-tools/utils": {
+ "version": "8.13.1",
+ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.13.1.tgz",
+ "integrity": "sha512-qIh9yYpdUFmctVqovwMdheVNJqFh+DQNWIhX87FJStfXYnmweBUDATok9fWPleKeFwxnW8IapKmY8m8toJEkAw==",
+ "requires": {
+ "tslib": "^2.4.0"
+ }
+ }
+ }
+ },
"graphql-type-json": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/graphql-type-json/-/graphql-type-json-0.3.2.tgz",
@@ -13644,6 +14020,15 @@
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
},
+ "hoist-non-react-statics": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+ "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+ "optional": true,
+ "requires": {
+ "react-is": "^16.7.0"
+ }
+ },
"hpagent": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/hpagent/-/hpagent-0.1.2.tgz",
@@ -15240,7 +15625,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
+ "devOptional": true
},
"js-yaml": {
"version": "3.14.1",
@@ -15515,6 +15900,15 @@
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
},
+ "loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "optional": true,
+ "requires": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ }
+ },
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
@@ -15814,6 +16208,27 @@
"integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==",
"dev": true
},
+ "optimism": {
+ "version": "0.16.1",
+ "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.16.1.tgz",
+ "integrity": "sha512-64i+Uw3otrndfq5kaoGNoY7pvOhSsjFEN4bdEFh80MWVk/dbgJfMv7VFDeCT8LxNAlEVhQmdVEbfE7X2nWNIIg==",
+ "optional": true,
+ "requires": {
+ "@wry/context": "^0.6.0",
+ "@wry/trie": "^0.3.0"
+ },
+ "dependencies": {
+ "@wry/context": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.6.1.tgz",
+ "integrity": "sha512-LOmVnY1iTU2D8tv4Xf6MVMZZ+juIJ87Kt/plMijjN20NMAXGmH4u8bS1t0uT74cZ5gwpocYueV58YwyI8y+GKw==",
+ "optional": true,
+ "requires": {
+ "tslib": "^2.3.0"
+ }
+ }
+ }
+ },
"optionator": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
@@ -16097,6 +16512,17 @@
"sisteransi": "^1.0.5"
}
},
+ "prop-types": {
+ "version": "15.8.1",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
+ "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
+ "optional": true,
+ "requires": {
+ "loose-envify": "^1.4.0",
+ "object-assign": "^4.1.1",
+ "react-is": "^16.13.1"
+ }
+ },
"proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@@ -16146,6 +16572,12 @@
"unpipe": "1.0.0"
}
},
+ "react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "optional": true
+ },
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
@@ -16283,6 +16715,12 @@
"integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==",
"dev": true
},
+ "response-iterator": {
+ "version": "0.2.6",
+ "resolved": "https://registry.npmjs.org/response-iterator/-/response-iterator-0.2.6.tgz",
+ "integrity": "sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw==",
+ "optional": true
+ },
"retry": {
"version": "0.13.1",
"resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
@@ -16574,6 +17012,12 @@
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true
},
+ "symbol-observable": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz",
+ "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==",
+ "optional": true
+ },
"tar-stream": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
@@ -16645,6 +17089,15 @@
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
+ "ts-invariant": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.10.3.tgz",
+ "integrity": "sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==",
+ "optional": true,
+ "requires": {
+ "tslib": "^2.1.0"
+ }
+ },
"ts-jest": {
"version": "29.0.3",
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz",
@@ -17009,6 +17462,21 @@
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
"dev": true
},
+ "zen-observable": {
+ "version": "0.8.15",
+ "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz",
+ "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==",
+ "optional": true
+ },
+ "zen-observable-ts": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.2.5.tgz",
+ "integrity": "sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg==",
+ "optional": true,
+ "requires": {
+ "zen-observable": "0.8.15"
+ }
+ },
"zlib": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/zlib/-/zlib-1.0.5.tgz",
diff --git a/modules/server/package.json b/modules/server/package.json
index 671a97682..04a41bc74 100644
--- a/modules/server/package.json
+++ b/modules/server/package.json
@@ -51,6 +51,7 @@
"graphql-middleware": "^6.1.33",
"graphql-playground-middleware-express": "^1.7.23",
"graphql-scalars": "^1.19.0",
+ "graphql-tools": "^8.3.8",
"graphql-type-json": "^0.3.2",
"jsonpath": "^1.1.1",
"lodash": "^4.17.21",
@@ -75,6 +76,7 @@
"@babel/preset-typescript": "^7.18.6",
"@babel/register": "^7.18.9",
"@types/convert-units": "^2.3.5",
+ "@types/graphql-fields": "^1.3.4",
"@types/jest": "^29.1.2",
"@types/lodash": "^4.14.186",
"@types/morgan": "^1.9.3",
diff --git a/modules/server/src/mapping/__tests__/resolveHits/hitsToEdges.test.js b/modules/server/src/mapping/__tests__/resolveHits/hitsToEdges.test.js
index 156a0ced8..21c38bcb3 100644
--- a/modules/server/src/mapping/__tests__/resolveHits/hitsToEdges.test.js
+++ b/modules/server/src/mapping/__tests__/resolveHits/hitsToEdges.test.js
@@ -1,16 +1,18 @@
-import hits from './mockData/wrangledHits.json';
-import nestedFields from './mockData/nestedFields.json';
-import expectedEdges from './mockData/wrangledExpectedEdges.json';
-import { hitsToEdges } from '../../resolveHits';
import Parallel from 'paralleljs';
+import { hitsToEdges } from '../../resolveHits';
+
+import nestedFieldNames from './mockData/nestedFieldNames.json';
+import expectedEdges from './mockData/wrangledExpectedEdges.json';
+import hits from './mockData/wrangledHits.json';
+
test('hitsToEdges should be acurate', async () => {
- const edges = await hitsToEdges({ hits, nestedFields, Parallel });
+ const edges = await hitsToEdges({ hits, nestedFieldNames, Parallel });
expect(edges).toEqual(expectedEdges);
});
test('hitsToEdges should not block process', async () => {
let complete = false;
- hitsToEdges({ hits, nestedFields, Parallel }).then(() => (complete = true));
+ hitsToEdges({ hits, nestedFieldNames, Parallel }).then(() => (complete = true));
expect(complete).toEqual(false);
});
diff --git a/modules/server/src/mapping/__tests__/resolveHits/mockData/nestedFields.json b/modules/server/src/mapping/__tests__/resolveHits/mockData/nestedFieldNames.json
similarity index 100%
rename from modules/server/src/mapping/__tests__/resolveHits/mockData/nestedFields.json
rename to modules/server/src/mapping/__tests__/resolveHits/mockData/nestedFieldNames.json
diff --git a/modules/server/src/mapping/resolveHits.js b/modules/server/src/mapping/resolveHits.js
index 6b60c54f7..b07bf5b42 100644
--- a/modules/server/src/mapping/resolveHits.js
+++ b/modules/server/src/mapping/resolveHits.js
@@ -1,9 +1,11 @@
import getFields from 'graphql-fields';
import { chunk } from 'lodash';
-import { buildQuery } from '../middleware';
+import { buildQuery } from '@/middleware';
+
import compileFilter from './utils/compileFilter';
import esSearch from './utils/esSearch';
+import loadExtendedFields from './utils/loadExtendedFields';
const findCopyToSourceFields = (mapping, path = '', results = {}) => {
Object.entries(mapping).forEach(([k, v]) => {
@@ -19,12 +21,21 @@ const findCopyToSourceFields = (mapping, path = '', results = {}) => {
};
export const hitsToEdges = ({
+ copyToSourceFields = {},
+ extendedFields = [],
hits,
nestedFieldNames,
Parallel,
- copyToSourceFields = {},
systemCores = process?.env?.SYSTEM_CORES || 2,
}) => {
+ const extendedFieldsObj = extendedFields.reduce(
+ (acc, field) => ({
+ ...acc,
+ [field.fieldName]: field,
+ }),
+ {},
+ );
+
/*
If there's a large request, we'll trigger ludicrous mode and do some parallel
map-reduce based on # of cores available. Otherwise, only one child-process
@@ -40,8 +51,8 @@ export const hitsToEdges = ({
(chunk) =>
//Parallel.spawn output has a .then but it's not returning an actual promise
new Promise((resolve) => {
- new Parallel({ hits: chunk, nestedFieldNames, copyToSourceFields })
- .spawn(({ hits, nestedFieldNames, copyToSourceFields }) => {
+ new Parallel({ copyToSourceFields, extendedFieldsObj, hits: chunk, nestedFieldNames })
+ .spawn(({ copyToSourceFields, extendedFieldsObj, hits, nestedFieldNames }) => {
/*
everthing inside spawn is executed in a separate thread, so we have
to use good old ES5 and require for run-time dependecy bundling.
@@ -77,7 +88,12 @@ export const hitsToEdges = ({
parent ? `${parent}.${fieldName}` : fieldName;
const resolveNested = ({ node, nestedFieldNames, parent = '' }) => {
- if (!isObject(node) || !node) return node;
+ if (!isObject(node) || !node) {
+ // Backwards compatibility for Array fields when data has not been migrated
+ return extendedFieldsObj?.[parent]?.isArray && !Array.isArray(node)
+ ? [node]
+ : node;
+ }
return Object.entries(node).reduce((acc, entry) => {
const fieldName = entry[0];
@@ -86,7 +102,7 @@ export const hitsToEdges = ({
// TODO: inner hits query if necessary
const fullPath = joinParent(parent, fieldName);
- acc[fieldName] = nestedFieldNames.includes(fullPath)
+ acc[fieldName] = nestedFieldNames?.includes(fullPath)
? {
hits: {
edges: hits.map((node) => ({
@@ -167,6 +183,7 @@ export default ({ type, Parallel, getServerSideFilter }) =>
let nestedFieldNames = type.nested_fields;
const { esClient } = context;
+ const { extendedFields } = type;
/**
* @todo: I left this chunk here for reference, in case someone actually understands what it actually is trying to do
@@ -246,10 +263,11 @@ export default ({ type, Parallel, getServerSideFilter }) =>
return {
edges: () =>
hitsToEdges({
+ copyToSourceFields,
+ extendedFields,
hits,
nestedFieldNames,
Parallel,
- copyToSourceFields,
}),
total: () => hits.total.value,
};
diff --git a/modules/server/src/mapping/utils/loadExtendedFields.js b/modules/server/src/mapping/utils/loadExtendedFields.js
index a055e281a..f990df84a 100644
--- a/modules/server/src/mapping/utils/loadExtendedFields.js
+++ b/modules/server/src/mapping/utils/loadExtendedFields.js
@@ -1,22 +1,11 @@
-import mapHits from './mapHits';
import { get } from 'lodash';
+
import esSearch from './esSearch';
+import mapHits from './mapHits';
export default async ({ esClient, index }) => {
try {
- const {
- hits: { total },
- } = await esSearch(esClient)({
- index,
- size: 0,
- _source: false,
- });
- const fields = mapHits(
- await esSearch(esClient)({
- index,
- size: total,
- }),
- );
+ const fields = mapHits(await esSearch(esClient)({ index }));
return fields;
} catch (err) {
const metaData = await esSearch(esClient)({ index });
diff --git a/modules/server/src/mapping/utils/mapHits.ts b/modules/server/src/mapping/utils/mapHits.ts
index 9194e8cb1..1765d941d 100644
--- a/modules/server/src/mapping/utils/mapHits.ts
+++ b/modules/server/src/mapping/utils/mapHits.ts
@@ -1,4 +1,4 @@
import { RequestEvent } from '@elastic/elasticsearch';
export default (esIndexResponseBody: RequestEvent['body']) =>
- esIndexResponseBody.hits.hits.map((hit: any) => hit._source);
+ esIndexResponseBody.hits.hits.map((hit: any) => hit?._source);
diff --git a/modules/server/src/middleware/buildQuery/index.js b/modules/server/src/middleware/buildQuery/index.js
index 08f85d11f..1c18bbbf3 100644
--- a/modules/server/src/middleware/buildQuery/index.js
+++ b/modules/server/src/middleware/buildQuery/index.js
@@ -292,6 +292,7 @@ export const opSwitch = ({ nestedFields, filter }) => {
export default function ({ nestedFields, filters: rawFilters }) {
if (Object.keys(rawFilters || {}).length === 0) return {};
+
return opSwitch({
nestedFields,
filter: normalizeFilters(rawFilters),
diff --git a/modules/server/src/utils/dataToExportFormat.js b/modules/server/src/utils/dataToExportFormat.js
index d9df6598e..a94e947a4 100644
--- a/modules/server/src/utils/dataToExportFormat.js
+++ b/modules/server/src/utils/dataToExportFormat.js
@@ -13,7 +13,9 @@ const getAllValue = (data) => {
};
const getValue = (row, column) => {
- const valueFromExtended = (value) => (column.displayValues || {})[value] || value;
+ const valueFromExtended = (value) =>
+ (column.extendedDisplayValues || {})[value] || column.isArray ? value.join(';') : value;
+
if (column.jsonPath) {
return jsonPath
.query(row, column.jsonPath.split('.hits.edges[*].node.').join('[*].'))
diff --git a/package.json b/package.json
index aa5539b09..f111af349 100644
--- a/package.json
+++ b/package.json
@@ -77,7 +77,9 @@
"prettier": {
"printWidth": 100,
"trailingComma": "all",
- "singleQuote": true
+ "semi": true,
+ "singleQuote": true,
+ "useTabs": true
},
"husky": {
"hooks": {