@guillotinaweb/react-gmi 0.29.0 → 0.29.2-alpha.2

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.
@@ -92,6 +92,7 @@ class Traversal {
92
92
  }
93
93
 
94
94
  apply(data) {
95
+ // apply a optimistic update to context
95
96
  this.dispatch({
96
97
  type: 'APPLY',
97
98
  payload: data
@@ -682,8 +683,10 @@ function base64ToArrayBuffer(base64) {
682
683
  return bytes;
683
684
  }
684
685
  function stringToSlug(str) {
685
- str = str.replace(/^\s+|\s+$/g, '');
686
- str = str.toLowerCase();
686
+ str = str.replace(/^\s+|\s+$/g, ''); // trim
687
+
688
+ str = str.toLowerCase(); // remove accents, swap ñ for n, etc
689
+
687
690
  const from = 'àáäâèéëêìíïîòóöôùúüûñç·/_,:;';
688
691
  const to = 'aaaaeeeeiiiioooouuuunc------';
689
692
 
@@ -691,7 +694,10 @@ function stringToSlug(str) {
691
694
  str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i));
692
695
  }
693
696
 
694
- str = str.replace(/[^a-z0-9 -]/g, '').replace(/\s+/g, '-').replace(/-+/g, '-');
697
+ str = str.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
698
+ .replace(/\s+/g, '-') // collapse whitespace and replace by -
699
+ .replace(/-+/g, '-'); // collapse dashes
700
+
695
701
  return str;
696
702
  }
697
703
  function sleep(ms) {
@@ -814,7 +820,8 @@ function Confirm({
814
820
  })]
815
821
  })]
816
822
  });
817
- }
823
+ } // @todo Improve it... Replacing the inputText to a tree
824
+
818
825
  function PathTree({
819
826
  title,
820
827
  defaultPath,
@@ -1062,6 +1069,7 @@ const Config = {
1062
1069
  DelayActions: 200,
1063
1070
  Permissions: Permissions,
1064
1071
  SearchEngine: 'PostreSQL',
1072
+ // Elasticsearch
1065
1073
  fieldHaveDeleteButton: schema => {
1066
1074
  return (schema == null ? void 0 : schema.widget) === 'file' || (schema == null ? void 0 : schema.widget) === 'select' || (schema == null ? void 0 : schema.type) === 'array';
1067
1075
  }
@@ -1113,7 +1121,9 @@ function RemoveItems(props) {
1113
1121
  const err = await res.json();
1114
1122
  errors.push(err);
1115
1123
  }
1116
- });
1124
+ }); // this sleep is here, to let elasticsearch, wait for
1125
+ // index our operations... (will work 99% of use cases)
1126
+
1117
1127
  actions.push(sleep(cfg.DelayActions));
1118
1128
  await Promise.all(actions);
1119
1129
 
@@ -1257,6 +1267,9 @@ const useInput = (onChange, value, validator) => {
1257
1267
  };
1258
1268
  };
1259
1269
 
1270
+ // From github.com/protonmail/proton-shared
1271
+
1272
+ /* eslint-disable no-useless-escape */
1260
1273
  const REGEX_EMAIL = /(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/i;
1261
1274
  const REGEX_URL = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)/;
1262
1275
  const REGEX_HEX_COLOR = /^#([a-f0-9]{3,4}|[a-f0-9]{4}(?:[a-f0-9]{2}){1,2})\b$/i;
@@ -1307,7 +1320,8 @@ const Input = forwardRef(({
1307
1320
  handlers = _objectWithoutPropertiesLoose(_useInput, ["state"]);
1308
1321
 
1309
1322
  const [uid] = useState(generateUID('input'));
1310
- const [mounted, setMounted] = useState(false);
1323
+ const [mounted, setMounted] = useState(false); // eslint-disable-next-line
1324
+
1311
1325
  ref = ref || useRef();
1312
1326
  useEffect(() => {
1313
1327
  setMounted(true);
@@ -1372,7 +1386,8 @@ const EmailInput = ({
1372
1386
  value: _value = '',
1373
1387
  dataTest,
1374
1388
  placeholder,
1375
- id
1389
+ id,
1390
+ onChange
1376
1391
  }) => {
1377
1392
  const intl = useIntl();
1378
1393
  return jsx(Input, {
@@ -1391,7 +1406,8 @@ const EmailInput = ({
1391
1406
  icon: "fas fa-envelope"
1392
1407
  }),
1393
1408
  id: id,
1394
- placeholder: placeholder
1409
+ placeholder: placeholder,
1410
+ onChange: onChange
1395
1411
  });
1396
1412
  };
1397
1413
 
@@ -1466,17 +1482,19 @@ function FormBuilder({
1466
1482
  properties,
1467
1483
  required
1468
1484
  } = schema;
1469
- const values = Object.assign({}, formData || {});
1485
+ const values = Object.assign({}, formData || {}); // build initial state
1486
+
1470
1487
  const initialState = {};
1471
1488
  const fields = Object.keys(properties).filter(x => !exclude.includes(x));
1472
1489
  fields.forEach(element => {
1473
1490
  initialState[element] = values[element] || undefined;
1474
- });
1491
+ }); // Register remotes
1475
1492
 
1476
1493
  if (!ref.current) {
1477
1494
  ref.current = {};
1478
1495
  Object.keys(remotes).forEach(item => ref.current[item] = remotes[item]);
1479
1496
  } else {
1497
+ // apply remote changes
1480
1498
  Object.keys(remotes).forEach(key => {
1481
1499
  if (JSON.stringify(ref.current[key]) !== JSON.stringify(remotes[key])) {
1482
1500
  ref.current[key] = remotes[key];
@@ -1621,128 +1639,7 @@ const Select = forwardRef(({
1621
1639
  });
1622
1640
  Select.displayName = 'Select';
1623
1641
 
1624
- const formatDate = str => {
1625
- const d = new Date(str);
1626
- const minutes = d.getMinutes() < 10 ? `0${d.getMinutes()}` : d.getMinutes();
1627
- return `${d.getDate()}/${d.getMonth() + 1}/${d.getFullYear()} ${d.getHours()}:${minutes}`;
1628
- };
1629
- const get$1 = (obj, path, defValue) => {
1630
- var _pathArray$reduce;
1631
-
1632
- if (!path) return undefined;
1633
- const pathArray = Array.isArray(path) ? path : path.match(/([^[.\]])+/g);
1634
- return (_pathArray$reduce = pathArray.reduce((prevObj, key) => prevObj && prevObj[key], obj)) != null ? _pathArray$reduce : defValue;
1635
- };
1636
- function getNewId(id = '') {
1637
- const suffix = '-copy-';
1638
- const rgx = new RegExp(`($|${suffix}\\d*)`);
1639
- return stringToSlug(id).replace(rgx, r => {
1640
- const num = parseInt(r.replace(suffix, '') || '0');
1641
- return `${suffix}${num + 1}`;
1642
- });
1643
- }
1644
-
1645
- function useVocabulary(vocabularyName, path = null) {
1646
- const traversal = useTraversal();
1647
- const [vocabulary, setVocabulary] = useSetState({
1648
- data: undefined,
1649
- loading: false,
1650
- error: undefined
1651
- });
1652
-
1653
- const getPath = () => {
1654
- if (path) return path;
1655
- return `${traversal.path}@vocabularies/${vocabularyName}`;
1656
- };
1657
-
1658
- useEffect(() => {
1659
- const getVocabulary = async () => {
1660
- if (vocabularyName && vocabulary.data === undefined && !vocabulary.loading) {
1661
- try {
1662
- setVocabulary({
1663
- loading: true
1664
- });
1665
- const data = await traversal.client.get(getPath());
1666
- const dataJson = await data.json();
1667
- setVocabulary({
1668
- loading: false,
1669
- data: dataJson
1670
- });
1671
- } catch (err) {
1672
- setVocabulary({
1673
- loading: false,
1674
- error: err,
1675
- data: undefined
1676
- });
1677
- }
1678
- }
1679
- };
1680
-
1681
- getVocabulary();
1682
- }, [vocabularyName, vocabulary, path]);
1683
- return vocabulary;
1684
- }
1685
-
1686
- const SelectVocabulary = forwardRef(({
1687
- vocabularyName,
1688
- className,
1689
- classWrap,
1690
- val,
1691
- dataTest,
1692
- multiple,
1693
- onChange,
1694
- id,
1695
- placeholder
1696
- }, ref) => {
1697
- const vocabulary = useVocabulary(vocabularyName);
1698
-
1699
- const getOptions = () => {
1700
- if (get$1(vocabulary, 'data.items', null)) {
1701
- const vocData = vocabulary.data.items.map(item => {
1702
- return {
1703
- text: item.title,
1704
- value: item.token
1705
- };
1706
- });
1707
- return vocData;
1708
- }
1709
-
1710
- return [];
1711
- };
1712
-
1713
- const getProps = () => {
1714
- if (multiple) {
1715
- const currentValue = val || [];
1716
- return {
1717
- multiple: true,
1718
- size: 5,
1719
- value: currentValue,
1720
- options: getOptions()
1721
- };
1722
- }
1723
-
1724
- return {
1725
- value: val != null ? val : '',
1726
- appendDefault: true,
1727
- options: getOptions()
1728
- };
1729
- };
1730
-
1731
- if (vocabulary.data === undefined || vocabulary.loading) {
1732
- return jsx("div", {});
1733
- }
1734
-
1735
- return jsx(Select, _extends({}, getProps(), {
1736
- className: className,
1737
- classWrap: classWrap || 'is-fullwidth',
1738
- dataTest: dataTest,
1739
- ref: ref,
1740
- onChange: onChange,
1741
- id: id,
1742
- placeholder: placeholder
1743
- }));
1744
- });
1745
- SelectVocabulary.displayName = 'SelectVocabulary';
1642
+ // https://github.com/molefrog/wouter
1746
1643
 
1747
1644
  const setURLParams = p => {
1748
1645
  return window.history.pushState(0, '0', '' + '?' + p.toString().replace(/%2F/g, '/'));
@@ -1758,7 +1655,10 @@ const useLocation = () => {
1758
1655
  const [path, update] = useState(currentSearchParams());
1759
1656
  const prevPath = useRef(path);
1760
1657
  useEffect(() => {
1761
- patchHistoryEvents();
1658
+ patchHistoryEvents(); // this function checks if the location has been changed since the
1659
+ // last render and updates the state only when needed.
1660
+ // unfortunately, we can't rely on `path` value here, since it can be stale,
1661
+ // that's why we store the last pathname in a ref.
1762
1662
 
1763
1663
  const checkForUpdates = () => {
1764
1664
  const pathname = currentSearchParams();
@@ -1766,12 +1666,20 @@ const useLocation = () => {
1766
1666
  };
1767
1667
 
1768
1668
  const events = ['popstate', 'pushState', 'replaceState'];
1769
- events.map(e => window.addEventListener(e, checkForUpdates));
1669
+ events.map(e => window.addEventListener(e, checkForUpdates)); // it's possible that an update has occurred between render and the effect handler,
1670
+ // so we run additional check on mount to catch these updates. Based on:
1671
+ // https://gist.github.com/bvaughn/e25397f70e8c65b0ae0d7c90b731b189
1672
+
1770
1673
  checkForUpdates();
1771
1674
  return () => {
1772
1675
  events.map(e => window.removeEventListener(e, checkForUpdates));
1773
1676
  };
1774
- }, []);
1677
+ }, []); // the 2nd argument of the `useLocation` return value is a function
1678
+ // that allows to perform a navigation.
1679
+ //
1680
+ // the function reference should stay the same between re-renders, so that
1681
+ // it can be passed down as an element prop without any performance concerns.
1682
+
1775
1683
  const navigate = useCallback((to, replace) => {
1776
1684
  if (replace) {
1777
1685
  clean(to);
@@ -1788,7 +1696,12 @@ const useLocation = () => {
1788
1696
  setURLParams(current);
1789
1697
  }, [path]);
1790
1698
  return [path, navigate, remove];
1791
- };
1699
+ }; // While History API does have `popstate` event, the only
1700
+ // proper way to listen to changes via `push/replaceState`
1701
+ // is to monkey-patch these methods.
1702
+ //
1703
+ // See https://stackoverflow.com/a/4585031
1704
+
1792
1705
  let patched = 0;
1793
1706
 
1794
1707
  const patchHistoryEvents = () => {
@@ -1797,7 +1710,8 @@ const patchHistoryEvents = () => {
1797
1710
  const original = window.history[type];
1798
1711
 
1799
1712
  window.history[type] = function (...args) {
1800
- const result = original.apply(this, args);
1713
+ const result = original.apply(this, args); // eslint-disable-next-line @typescript-eslint/no-explicit-any
1714
+
1801
1715
  const event = new Event(type);
1802
1716
  event.arguments = args;
1803
1717
  dispatchEvent(event);
@@ -2232,7 +2146,8 @@ class GuillotinaClient {
2232
2146
  children: m.updated
2233
2147
  })
2234
2148
  }];
2235
- }
2149
+ } // BBB API changes. Compat G5 and G6
2150
+
2236
2151
 
2237
2152
  applyCompat(data) {
2238
2153
  data.member = data.items;
@@ -2320,7 +2235,8 @@ class GuillotinaClient {
2320
2235
 
2321
2236
  async getTypeSchema(path, name) {
2322
2237
  if (!cacheSchemas[name]) {
2323
- const url = this.getContainerFromPath(path);
2238
+ const url = this.getContainerFromPath(path); // todo: handle db case (only addable containers)
2239
+
2324
2240
  const res = await this.rest.get(`${url}@types/${name}`);
2325
2241
  cacheSchemas[name] = await res.json();
2326
2242
  }
@@ -2370,6 +2286,7 @@ class GuillotinaClient {
2370
2286
  }
2371
2287
 
2372
2288
  async getAllPermissions(path) {
2289
+ // paths used to query the API always has to start without a "/"
2373
2290
  if (path.startsWith('/')) {
2374
2291
  path = path.slice(1);
2375
2292
  }
@@ -2554,10 +2471,37 @@ function useClickAway(ref, onClickAway, events = defaultEvents) {
2554
2471
  }, [events, ref]);
2555
2472
  }
2556
2473
 
2474
+ const formatDate = str => {
2475
+ const d = new Date(str);
2476
+ const minutes = d.getMinutes() < 10 ? `0${d.getMinutes()}` : d.getMinutes();
2477
+ return `${d.getDate()}/${d.getMonth() + 1}/${d.getFullYear()} ${d.getHours()}:${minutes}`;
2478
+ };
2479
+ const get$1 = (obj, path, defValue) => {
2480
+ var _pathArray$reduce;
2481
+
2482
+ // If path is not defined or it has false value
2483
+ if (!path) return undefined; // Check if path is string or array. Regex : ensure that we do not have '.' and brackets.
2484
+ // Regex explained: https://regexr.com/58j0k
2485
+
2486
+ const pathArray = Array.isArray(path) ? path : path.match(/([^[.\]])+/g); // Find value if exist return otherwise return undefined value;
2487
+
2488
+ return (_pathArray$reduce = pathArray.reduce((prevObj, key) => prevObj && prevObj[key], obj)) != null ? _pathArray$reduce : defValue;
2489
+ };
2490
+ function getNewId(id = '') {
2491
+ const suffix = '-copy-';
2492
+ const rgx = new RegExp(`($|${suffix}\\d*)`);
2493
+ return stringToSlug(id).replace(rgx, r => {
2494
+ const num = parseInt(r.replace(suffix, '') || '0');
2495
+ return `${suffix}${num + 1}`;
2496
+ });
2497
+ }
2498
+
2557
2499
  function debounce(func, wait) {
2558
2500
  let timeout;
2559
2501
  return function () {
2560
- const context = this;
2502
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
2503
+ const context = this; // eslint-disable-next-line prefer-rest-params
2504
+
2561
2505
  const args = arguments;
2562
2506
 
2563
2507
  const later = function later() {
@@ -2838,7 +2782,9 @@ const SearchInput = ({
2838
2782
  function debounce$1(func, wait) {
2839
2783
  let timeout;
2840
2784
  return function () {
2841
- const context = this;
2785
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
2786
+ const context = this; // eslint-disable-next-line prefer-rest-params
2787
+
2842
2788
  const args = arguments;
2843
2789
 
2844
2790
  const later = function later() {
@@ -3433,7 +3379,8 @@ const DownloadField = ({
3433
3379
  const blob = new Blob([text], {
3434
3380
  type: data.content_type
3435
3381
  });
3436
- const url = window.URL.createObjectURL(blob);
3382
+ const url = window.URL.createObjectURL(blob); // Create blob link to download
3383
+
3437
3384
  const link = document.createElement('a');
3438
3385
  link.href = url;
3439
3386
 
@@ -3448,6 +3395,7 @@ const DownloadField = ({
3448
3395
  setTimeout(function () {
3449
3396
  var _link$parentNode;
3450
3397
 
3398
+ // For Firefox it is necessary to delay revoking the ObjectURL
3451
3399
  window.URL.revokeObjectURL(url);
3452
3400
  (_link$parentNode = link.parentNode) == null ? void 0 : _link$parentNode.removeChild(link);
3453
3401
  }, 100);
@@ -3487,6 +3435,47 @@ const DownloadField = ({
3487
3435
  });
3488
3436
  };
3489
3437
 
3438
+ function useVocabulary(vocabularyName, path = null) {
3439
+ const traversal = useTraversal();
3440
+ const [vocabulary, setVocabulary] = useSetState({
3441
+ data: undefined,
3442
+ loading: false,
3443
+ error: undefined
3444
+ });
3445
+
3446
+ const getPath = () => {
3447
+ if (path) return path;
3448
+ return `${traversal.path}@vocabularies/${vocabularyName}`;
3449
+ };
3450
+
3451
+ useEffect(() => {
3452
+ const getVocabulary = async () => {
3453
+ if (vocabularyName && vocabulary.data === undefined && !vocabulary.loading) {
3454
+ try {
3455
+ setVocabulary({
3456
+ loading: true
3457
+ });
3458
+ const data = await traversal.client.get(getPath());
3459
+ const dataJson = await data.json();
3460
+ setVocabulary({
3461
+ loading: false,
3462
+ data: dataJson
3463
+ });
3464
+ } catch (err) {
3465
+ setVocabulary({
3466
+ loading: false,
3467
+ error: err,
3468
+ data: undefined
3469
+ });
3470
+ }
3471
+ }
3472
+ };
3473
+
3474
+ getVocabulary();
3475
+ }, [vocabularyName, vocabulary, path]);
3476
+ return vocabulary;
3477
+ }
3478
+
3490
3479
  const plain = ['string', 'number', 'boolean'];
3491
3480
  function RenderField({
3492
3481
  value,
@@ -3715,6 +3704,67 @@ function RenderFieldComponent({
3715
3704
  return jsx(RenderField, _extends({}, getRenderProps()));
3716
3705
  }
3717
3706
 
3707
+ const SelectVocabulary = forwardRef(({
3708
+ vocabularyName,
3709
+ className,
3710
+ classWrap,
3711
+ val,
3712
+ dataTest,
3713
+ multiple,
3714
+ onChange,
3715
+ id,
3716
+ placeholder
3717
+ }, ref) => {
3718
+ const vocabulary = useVocabulary(vocabularyName);
3719
+
3720
+ const getOptions = () => {
3721
+ if (get$1(vocabulary, 'data.items', null)) {
3722
+ const vocData = vocabulary.data.items.map(item => {
3723
+ return {
3724
+ text: item.title,
3725
+ value: item.token
3726
+ };
3727
+ });
3728
+ return vocData;
3729
+ }
3730
+
3731
+ return [];
3732
+ };
3733
+
3734
+ const getProps = () => {
3735
+ if (multiple) {
3736
+ const currentValue = val || [];
3737
+ return {
3738
+ multiple: true,
3739
+ size: 5,
3740
+ value: currentValue,
3741
+ options: getOptions()
3742
+ };
3743
+ }
3744
+
3745
+ return {
3746
+ value: val != null ? val : '',
3747
+ appendDefault: true,
3748
+ options: getOptions()
3749
+ };
3750
+ };
3751
+
3752
+ if (vocabulary.data === undefined || vocabulary.loading) {
3753
+ return jsx("div", {});
3754
+ }
3755
+
3756
+ return jsx(Select, _extends({}, getProps(), {
3757
+ className: className,
3758
+ classWrap: classWrap || 'is-fullwidth',
3759
+ dataTest: dataTest,
3760
+ ref: ref,
3761
+ onChange: onChange,
3762
+ id: id,
3763
+ placeholder: placeholder
3764
+ }));
3765
+ });
3766
+ SelectVocabulary.displayName = 'SelectVocabulary';
3767
+
3718
3768
  const EditComponent = forwardRef(({
3719
3769
  schema,
3720
3770
  val,
@@ -4680,6 +4730,7 @@ class ItemModel {
4680
4730
  }
4681
4731
 
4682
4732
  get path() {
4733
+ // Compat
4683
4734
  const item = this.item['@id'] ? this.item['@id'] : this.item['@absolute_url'];
4684
4735
  let path = item.split('//')[1].split('/').splice(1).join('/');
4685
4736
  path = `/${path}/`;
@@ -4700,6 +4751,7 @@ class ItemModel {
4700
4751
  }
4701
4752
 
4702
4753
  get icon() {
4754
+ // eslint-disable-next-line
4703
4755
  const cfg = useConfig();
4704
4756
 
4705
4757
  if (cfg.icons && cfg.icons[this.type]) {
@@ -4964,7 +5016,8 @@ const messages$2 = defineMessages({
4964
5016
  "value": "Installed Addons"
4965
5017
  }]
4966
5018
  }
4967
- });
5019
+ }); // TODO: Refactor without useAsync... just crudContext
5020
+
4968
5021
  function PanelAddons() {
4969
5022
  var _state$data$available, _state$data, _state$data$available2, _state$data2, _state$data$installed, _state$data3, _state$data$installed2, _state$data4;
4970
5023
 
@@ -5243,6 +5296,11 @@ function ItemsActionsProvider({
5243
5296
  children: children
5244
5297
  });
5245
5298
  }
5299
+ /**
5300
+ * Checkbox component without props that consume the ItemsActionsContext
5301
+ * and it select/unselect all items of the page.
5302
+ */
5303
+
5246
5304
  function AllItemsCheckbox({
5247
5305
  dataTest
5248
5306
  }) {
@@ -5272,6 +5330,10 @@ function ItemCheckbox({
5272
5330
  dataTest: dataTest
5273
5331
  });
5274
5332
  }
5333
+ /**
5334
+ * Dropdown to choose some action to apply to the selected items.
5335
+ */
5336
+
5275
5337
  function ItemsActionsDropdown() {
5276
5338
  const intl = useIntl();
5277
5339
  const ACTIONS_OBJECT = getActionsObject(intl, true);
@@ -5355,6 +5417,7 @@ function Pagination({
5355
5417
  "aria-label": "pagination",
5356
5418
  children: [jsx("a", {
5357
5419
  className: "pagination-previous is-small",
5420
+ // disabled={current === 0}
5358
5421
  onClick: () => current > 0 ? doPaginate(current - 1) : null,
5359
5422
  children: jsx("span", {
5360
5423
  className: "icon",
@@ -5364,6 +5427,7 @@ function Pagination({
5364
5427
  })
5365
5428
  }), jsx("a", {
5366
5429
  className: "pagination-next is-small",
5430
+ // disabled={current >= maxPages - 1}
5367
5431
  onClick: () => doPaginate(current + 1),
5368
5432
  children: jsx("span", {
5369
5433
  className: "icon",
@@ -5676,7 +5740,7 @@ function PanelItems() {
5676
5740
  key: 'id',
5677
5741
  direction: 'des'
5678
5742
  });
5679
- sortParsed = parser(`_sort_${defaultSortValue.direction}=${defaultSortValue.key}}`);
5743
+ sortParsed = parser(`_sort_${defaultSortValue.direction}=${defaultSortValue.key}`);
5680
5744
  }
5681
5745
 
5682
5746
  const qsParsed = Ctx.client[fnName]({
@@ -5686,12 +5750,14 @@ function PanelItems() {
5686
5750
  });
5687
5751
  let qs = '';
5688
5752
 
5689
- if (search || type || sort || resultQueryParams.length > 0) {
5753
+ if (search || type || resultQueryParams.length > 0) {
5690
5754
  var _searchParsed, _typeParsed, _sortParsed;
5691
5755
 
5692
5756
  qs = buildQs([...qsParsed, ...((_searchParsed = searchParsed) != null ? _searchParsed : []), ...((_typeParsed = typeParsed) != null ? _typeParsed : []), ...((_sortParsed = sortParsed) != null ? _sortParsed : []), ...resultQueryParams]);
5693
5757
  } else {
5694
- qs = buildQs(qsParsed);
5758
+ var _sortParsed2;
5759
+
5760
+ qs = buildQs([...qsParsed, ...((_sortParsed2 = sortParsed) != null ? _sortParsed2 : [])]);
5695
5761
  }
5696
5762
 
5697
5763
  const {
@@ -6870,7 +6936,8 @@ function CreateButton() {
6870
6936
 
6871
6937
  if (state.types && state.types.length === 0) {
6872
6938
  return null;
6873
- }
6939
+ } // Implement some kind of filtering
6940
+
6874
6941
 
6875
6942
  return jsx(Dropdown, {
6876
6943
  id: "dropdown-menu",
@@ -7021,12 +7088,17 @@ function TabsPanel({
7021
7088
  } else {
7022
7089
  currentTab = currentTab || Object.keys(tabs)[0];
7023
7090
  }
7091
+ /*if (!Object.keys(tabs).includes(currentTab)) {
7092
+ setLocation(defaultTab)
7093
+ currentTab = defaultTab
7094
+ }*/
7095
+
7024
7096
 
7025
7097
  const [current, setTab] = useState(currentTab);
7026
7098
  const CurrentComp = tabs[current] || fallback;
7027
7099
  React.useEffect(() => {
7028
7100
  if (Object.keys(tabs).includes(currentTab)) {
7029
- setTab(currentTab);
7101
+ setTab(currentTab); // setLocation({tab: currentTab})
7030
7102
  }
7031
7103
  }, [currentTab, tabs]);
7032
7104
 
@@ -7412,7 +7484,8 @@ function UsersToolbar() {
7412
7484
  page: 0
7413
7485
  });
7414
7486
  ev.preventDefault();
7415
- };
7487
+ }; // cleanup form on state.search change
7488
+
7416
7489
 
7417
7490
  useEffect(() => {
7418
7491
  if (!searchText || searchText === '') {
@@ -8057,7 +8130,8 @@ function GroupToolbar() {
8057
8130
  page: 0
8058
8131
  });
8059
8132
  ev.preventDefault();
8060
- };
8133
+ }; // cleanup form on state.search change
8134
+
8061
8135
 
8062
8136
  useEffect(() => {
8063
8137
  if (!searchText || searchText === '') {
@@ -8601,11 +8675,13 @@ const get$2 = (key, param, fallback = undefined) => {
8601
8675
  };
8602
8676
 
8603
8677
  const getComponent = (context, path, fallback = undefined) => {
8604
- if (!context) return;
8678
+ if (!context) return; // console.log("Component for path", path)
8679
+ // lookup by path
8605
8680
 
8606
8681
  if (registry.paths[path]) {
8607
8682
  return registry.paths[path];
8608
- }
8683
+ } // by type
8684
+
8609
8685
 
8610
8686
  if (registry.views[context['@type']]) {
8611
8687
  return registry.views[context['@type']];
@@ -8646,6 +8722,17 @@ const getProperties = type => {
8646
8722
 
8647
8723
  const getSchemas = type => {
8648
8724
  return registry.schemas[type] || {};
8725
+ /*
8726
+ filters: [
8727
+ {
8728
+ attribute_key: string,
8729
+ label: string,
8730
+ type: 'select' | 'input'
8731
+ vocabulary: string | undefined
8732
+ values: {[key:string]:any}[]
8733
+ }
8734
+ ]
8735
+ */
8649
8736
  };
8650
8737
 
8651
8738
  const getFieldsToFilter = (type, fallback) => {
@@ -8660,6 +8747,7 @@ const defaultComponent = context => {
8660
8747
  return context.is_folderish ? FolderCtx : ItemCtx;
8661
8748
  };
8662
8749
  function useRegistry(data) {
8750
+ // if data is provided we need to merge it into actual registry
8663
8751
  const ref = React.useRef();
8664
8752
 
8665
8753
  if (data && !ref.current) {
@@ -8681,6 +8769,22 @@ function useRegistry(data) {
8681
8769
  getSchemas
8682
8770
  };
8683
8771
  }
8772
+ /*
8773
+
8774
+ const registry = {
8775
+ paths: {
8776
+ "/db/guillotina/tags/": TagsContext
8777
+ },
8778
+ forms: {
8779
+ Tag: AddTagForm
8780
+ }
8781
+ }
8782
+
8783
+
8784
+ <guillotina registry={registry} />
8785
+
8786
+
8787
+ */
8684
8788
 
8685
8789
  const initialState$4 = {
8686
8790
  path: '',
@@ -11570,14 +11674,17 @@ function Guillotina(_ref) {
11570
11674
  props = _objectWithoutPropertiesLoose(_ref, ["auth", "locale"]);
11571
11675
 
11572
11676
  const messages = loadLocaleData(locale);
11573
- const url = props.url || 'http://localhost:8080';
11677
+ const url = props.url || 'http://localhost:8080'; // without trailing slash
11678
+
11574
11679
  const config = props.config || {};
11575
11680
  const client = useGuillotinaClient();
11576
11681
  const {
11577
11682
  Permissions
11578
11683
  } = useConfig(config);
11579
- const registry = useRegistry(props.registry || {});
11580
- const [location] = useLocation();
11684
+ const registry = useRegistry(props.registry || {}); // Location is cooked routing solution (only uses search params)
11685
+
11686
+ const [location] = useLocation(); // if there is no path provided just go to root
11687
+
11581
11688
  const searchPath = location.get('path') || '/';
11582
11689
 
11583
11690
  if (searchPath && searchPath !== '') {
@@ -12106,6 +12213,7 @@ class Auth {
12106
12213
  });
12107
12214
 
12108
12215
  if (data.status === 401) {
12216
+ // invalid token
12109
12217
  this.cleanAuth();
12110
12218
  this.logout();
12111
12219
  return;