@blaze-cms/plugin-data-ui 0.146.0-node18-tooltips.44 → 0.146.0-node18-core-styles-tooltips.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"get-default-query-params.js","names":["getDefaultQueryParams","schema","updated","properties","adminDefaultListingFilter","where","displayProperties","limit","offset","sort","property","direction"],"sources":["../../src/utils/get-default-query-params.js"],"sourcesContent":["const getDefaultQueryParams = schema => {\n const updated = schema.properties && schema.properties.updated;\n const { adminDefaultListingFilter: where } = schema.displayProperties || {};\n\n return {\n where,\n limit: 10,\n offset: 0,\n sort: updated\n ? [\n {\n property: 'updated',\n direction: 'desc'\n }\n ]\n : []\n };\n};\n\nexport { getDefaultQueryParams };\n"],"mappings":"AAAA,MAAMA,qBAAqB,GAAGC,MAAM,IAAI;EACtC,MAAMC,OAAO,GAAGD,MAAM,CAACE,UAAU,IAAIF,MAAM,CAACE,UAAU,CAACD,OAAO;EAC9D,MAAM;IAAEE,yBAAyB,EAAEC;EAAM,CAAC,GAAGJ,MAAM,CAACK,iBAAiB,IAAI,CAAC,CAAC;EAE3E,OAAO;IACLD,KAAK;IACLE,KAAK,EAAE,EAAE;IACTC,MAAM,EAAE,CAAC;IACTC,IAAI,EAAEP,OAAO,GACT,CACE;MACEQ,QAAQ,EAAE,SAAS;MACnBC,SAAS,EAAE;IACb,CAAC,CACF,GACD;EACN,CAAC;AACH,CAAC;AAED,SAASX,qBAAqB","ignoreList":[]}
1
+ {"version":3,"file":"get-default-query-params.js","names":["getDefaultQueryParams","schema","updated","properties","adminDefaultListingFilter","where","adminListings","defaultSort","displayProperties","sort","property","direction","limit","offset"],"sources":["../../src/utils/get-default-query-params.js"],"sourcesContent":["const getDefaultQueryParams = schema => {\n const updated = schema.properties && schema.properties.updated;\n const { adminDefaultListingFilter: where, adminListings: { defaultSort } = {} } =\n schema.displayProperties || {};\n\n let sort = [];\n\n if (defaultSort?.property) {\n sort = [\n {\n property: defaultSort.property,\n direction: defaultSort.direction || 'asc'\n }\n ];\n } else if (updated) {\n sort = [\n {\n property: 'updated',\n direction: 'desc'\n }\n ];\n }\n\n return {\n where,\n limit: 10,\n offset: 0,\n sort\n };\n};\n\nexport { getDefaultQueryParams };\n"],"mappings":"AAAA,MAAMA,qBAAqB,GAAGC,MAAM,IAAI;EACtC,MAAMC,OAAO,GAAGD,MAAM,CAACE,UAAU,IAAIF,MAAM,CAACE,UAAU,CAACD,OAAO;EAC9D,MAAM;IAAEE,yBAAyB,EAAEC,KAAK;IAAEC,aAAa,EAAE;MAAEC;IAAY,CAAC,GAAG,CAAC;EAAE,CAAC,GAC7EN,MAAM,CAACO,iBAAiB,IAAI,CAAC,CAAC;EAEhC,IAAIC,IAAI,GAAG,EAAE;EAEb,IAAIF,WAAW,aAAXA,WAAW,uBAAXA,WAAW,CAAEG,QAAQ,EAAE;IACzBD,IAAI,GAAG,CACL;MACEC,QAAQ,EAAEH,WAAW,CAACG,QAAQ;MAC9BC,SAAS,EAAEJ,WAAW,CAACI,SAAS,IAAI;IACtC,CAAC,CACF;EACH,CAAC,MAAM,IAAIT,OAAO,EAAE;IAClBO,IAAI,GAAG,CACL;MACEC,QAAQ,EAAE,SAAS;MACnBC,SAAS,EAAE;IACb,CAAC,CACF;EACH;EAEA,OAAO;IACLN,KAAK;IACLO,KAAK,EAAE,EAAE;IACTC,MAAM,EAAE,CAAC;IACTJ;EACF,CAAC;AACH,CAAC;AAED,SAAST,qBAAqB","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blaze-cms/plugin-data-ui",
3
- "version": "0.146.0-node18-tooltips.44",
3
+ "version": "0.146.0-node18-core-styles-tooltips.60",
4
4
  "description": "Blaze plugin data ui",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib-es/index.js",
@@ -27,13 +27,13 @@
27
27
  },
28
28
  "license": "GPL-3.0",
29
29
  "dependencies": {
30
- "@blaze-cms/admin-ui-utils": "0.146.0-node18-tooltips.44",
31
- "@blaze-cms/core-errors": "0.146.0-node18-tooltips.0",
32
- "@blaze-cms/plugin-render-hooks-ui": "0.146.0-node18-tooltips.0",
33
- "@blaze-cms/react-form-builder": "0.146.0-node18-tooltips.44",
34
- "@blaze-cms/react-page-builder": "0.146.0-node18-tooltips.44",
35
- "@blaze-cms/setup-ui": "0.146.0-node18-tooltips.0",
36
- "@blaze-cms/versioning-ui": "0.146.0-node18-tooltips.37",
30
+ "@blaze-cms/admin-ui-utils": "0.146.0-node18-core-styles-tooltips.60",
31
+ "@blaze-cms/core-errors": "0.146.0-node18-core-styles-tooltips.46",
32
+ "@blaze-cms/plugin-render-hooks-ui": "0.146.0-node18-core-styles-tooltips.46",
33
+ "@blaze-cms/react-form-builder": "0.146.0-node18-core-styles-tooltips.60",
34
+ "@blaze-cms/react-page-builder": "0.146.0-node18-core-styles-tooltips.60",
35
+ "@blaze-cms/setup-ui": "0.146.0-node18-core-styles-tooltips.46",
36
+ "@blaze-cms/versioning-ui": "0.146.0-node18-core-styles-tooltips.46",
37
37
  "@blaze-react/button": "0.8.0-alpha.82",
38
38
  "@blaze-react/more": "0.5.19",
39
39
  "@blaze-react/multiselect": "0.8.0-alpha.108",
@@ -57,7 +57,7 @@
57
57
  "uuid": "^3.3.3"
58
58
  },
59
59
  "devDependencies": {
60
- "@blaze-cms/core-ui": "0.146.0-node18-tooltips.44"
60
+ "@blaze-cms/core-ui": "0.146.0-node18-core-styles-tooltips.58"
61
61
  },
62
62
  "peerDependencies": {
63
63
  "@apollo/client": "3.x",
@@ -69,5 +69,5 @@
69
69
  "lib/*",
70
70
  "lib-es/*"
71
71
  ],
72
- "gitHead": "952edd6c8a27c44508a3e4989222f72631e2e093"
72
+ "gitHead": "447a75ee4bcd2cbbf2ed3fab689d5d0533f3b76e"
73
73
  }
@@ -0,0 +1,158 @@
1
+ import React, { useState, useEffect, useMemo } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import MultiSelect from '@blaze-react/multiselect';
4
+ import debounce from 'lodash.debounce';
5
+ import unionBy from 'lodash.unionby';
6
+ import { useApolloClient } from '@apollo/client';
7
+ import {
8
+ getQuery,
9
+ getDynamicQuery,
10
+ getAdminRecordSearch,
11
+ buildLabel
12
+ } from '@blaze-cms/admin-ui-utils';
13
+
14
+ const DEBOUNCE_TIME = 500;
15
+ const SEARCH_LOAD_OFFSET = 10;
16
+ const SELECTION_LIMIT = 10;
17
+
18
+ const shouldLoadMore = (searchTerm, stopIndex, currentDataLength) =>
19
+ searchTerm &&
20
+ stopIndex > SEARCH_LOAD_OFFSET &&
21
+ stopIndex >= currentDataLength - SEARCH_LOAD_OFFSET;
22
+
23
+ const RelationMultiSelectFilter = ({ id, label, entityIdentifier, selectedIds, onChange }) => {
24
+ const client = useApolloClient();
25
+ const [schema, setSchema] = useState(null);
26
+ const [data, setData] = useState([]);
27
+ const [searchTerm, setSearchTerm] = useState('');
28
+
29
+ const { displayProperties } = schema || {};
30
+
31
+ useEffect(() => {
32
+ let active = true;
33
+ (async () => {
34
+ try {
35
+ const { data: { getEntitySchemas = [] } = {} } = await client.query({
36
+ query: getQuery('GET_ENTITY_SCHEMA'),
37
+ variables: { identifier: entityIdentifier }
38
+ });
39
+ const [relationSchema] = getEntitySchemas;
40
+ if (active && relationSchema) setSchema(relationSchema);
41
+ } catch {
42
+ if (active) setSchema(null);
43
+ }
44
+ })();
45
+ return () => {
46
+ active = false;
47
+ };
48
+ }, [client, entityIdentifier]);
49
+
50
+ useEffect(() => {
51
+ if (!schema || !selectedIds.length) return undefined;
52
+ let active = true;
53
+ (async () => {
54
+ try {
55
+ const { data: { result = [] } = {} } = await client.query({
56
+ query: getDynamicQuery('GET_ALL_ENTITIES')(schema),
57
+ variables: {
58
+ where: { id: { _in: selectedIds } },
59
+ sort: [{ property: 'name', direction: 'asc' }]
60
+ }
61
+ });
62
+ if (active && result.length) setData(prev => unionBy([...prev, ...result], 'id'));
63
+ } catch {
64
+ // ignore - selected chips will fall back to id-only display
65
+ }
66
+ })();
67
+ return () => {
68
+ active = false;
69
+ };
70
+ // eslint-disable-next-line react-hooks/exhaustive-deps
71
+ }, [schema]);
72
+
73
+ const onSearch = useMemo(
74
+ () => (schema ? getAdminRecordSearch(schema, client) : null),
75
+ [schema, client]
76
+ );
77
+
78
+ const currentData = useMemo(
79
+ () =>
80
+ data.map(option => {
81
+ const checked = selectedIds.includes(option.id);
82
+ return {
83
+ ...option,
84
+ checked,
85
+ show: !checked,
86
+ name: buildLabel(displayProperties, option)
87
+ };
88
+ }),
89
+ [data, selectedIds, displayProperties]
90
+ );
91
+
92
+ const interceptOnSearchChange = debounce(async ({ value }) => {
93
+ setSearchTerm(value);
94
+ if (!onSearch) return;
95
+ const result = await onSearch({ event: { value }, currentValue: selectedIds });
96
+ if (!result) return;
97
+ setData(prev => {
98
+ const selected = prev.filter(item => selectedIds.includes(item.id));
99
+ const newOnes = result.filter(item => !selectedIds.includes(item.id));
100
+ return unionBy([...selected, ...newOnes], 'id');
101
+ });
102
+ }, DEBOUNCE_TIME);
103
+
104
+ const scrollHook = debounce(async ({ stopIndex }) => {
105
+ if (!onSearch) return;
106
+ const currentDataLength = data.length - selectedIds.length;
107
+ if (!shouldLoadMore(searchTerm, stopIndex, currentDataLength)) return;
108
+ const result = await onSearch({
109
+ event: { value: searchTerm },
110
+ currentValue: selectedIds,
111
+ currentOffset: currentDataLength
112
+ });
113
+ if (!result || !result.length) return;
114
+ setData(prev => unionBy([...prev, ...result], 'id'));
115
+ }, DEBOUNCE_TIME);
116
+
117
+ const onItemsRenderedIntercept = async event => {
118
+ if (!onSearch) return;
119
+ scrollHook(event);
120
+ };
121
+
122
+ const getSelected = ({
123
+ event: {
124
+ target: { value }
125
+ }
126
+ }) => onChange(id, value);
127
+
128
+ return (
129
+ <MultiSelect
130
+ label={label}
131
+ name={id}
132
+ data={{ data: currentData, filterBy: ['name'], identification: 'id', keyValue: 'name' }}
133
+ limit={SELECTION_LIMIT}
134
+ onChange={interceptOnSearchChange}
135
+ getSelected={getSelected}
136
+ onItemsRendered={onItemsRenderedIntercept}
137
+ required={false}
138
+ checkedPreviewCount={1}
139
+ formatMoreLabel={count => `${count} more`}
140
+ isDynamic
141
+ />
142
+ );
143
+ };
144
+
145
+ RelationMultiSelectFilter.propTypes = {
146
+ id: PropTypes.string.isRequired,
147
+ label: PropTypes.string,
148
+ entityIdentifier: PropTypes.string.isRequired,
149
+ selectedIds: PropTypes.array,
150
+ onChange: PropTypes.func.isRequired
151
+ };
152
+
153
+ RelationMultiSelectFilter.defaultProps = {
154
+ label: '',
155
+ selectedIds: []
156
+ };
157
+
158
+ export default RelationMultiSelectFilter;
@@ -16,6 +16,7 @@ import { getStringTypeProps } from '@blaze-cms/utils';
16
16
 
17
17
  import { BsArrowCounterclockwise, BsSearch } from 'react-icons/bs';
18
18
  import { updateListFilters, buildQueryFields, getTidyLabel } from './helpers';
19
+ import RelationMultiSelectFilter from './RelationMultiSelectFilter';
19
20
  import { NOOP_QUERY } from './querys';
20
21
  import { ENTER_KEY, DEFAULT_FILTER_OPTION_LABEL } from '../../../constants';
21
22
 
@@ -57,6 +58,16 @@ const SearchContainer = ({
57
58
  [multiSelectFiltersToDisplay]
58
59
  );
59
60
 
61
+ const relationMultiSelectFilters = useMemo(
62
+ () => multiSelectFiltersToDisplay.filter(([, config]) => config && config.relation),
63
+ [multiSelectFiltersToDisplay]
64
+ );
65
+
66
+ const nonRelationMultiSelectFilters = useMemo(
67
+ () => multiSelectFiltersToDisplay.filter(([, config]) => !config || !config.relation),
68
+ [multiSelectFiltersToDisplay]
69
+ );
70
+
60
71
  const { keywordSearchProperties, keywordSearchLabels } = useMemo(() => {
61
72
  const labels = [];
62
73
  const properties = [];
@@ -70,8 +81,9 @@ const SearchContainer = ({
70
81
  }, [keywordFiltersToUse]);
71
82
 
72
83
  const { gqlFields, rawQuery } = useMemo(
73
- () => buildQueryFields([...selectFiltersToDisplay, ...multiSelectFiltersToDisplay], schema.id),
74
- [selectFiltersToDisplay, multiSelectFiltersToDisplay, schema.id]
84
+ () =>
85
+ buildQueryFields([...selectFiltersToDisplay, ...nonRelationMultiSelectFilters], schema.id),
86
+ [selectFiltersToDisplay, nonRelationMultiSelectFilters, schema.id]
75
87
  );
76
88
 
77
89
  const action = displayAggregations
@@ -492,6 +504,27 @@ const SearchContainer = ({
492
504
  );
493
505
  })}
494
506
 
507
+ {relationMultiSelectFilters.map(([property, config]) => {
508
+ const entityIdentifier =
509
+ resolveEntityIdentifier(property, config) || config.relation?.entityIdentifier;
510
+
511
+ if (!entityIdentifier) return null;
512
+
513
+ return (
514
+ <div
515
+ className="search-container__select-wrapper"
516
+ key={`relation-multiselect-${property}`}>
517
+ <RelationMultiSelectFilter
518
+ id={property}
519
+ label={config.label || config.relation.label}
520
+ entityIdentifier={entityIdentifier}
521
+ selectedIds={selectedFilters[property] || []}
522
+ onChange={handleMultiSelect}
523
+ />
524
+ </div>
525
+ );
526
+ })}
527
+
495
528
  <div className="search-container__reset-button">
496
529
  <span role="button" onClick={handleReset}>
497
530
  <BsArrowCounterclockwise />
@@ -75,9 +75,8 @@ const findMultiSelectFilters = schema => {
75
75
 
76
76
  const { properties = {}, dynamicProperties = {} } = schema;
77
77
  const propertyMultiSelect = Object.entries(properties).filter(isFilterMultiSelectItems);
78
- const dynamicPropertyMultiSelect = Object.entries(dynamicProperties).filter(
79
- isFilterMultiSelectItems
80
- );
78
+ const dynamicPropertyMultiSelect =
79
+ Object.entries(dynamicProperties).filter(isFilterMultiSelectItems);
81
80
  return [...propertyMultiSelect, ...dynamicPropertyMultiSelect];
82
81
  };
83
82
 
@@ -1,19 +1,31 @@
1
1
  const getDefaultQueryParams = schema => {
2
2
  const updated = schema.properties && schema.properties.updated;
3
- const { adminDefaultListingFilter: where } = schema.displayProperties || {};
3
+ const { adminDefaultListingFilter: where, adminListings: { defaultSort } = {} } =
4
+ schema.displayProperties || {};
5
+
6
+ let sort = [];
7
+
8
+ if (defaultSort?.property) {
9
+ sort = [
10
+ {
11
+ property: defaultSort.property,
12
+ direction: defaultSort.direction || 'asc'
13
+ }
14
+ ];
15
+ } else if (updated) {
16
+ sort = [
17
+ {
18
+ property: 'updated',
19
+ direction: 'desc'
20
+ }
21
+ ];
22
+ }
4
23
 
5
24
  return {
6
25
  where,
7
26
  limit: 10,
8
27
  offset: 0,
9
- sort: updated
10
- ? [
11
- {
12
- property: 'updated',
13
- direction: 'desc'
14
- }
15
- ]
16
- : []
28
+ sort
17
29
  };
18
30
  };
19
31