@opengeoweb/workspace 19.6.1-nightly-20260917 → 20.0.0

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.
package/dist/index.esm.js CHANGED
@@ -5,7 +5,7 @@ import { syncGroupsTypes, FEATURE_GROUP_PREFIX, syncGroupsActions, layerActions,
5
5
  import { timeSeriesActions, TimeSeriesTypes, timeSeriesSelectors, timeSeriesReducer } from '@opengeoweb/time-series';
6
6
  import { chunk, cloneDeep, isEqual, isString } from 'lodash';
7
7
  import { getLeaves, createBalancedTreeFromLeaves, MosaicContext, getAndAssertNodeAtPathExists, MosaicWindow, Mosaic } from 'react-mosaic-component';
8
- import { queryOptions, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
8
+ import { queryOptions, useQueryClient, useQuery, useMutation, useIsMutating } from '@tanstack/react-query';
9
9
  import { sessionStorageProvider, isAxiosError, getAxiosErrorMessage, isAuthError, isAxiosAuthError, SHARED_NAMESPACE, safelyInitI18nForTestsAndStories, sharedTranslations, ConfirmationServiceProvider, CustomIconButton, useConfirmationDialog, usePrevious, AlertBanner, CustomAccordion, CustomTooltip, linkifyText, dateUtils, SystemScope, SearchHighlight, ToggleMenu, SearchField, Filter, LastUpdateTime, renderCounter, CustomDialog, ToolContainer, CustomToggleButton, ConfirmationButtons } from '@opengeoweb/shared';
10
10
  import { pluginsActions, getPluginState, pluginsReducer, PluginProvider, PluginDebugProvider, OverlayPluginMenuButton, usePluginCatalog } from '@opengeoweb/plugins';
11
11
  import { warningsFiltersActions, publicWarningsSelectors, warningsTranslations, WARN_NAMESPACE } from '@opengeoweb/warnings';
@@ -15,7 +15,7 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
15
15
  import { useTranslation, I18nextProvider } from 'react-i18next';
16
16
  import { Provider, useDispatch, useSelector, useStore, shallowEqual } from 'react-redux';
17
17
  import { AuthenticationProvider, useAuthenticationContext, GEOWEB_ROLE_PRESETS_ADMIN } from '@opengeoweb/authentication';
18
- import { ThemeWrapper, lightTheme, Link, LinkOff, SplitHorizontal, SplitVertical, SplitHorizontalWithContent, SplitVerticalWithContent, Expand, UnExpand, ChevronDown, Close, ChevronUp, LockLocked, StarOutline, Info, WorkspacePresetsSystemIcon, WorkspacePresetsPluginIcon, SharedPresetsMyUser, SharedPresetsOtherUsers, WorkspacePresetsMyIcon, BackdropStyle, Options, CloudLoading, CloudIdle, WebAssetOff, Exclamation } from '@opengeoweb/theme';
18
+ import { ThemeWrapper, lightTheme, Link, LinkOff, SplitHorizontal, SplitVertical, SplitHorizontalWithContent, SplitVerticalWithContent, Expand, UnExpand, ChevronDown, Close, ChevronUp, LockLocked, Star, StarOutline, Info, WorkspacePresetsSystemIcon, WorkspacePresetsPluginIcon, SharedPresetsMyUser, SharedPresetsOtherUsers, WorkspacePresetsMyIcon, BackdropStyle, Options, CloudLoading, CloudIdle, WebAssetOff, Exclamation } from '@opengeoweb/theme';
19
19
  import i18n from 'i18next';
20
20
  import { coreTranslations, CORE_NAMESPACE, LoadingIndicatorProgressBar } from '@opengeoweb/core';
21
21
  import { formFieldsTranslations, FORM_FIELDS_NAMESPACE, ReactHookFormHiddenInput, ReactHookFormTextField, ReactHookFormProvider, defaultFormOptions } from '@opengeoweb/form-fields';
@@ -28,7 +28,10 @@ import { List as List$1 } from 'react-window';
28
28
  import { http, HttpResponse, delay } from 'msw';
29
29
 
30
30
  var en = {
31
+ "workspace-favourites": "Favourites",
31
32
  "workspace-add-favourite": "Add {{title}} to favourites",
33
+ "workspace-remove-favourite": "Remove {{title}} from favourites",
34
+ "workspace-favourites-error": "Could not load or save favourites. Please try again.",
32
35
  "workspace-menu": "Workspace menu",
33
36
  "workspace-new": "New workspace",
34
37
  "workspace-new-soundings": "New soundings workspace",
@@ -182,6 +185,10 @@ var en = {
182
185
  "viewpreset-paste-validation-wrong-preset-type": "The clipboard contains a workspace preset, not a view preset."
183
186
  };
184
187
  var fi = {
188
+ "workspace-favourites": "Suosikit",
189
+ "workspace-add-favourite": "Lisää {{title}} suosikkeihin",
190
+ "workspace-remove-favourite": "Poista {{title}} suosikeista",
191
+ "workspace-favourites-error": "Suosikkeja ei voitu ladata tai tallentaa. Yritä uudelleen.",
185
192
  "workspace-menu": "Workspace menu",
186
193
  "workspace-new": "Uusi workspace",
187
194
  "workspace-new-soundings": "Uusi luotaustyötila",
@@ -327,6 +334,10 @@ var fi = {
327
334
  "viewpreset-paste-validation-wrong-preset-type": "The clipboard contains a workspace preset, not a view preset."
328
335
  };
329
336
  var no = {
337
+ "workspace-favourites": "Favoritter",
338
+ "workspace-add-favourite": "Legg til {{title}} i favoritter",
339
+ "workspace-remove-favourite": "Fjern {{title}} fra favoritter",
340
+ "workspace-favourites-error": "Kunne ikke laste eller lagre favoritter. Vennligst prøv igjen.",
330
341
  "workspace-menu": "Arbeidsflater",
331
342
  "workspace-new": "Ny arbeidsflate",
332
343
  "workspace-new-soundings": "New soundings workspace",
@@ -473,6 +484,10 @@ var no = {
473
484
  "viewpreset-paste-validation-wrong-preset-type": "Utklippstavlen inneholder en Arbeidsflate, ikke en Snarvei."
474
485
  };
475
486
  var nl = {
487
+ "workspace-favourites": "Favorieten",
488
+ "workspace-add-favourite": "Voeg {{title}} toe aan favorieten",
489
+ "workspace-remove-favourite": "Verwijder {{title}} uit favorieten",
490
+ "workspace-favourites-error": "Kon favorieten niet laden of opslaan. Probeer het opnieuw.",
476
491
  "workspace-menu": "Workspace menu",
477
492
  "workspace-new": "Nieuwe workspace",
478
493
  "workspace-new-soundings": "Nieuwe soundings workspace",
@@ -1259,6 +1274,20 @@ var filterWorkspacePresetList = function filterWorkspacePresetList(params) {
1259
1274
  return true;
1260
1275
  });
1261
1276
  };
1277
+ var favouritePresetKey = function favouritePresetKey(type, preset) {
1278
+ return type + ":" + preset.id;
1279
+ };
1280
+ var updateCachedFavourite = function updateCachedFavourite(client, queryKey, key, isFavourite) {
1281
+ client.setQueryData(queryKey, function (preferences) {
1282
+ var _preferences$favourit;
1283
+ var favourites = (_preferences$favourit = preferences == null ? void 0 : preferences.favouritePresets) != null ? _preferences$favourit : [];
1284
+ return Object.assign({}, preferences, {
1285
+ favouritePresets: isFavourite ? Array.from(new Set([].concat(favourites, [key]))) : favourites.filter(function (value) {
1286
+ return value !== key;
1287
+ })
1288
+ });
1289
+ });
1290
+ };
1262
1291
 
1263
1292
  var getViewPreset = /*#__PURE__*/function () {
1264
1293
  var _ref = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(viewpresetId, auth) {
@@ -3316,7 +3345,7 @@ var getViewPresetLabelFilters = createSelector(getViewPresetById, function (_sto
3316
3345
  }, function (viewPreset) {
3317
3346
  return viewPreset == null ? void 0 : viewPreset.labelFilters;
3318
3347
  }, selectorMemoizationOptions);
3319
- createSelector(getViewPresetById, function (entity) {
3348
+ var getFavouritesOnly$1 = createSelector(getViewPresetById, function (entity) {
3320
3349
  var _entity$favouritesOnl;
3321
3350
  return (_entity$favouritesOnl = entity == null ? void 0 : entity.favouritesOnly) != null ? _entity$favouritesOnl : false;
3322
3351
  });
@@ -3770,10 +3799,17 @@ var getWorkspaceLabelFilters = createSelector(getWorkspaceListStore, function (s
3770
3799
  }, function (state) {
3771
3800
  return state.workspaceLabelFilters;
3772
3801
  }, selectorMemoizationOptions);
3773
- createSelector(getWorkspaceListStore, function (state) {
3802
+ var getFavouritesOnly = createSelector(getWorkspaceListStore, function (state) {
3774
3803
  var _state$favouritesOnly;
3775
3804
  return (_state$favouritesOnly = state == null ? void 0 : state.favouritesOnly) != null ? _state$favouritesOnly : false;
3776
3805
  });
3806
+ var filterAndSortFavouritePresets = function filterAndSortFavouritePresets(presets, isFavourite, favouritesOnly) {
3807
+ return presets.filter(function (preset) {
3808
+ return !favouritesOnly || isFavourite(preset);
3809
+ }).sort(function (first, second) {
3810
+ return Number(isFavourite(second)) - Number(isFavourite(first));
3811
+ });
3812
+ };
3777
3813
 
3778
3814
  var emptyWorkspaceBEData = Object.assign({}, getEmptyMapWorkspace(), {
3779
3815
  views: [{
@@ -5798,6 +5834,171 @@ var defaultComponentsLookUp = function defaultComponentsLookUp(_ref3) {
5798
5834
  }
5799
5835
  };
5800
5836
 
5837
+ var getUserPreferences = /*#__PURE__*/function () {
5838
+ var _ref = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(auth) {
5839
+ return _regenerator().w(function (_context) {
5840
+ while (1) switch (_context.n) {
5841
+ case 0:
5842
+ return _context.a(2, fetch(getPresetBaseUrl() + "/user/preferences", {
5843
+ headers: getHeaders(auth)
5844
+ }).then(handleResponse));
5845
+ }
5846
+ }, _callee);
5847
+ }));
5848
+ return function getUserPreferences(_x) {
5849
+ return _ref.apply(this, arguments);
5850
+ };
5851
+ }();
5852
+ var setFavouritePreset = /*#__PURE__*/function () {
5853
+ var _ref2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(presetType, presetId, isFavourite, auth) {
5854
+ return _regenerator().w(function (_context2) {
5855
+ while (1) switch (_context2.n) {
5856
+ case 0:
5857
+ return _context2.a(2, fetch(getPresetBaseUrl() + "/user/preferences/favourite-presets/" + presetType + "/" + encodeURIComponent(presetId), {
5858
+ method: isFavourite ? 'PUT' : 'DELETE',
5859
+ headers: getHeaders(auth)
5860
+ }).then(handleResponse));
5861
+ }
5862
+ }, _callee2);
5863
+ }));
5864
+ return function setFavouritePreset(_x2, _x3, _x4, _x5) {
5865
+ return _ref2.apply(this, arguments);
5866
+ };
5867
+ }();
5868
+
5869
+ var useFavouritePresets = function useFavouritePresets(type) {
5870
+ var _useAuthenticationCon = useAuthenticationContext(),
5871
+ auth = _useAuthenticationCon.auth,
5872
+ isLoggedIn = _useAuthenticationCon.isLoggedIn;
5873
+ var client = useQueryClient();
5874
+ var queryKey = [LIB_KEY, 'user-preferences', auth == null ? void 0 : auth.username];
5875
+ var enabled = Boolean(auth && isLoggedIn && !hasNoPresetBackend());
5876
+ var query = useQuery({
5877
+ queryKey: queryKey,
5878
+ queryFn: function () {
5879
+ var _queryFn = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
5880
+ return _regenerator().w(function (_context) {
5881
+ while (1) switch (_context.n) {
5882
+ case 0:
5883
+ return _context.a(2, getUserPreferences(auth));
5884
+ }
5885
+ }, _callee);
5886
+ }));
5887
+ function queryFn() {
5888
+ return _queryFn.apply(this, arguments);
5889
+ }
5890
+ return queryFn;
5891
+ }(),
5892
+ enabled: enabled,
5893
+ retry: false
5894
+ });
5895
+ var mutation = useMutation({
5896
+ mutationKey: queryKey,
5897
+ scope: {
5898
+ id: JSON.stringify(queryKey)
5899
+ },
5900
+ mutationFn: function () {
5901
+ var _mutationFn = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(_ref) {
5902
+ var id, isFavourite;
5903
+ return _regenerator().w(function (_context2) {
5904
+ while (1) switch (_context2.n) {
5905
+ case 0:
5906
+ id = _ref.id, isFavourite = _ref.isFavourite;
5907
+ return _context2.a(2, setFavouritePreset(type, id, isFavourite, auth));
5908
+ }
5909
+ }, _callee2);
5910
+ }));
5911
+ function mutationFn(_x) {
5912
+ return _mutationFn.apply(this, arguments);
5913
+ }
5914
+ return mutationFn;
5915
+ }(),
5916
+ onMutate: function () {
5917
+ var _onMutate = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(_ref2) {
5918
+ var _previous$favouritePr, _previous$favouritePr2;
5919
+ var id, isFavourite, key, previous, wasFavourite;
5920
+ return _regenerator().w(function (_context3) {
5921
+ while (1) switch (_context3.n) {
5922
+ case 0:
5923
+ id = _ref2.id, isFavourite = _ref2.isFavourite;
5924
+ _context3.n = 1;
5925
+ return client.cancelQueries({
5926
+ queryKey: queryKey
5927
+ });
5928
+ case 1:
5929
+ key = favouritePresetKey(type, {
5930
+ id: id
5931
+ });
5932
+ previous = client.getQueryData(queryKey);
5933
+ wasFavourite = (_previous$favouritePr = previous == null || (_previous$favouritePr2 = previous.favouritePresets) == null ? void 0 : _previous$favouritePr2.includes(key)) != null ? _previous$favouritePr : false;
5934
+ updateCachedFavourite(client, queryKey, key, isFavourite);
5935
+ // Undo only this favourite, preserving other cached preference changes.
5936
+ return _context3.a(2, function () {
5937
+ return updateCachedFavourite(client, queryKey, key, wasFavourite);
5938
+ });
5939
+ }
5940
+ }, _callee3);
5941
+ }));
5942
+ function onMutate(_x2) {
5943
+ return _onMutate.apply(this, arguments);
5944
+ }
5945
+ return onMutate;
5946
+ }(),
5947
+ onError: function onError(_error, _variables, rollback) {
5948
+ return rollback == null ? void 0 : rollback();
5949
+ },
5950
+ onSuccess: function () {
5951
+ var _onSuccess = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4(preferences) {
5952
+ return _regenerator().w(function (_context4) {
5953
+ while (1) switch (_context4.n) {
5954
+ case 0:
5955
+ _context4.n = 1;
5956
+ return client.cancelQueries({
5957
+ queryKey: queryKey
5958
+ });
5959
+ case 1:
5960
+ client.setQueryData(queryKey, preferences);
5961
+ case 2:
5962
+ return _context4.a(2);
5963
+ }
5964
+ }, _callee4);
5965
+ }));
5966
+ function onSuccess(_x3) {
5967
+ return _onSuccess.apply(this, arguments);
5968
+ }
5969
+ return onSuccess;
5970
+ }()
5971
+ });
5972
+ var isSaving = useIsMutating({
5973
+ mutationKey: queryKey
5974
+ }) > 0;
5975
+ var isFavourite = function isFavourite(preset) {
5976
+ var _query$data;
5977
+ return enabled && Array.isArray((_query$data = query.data) == null ? void 0 : _query$data.favouritePresets) && query.data.favouritePresets.includes(favouritePresetKey(type, preset));
5978
+ };
5979
+ return {
5980
+ isFavourite: isFavourite,
5981
+ toggleFavourite: function toggleFavourite(preset) {
5982
+ if (enabled) {
5983
+ mutation.mutate({
5984
+ id: preset.id,
5985
+ isFavourite: !isFavourite(preset)
5986
+ });
5987
+ }
5988
+ },
5989
+ disabled: !enabled || !query.isSuccess || query.isFetching || isSaving,
5990
+ isLoading: enabled && query.isFetching,
5991
+ isSaving: isSaving,
5992
+ error: enabled ? query.error || mutation.error : null,
5993
+ retry: function retry() {
5994
+ mutation.reset();
5995
+ if (enabled) {
5996
+ void query.refetch();
5997
+ }
5998
+ }
5999
+ };
6000
+ };
6001
+
5801
6002
  var useDeleteViewPreset = function useDeleteViewPreset() {
5802
6003
  var _useAuthenticationCon = useAuthenticationContext(),
5803
6004
  auth = _useAuthenticationCon.auth;
@@ -7223,6 +7424,10 @@ var getPresetIcon = function getPresetIcon(preset, currentUsername) {
7223
7424
  var WorkspaceSelectListRow = function WorkspaceSelectListRow(_ref) {
7224
7425
  var _workspacePreset$desc, _workspacePreset$orig, _workspacePreset$orig2, _workspacePreset$orig3, _workspacePreset$orig4;
7225
7426
  var workspacePreset = _ref.workspacePreset,
7427
+ _ref$isFavourite = _ref.isFavourite,
7428
+ isFavourite = _ref$isFavourite === void 0 ? false : _ref$isFavourite,
7429
+ onToggleFavourite = _ref.onToggleFavourite,
7430
+ favouritesDisabled = _ref.favouritesDisabled,
7226
7431
  isSelected = _ref.isSelected,
7227
7432
  onClickWorkspacePreset = _ref.onClickWorkspacePreset,
7228
7433
  onClickWorkspacePresetOption = _ref.onClickWorkspacePresetOption,
@@ -7323,7 +7528,7 @@ var WorkspaceSelectListRow = function WorkspaceSelectListRow(_ref) {
7323
7528
  return 'workspace-version';
7324
7529
  };
7325
7530
  var showInfoIcon = !!workspacePreset.id && workspacePreset.id !== LOCAL_SOUNDINGS_ID;
7326
- return jsxs(ListItem, {
7531
+ return jsx(ListItem, {
7327
7532
  disablePadding: true,
7328
7533
  sx: {
7329
7534
  mb: 0.5,
@@ -7349,22 +7554,7 @@ var WorkspaceSelectListRow = function WorkspaceSelectListRow(_ref) {
7349
7554
  color: 'geowebColors.typographyAndIcons.text'
7350
7555
  }
7351
7556
  },
7352
- children: [!isNewPreset && jsx(Box, {
7353
- sx: {
7354
- pl: 1,
7355
- flexShrink: 0
7356
- },
7357
- children: jsx(CustomIconButton, {
7358
- disabled: true,
7359
- tooltipTitle: t('workspace-add-favourite', {
7360
- title: workspacePreset.title
7361
- }),
7362
- variant: "flat",
7363
- children: jsx(StarOutline, {
7364
- fontSize: "small"
7365
- })
7366
- })
7367
- }), jsxs(ListItemButton, {
7557
+ children: jsxs(ListItemButton, {
7368
7558
  "aria-label": testIdPrefix,
7369
7559
  "data-testid": testIdPrefix + "-selectListRow",
7370
7560
  onClick: function onClick(event) {
@@ -7384,7 +7574,36 @@ var WorkspaceSelectListRow = function WorkspaceSelectListRow(_ref) {
7384
7574
  py: 1,
7385
7575
  height: WORKSPACE_SELECT_LIST_ROW_HEIGHT + "px"
7386
7576
  },
7387
- children: [jsx(ListItemIcon, {
7577
+ children: [!isNewPreset ? jsx(Box, {
7578
+ onClick: function onClick(event) {
7579
+ // Disabled icon buttons pass pointer clicks to their container.
7580
+ event.stopPropagation();
7581
+ },
7582
+ sx: {
7583
+ pr: 1,
7584
+ flexShrink: 0
7585
+ },
7586
+ children: jsx(CustomIconButton, {
7587
+ "aria-label": t(isFavourite ? 'workspace-remove-favourite' : 'workspace-add-favourite', {
7588
+ title: workspacePreset.title
7589
+ }),
7590
+ disabled: favouritesDisabled || !onToggleFavourite,
7591
+ isSelected: isFavourite,
7592
+ onClick: function onClick(event) {
7593
+ event.stopPropagation();
7594
+ onToggleFavourite == null || onToggleFavourite(workspacePreset);
7595
+ },
7596
+ tooltipTitle: t(isFavourite ? 'workspace-remove-favourite' : 'workspace-add-favourite', {
7597
+ title: workspacePreset.title
7598
+ }),
7599
+ variant: "flat",
7600
+ children: isFavourite ? jsx(Star, {
7601
+ fontSize: "small"
7602
+ }) : jsx(StarOutline, {
7603
+ fontSize: "small"
7604
+ })
7605
+ })
7606
+ }) : null, jsx(ListItemIcon, {
7388
7607
  children: getPresetIcon(workspacePreset, auth == null ? void 0 : auth.username)
7389
7608
  }), jsx(ListItemText, {
7390
7609
  primary: jsx(CustomTooltip, {
@@ -7483,7 +7702,7 @@ var WorkspaceSelectListRow = function WorkspaceSelectListRow(_ref) {
7483
7702
  })]
7484
7703
  })
7485
7704
  })]
7486
- })]
7705
+ })
7487
7706
  });
7488
7707
  };
7489
7708
 
@@ -7500,21 +7719,27 @@ var RowComponent = function RowComponent(_ref) {
7500
7719
  isAdmin = _ref.isAdmin,
7501
7720
  searchQuery = _ref.searchQuery,
7502
7721
  testIdPrefix = _ref.testIdPrefix,
7503
- onSelectVersion = _ref.onSelectVersion;
7722
+ onSelectVersion = _ref.onSelectVersion,
7723
+ isFavourite = _ref.isFavourite,
7724
+ onToggleFavourite = _ref.onToggleFavourite,
7725
+ favouritesDisabled = _ref.favouritesDisabled;
7504
7726
  var preset = items[index];
7505
7727
  return jsx("div", {
7506
7728
  style: Object.assign({}, style, {
7507
7729
  paddingRight: '8px'
7508
7730
  }),
7509
7731
  children: jsx(WorkspaceSelectListRow, {
7732
+ favouritesDisabled: favouritesDisabled,
7510
7733
  infoOpenPresetId: infoOpenPresetId,
7511
7734
  isAdmin: isAdmin,
7512
7735
  isEditable: isEditable,
7736
+ isFavourite: isFavourite == null ? void 0 : isFavourite(preset),
7513
7737
  isSelected: currentSelectedId === preset.id || currentSelectedId === '' && preset.id === undefined,
7514
7738
  onClickWorkspacePreset: onClickWorkspacePreset,
7515
7739
  onClickWorkspacePresetOption: onClickWorkspacePresetOption,
7516
7740
  onOpenPresetInfo: onOpenPresetInfo,
7517
7741
  onSelectVersion: onSelectVersion,
7742
+ onToggleFavourite: onToggleFavourite,
7518
7743
  searchQuery: searchQuery,
7519
7744
  testIdPrefix: testIdPrefix,
7520
7745
  workspacePreset: preset
@@ -7539,13 +7764,22 @@ var WorkspaceSelectList = function WorkspaceSelectList(_ref2) {
7539
7764
  testIdPrefix = _ref2$testIdPrefix === void 0 ? 'workspace' : _ref2$testIdPrefix,
7540
7765
  onOpenPresetInfo = _ref2.onOpenPresetInfo,
7541
7766
  infoOpenPresetId = _ref2.infoOpenPresetId,
7542
- onSelectVersion = _ref2.onSelectVersion;
7767
+ onSelectVersion = _ref2.onSelectVersion,
7768
+ isFavourite = _ref2.isFavourite,
7769
+ onToggleFavourite = _ref2.onToggleFavourite,
7770
+ favouritesDisabled = _ref2.favouritesDisabled;
7543
7771
  var _useWorkspaceTranslat = useWorkspaceTranslation(),
7544
7772
  t = _useWorkspaceTranslat.t;
7545
7773
  var items = React.useMemo(function () {
7546
7774
  var newPresetsTruthy = newPresets && newPresets.length > 0 ? newPresets : [getEmptyWorkspaceListItem(t), getNewSoundingsWorkspaceListItem(t)];
7547
- return !hideNewWorkspace ? [].concat(newPresetsTruthy, workspacePresets) : [].concat(workspacePresets);
7548
- }, [hideNewWorkspace, newPresets, workspacePresets, t]);
7775
+ var favourites = workspacePresets.filter(function (preset) {
7776
+ return isFavourite == null ? void 0 : isFavourite(preset);
7777
+ });
7778
+ var otherPresets = workspacePresets.filter(function (preset) {
7779
+ return !(isFavourite != null && isFavourite(preset));
7780
+ });
7781
+ return [].concat(favourites, !hideNewWorkspace ? newPresetsTruthy : [], otherPresets);
7782
+ }, [hideNewWorkspace, newPresets, workspacePresets, isFavourite, t]);
7549
7783
  return jsxs(Box, {
7550
7784
  "data-testid": testIdPrefix + "-selectList",
7551
7785
  sx: {
@@ -7580,7 +7814,10 @@ var WorkspaceSelectList = function WorkspaceSelectList(_ref2) {
7580
7814
  isAdmin: isAdmin,
7581
7815
  searchQuery: searchQuery,
7582
7816
  testIdPrefix: testIdPrefix,
7583
- onSelectVersion: onSelectVersion
7817
+ onSelectVersion: onSelectVersion,
7818
+ isFavourite: isFavourite,
7819
+ onToggleFavourite: onToggleFavourite,
7820
+ favouritesDisabled: favouritesDisabled
7584
7821
  }
7585
7822
  })
7586
7823
  })]
@@ -7596,6 +7833,10 @@ var ViewPresetMenuListConnect = function ViewPresetMenuListConnect(_ref) {
7596
7833
  hasSpaceForLabelFilter = _ref$hasSpaceForLabel === void 0 ? true : _ref$hasSpaceForLabel;
7597
7834
  var _useWorkspaceTranslat = useWorkspaceTranslation(),
7598
7835
  t = _useWorkspaceTranslat.t;
7836
+ var favourites = useFavouritePresets('view');
7837
+ var selectedFavouritesOnly = useSelector(function (state) {
7838
+ return getFavouritesOnly$1(state, panelId);
7839
+ });
7599
7840
  var dispatch = useDispatch();
7600
7841
  var queryClient = useQueryClient();
7601
7842
  var store = useStore();
@@ -7603,6 +7844,7 @@ var ViewPresetMenuListConnect = function ViewPresetMenuListConnect(_ref) {
7603
7844
  currentRole = _useAuthenticationCon.currentRole,
7604
7845
  isLoggedIn = _useAuthenticationCon.isLoggedIn,
7605
7846
  auth = _useAuthenticationCon.auth;
7847
+ var favouritesOnly = isLoggedIn && selectedFavouritesOnly;
7606
7848
  var username = (auth == null ? void 0 : auth.username) || '';
7607
7849
  var isAdmin = (currentRole == null ? void 0 : currentRole.name) === GEOWEB_ROLE_PRESETS_ADMIN.name;
7608
7850
  var scope = !isAdmin ? 'user' : 'system';
@@ -7671,12 +7913,13 @@ var ViewPresetMenuListConnect = function ViewPresetMenuListConnect(_ref) {
7671
7913
  }
7672
7914
  return Object.values(viewPresetLabelFilters).flat().length;
7673
7915
  }, [viewPresetLabelFilters]);
7674
- var filteredPresets = React.useMemo(function () {
7916
+ var matchingPresets = React.useMemo(function () {
7675
7917
  if (viewPresets) {
7676
7918
  return [].concat(filterAndSortPresets([].concat(viewPresets, pluginCatalogAsPresets), viewPresetListFilters, username, isAdmin, viewPresetLabelFilters != null ? viewPresetLabelFilters : undefined, viewPresetListSearchQuery));
7677
7919
  }
7678
7920
  return [];
7679
7921
  }, [viewPresets, viewPresetListFilters, username, isAdmin, viewPresetLabelFilters, viewPresetListSearchQuery, pluginCatalogAsPresets]);
7922
+ var filteredPresets = filterAndSortFavouritePresets(matchingPresets, favourites.isFavourite, favouritesOnly);
7680
7923
  var labelsFormMethods = useForm({
7681
7924
  defaultValues: {
7682
7925
  labels: viewPresetLabelFilters
@@ -8007,15 +8250,23 @@ var ViewPresetMenuListConnect = function ViewPresetMenuListConnect(_ref) {
8007
8250
  flexDirection: 'column',
8008
8251
  height: '100%'
8009
8252
  },
8010
- children: [jsx(Box, {
8253
+ children: [!!favourites.error && jsx(AlertBanner, {
8254
+ actionButtonProps: {
8255
+ title: t('workspace-retry'),
8256
+ onClick: favourites.retry
8257
+ },
8258
+ info: t('workspace-favourites-error'),
8259
+ title: t('workspace-favourites')
8260
+ }), jsx(Box, {
8011
8261
  sx: {
8012
8262
  height: 4,
8263
+ flexShrink: 0,
8013
8264
  overflow: 'hidden'
8014
8265
  },
8015
- children: !!isViewPresetsListFetching && jsx(LinearProgress, {
8266
+ children: isViewPresetsListFetching || favourites.isLoading || favourites.isSaving ? jsx(LinearProgress, {
8016
8267
  color: "secondary",
8017
8268
  "data-testid": "loading-bar"
8018
- })
8269
+ }) : null
8019
8270
  }), !isViewPresetsListFetching && !!error && jsx(AlertBanner, Object.assign({
8020
8271
  info: error.message,
8021
8272
  shouldClose: true,
@@ -8078,8 +8329,17 @@ var ViewPresetMenuListConnect = function ViewPresetMenuListConnect(_ref) {
8078
8329
  },
8079
8330
  children: jsx(Filter, {
8080
8331
  activeLabelFilterCount: activeLabelFilterCount,
8081
- filters: viewPresetListFilters,
8082
- isAllSelected: isAllSelectedForFilters,
8332
+ filters: [].concat(viewPresetListFilters.map(function (filter) {
8333
+ return Object.assign({}, filter, {
8334
+ isSelected: !favouritesOnly && !isAllSelectedForFilters && filter.isSelected
8335
+ });
8336
+ }), [{
8337
+ id: 'favourites',
8338
+ label: t('workspace-favourites'),
8339
+ isSelected: favouritesOnly,
8340
+ isDisabled: !isLoggedIn
8341
+ }]),
8342
+ isAllSelected: isAllSelectedForFilters ? !favouritesOnly : false,
8083
8343
  isLabelFilterOpen: isLabelFilterOpen,
8084
8344
  onClickFilterChip: onClickFilterChip,
8085
8345
  onSearch: onSearchFilter,
@@ -8118,10 +8378,12 @@ var ViewPresetMenuListConnect = function ViewPresetMenuListConnect(_ref) {
8118
8378
  },
8119
8379
  children: [jsx(WorkspaceSelectList, {
8120
8380
  currentSelectedId: activeViewPresetId || undefined,
8121
- hideNewWorkspace: shouldHideNewWorkspace,
8381
+ favouritesDisabled: favourites.disabled,
8382
+ hideNewWorkspace: shouldHideNewWorkspace || favouritesOnly,
8122
8383
  infoOpenPresetId: infoPreset == null ? void 0 : infoPreset.id,
8123
8384
  isAdmin: isAdmin,
8124
8385
  isEditable: isLoggedIn,
8386
+ isFavourite: favourites.isFavourite,
8125
8387
  newPresets: [Object.assign({}, getEmptyWorkspaceListItem(t), {
8126
8388
  title: t('workspace-mappreset-new')
8127
8389
  })],
@@ -8129,6 +8391,7 @@ var ViewPresetMenuListConnect = function ViewPresetMenuListConnect(_ref) {
8129
8391
  onClickWorkspacePresetOption: onClickViewPresetOption,
8130
8392
  onOpenPresetInfo: onOpenPresetInfo,
8131
8393
  onSelectVersion: onSelectVersion,
8394
+ onToggleFavourite: favourites.toggleFavourite,
8132
8395
  searchQuery: viewPresetListSearchQuery,
8133
8396
  testIdPrefix: "viewpreset",
8134
8397
  workspacePresets: filteredPresets
@@ -8353,6 +8616,10 @@ var WorkspaceSelectListConnect = function WorkspaceSelectListConnect(_ref) {
8353
8616
  var _ref$isLabelFilterOpe = _ref.isLabelFilterOpen,
8354
8617
  isLabelFilterOpen = _ref$isLabelFilterOpe === void 0 ? false : _ref$isLabelFilterOpe,
8355
8618
  onToggleLabelFilter = _ref.onToggleLabelFilter;
8619
+ var favourites = useFavouritePresets('workspace');
8620
+ var selectedFavouritesOnly = useSelector(function (state) {
8621
+ return getFavouritesOnly(state);
8622
+ });
8356
8623
  var dispatch = useDispatch();
8357
8624
  var _useWorkspaceTranslat = useWorkspaceTranslation(),
8358
8625
  t = _useWorkspaceTranslat.t;
@@ -8360,6 +8627,7 @@ var WorkspaceSelectListConnect = function WorkspaceSelectListConnect(_ref) {
8360
8627
  currentRole = _useAuthenticationCon.currentRole,
8361
8628
  isLoggedIn = _useAuthenticationCon.isLoggedIn,
8362
8629
  auth = _useAuthenticationCon.auth;
8630
+ var favouritesOnly = isLoggedIn && selectedFavouritesOnly;
8363
8631
  var username = (auth == null ? void 0 : auth.username) || '';
8364
8632
  var isAdmin = (currentRole == null ? void 0 : currentRole.name) === GEOWEB_ROLE_PRESETS_ADMIN.name;
8365
8633
  var scope = !isAdmin ? 'user' : 'system';
@@ -8390,9 +8658,10 @@ var WorkspaceSelectListConnect = function WorkspaceSelectListConnect(_ref) {
8390
8658
  }
8391
8659
  return Object.values(labelFilters).flat().length;
8392
8660
  }, [labelFilters]);
8393
- var filteredPresets = React.useMemo(function () {
8661
+ var matchingPresets = React.useMemo(function () {
8394
8662
  return filterAndSortPresets(workspacePresets, selectedFilters, username, isAdmin, labelFilters != null ? labelFilters : undefined, workspaceSearchQuery);
8395
8663
  }, [workspacePresets, selectedFilters, username, isAdmin, labelFilters, workspaceSearchQuery]);
8664
+ var filteredPresets = filterAndSortFavouritePresets(matchingPresets, favourites.isFavourite, favouritesOnly);
8396
8665
  var infoPanelAnchorRef = React.useRef(null);
8397
8666
  var _React$useState = React.useState(),
8398
8667
  infoPreset = _React$useState[0],
@@ -8726,15 +8995,23 @@ var WorkspaceSelectListConnect = function WorkspaceSelectListConnect(_ref) {
8726
8995
  bgcolor: 'geowebColors.background.surface'
8727
8996
  },
8728
8997
  tabIndex: 0,
8729
- children: [jsx(Box, {
8998
+ children: [!!favourites.error && jsx(AlertBanner, {
8999
+ actionButtonProps: {
9000
+ title: t('workspace-retry'),
9001
+ onClick: favourites.retry
9002
+ },
9003
+ info: t('workspace-favourites-error'),
9004
+ title: t('workspace-favourites')
9005
+ }), jsx(Box, {
8730
9006
  sx: {
8731
9007
  height: 4,
9008
+ flexShrink: 0,
8732
9009
  overflow: 'hidden'
8733
9010
  },
8734
- children: !!isFetching && jsx(LinearProgress, {
9011
+ children: isFetching || favourites.isLoading || favourites.isSaving ? jsx(LinearProgress, {
8735
9012
  color: "secondary",
8736
9013
  "data-testid": "loading-bar"
8737
- })
9014
+ }) : null
8738
9015
  }), !!error && jsx("div", {
8739
9016
  style: {
8740
9017
  whiteSpace: 'normal'
@@ -8799,8 +9076,17 @@ var WorkspaceSelectListConnect = function WorkspaceSelectListConnect(_ref) {
8799
9076
  },
8800
9077
  children: jsx(Filter, {
8801
9078
  activeLabelFilterCount: activeLabelFilterCount,
8802
- filters: workspaceListFilters,
8803
- isAllSelected: isAllSelected,
9079
+ filters: [].concat(workspaceListFilters.map(function (filter) {
9080
+ return Object.assign({}, filter, {
9081
+ isSelected: !favouritesOnly && !isAllSelected && filter.isSelected
9082
+ });
9083
+ }), [{
9084
+ id: 'favourites',
9085
+ label: t('workspace-favourites'),
9086
+ isSelected: favouritesOnly,
9087
+ isDisabled: !isLoggedIn
9088
+ }]),
9089
+ isAllSelected: isAllSelected ? !favouritesOnly : false,
8804
9090
  isLabelFilterOpen: isLabelFilterOpen,
8805
9091
  onClickFilterChip: onClickFilterChip,
8806
9092
  onSearch: searchFilter,
@@ -8831,13 +9117,16 @@ var WorkspaceSelectListConnect = function WorkspaceSelectListConnect(_ref) {
8831
9117
  },
8832
9118
  children: [jsx(WorkspaceSelectList, {
8833
9119
  currentSelectedId: currentView.id || '',
8834
- hideNewWorkspace: shouldHideNewWorkspace,
9120
+ favouritesDisabled: favourites.disabled,
9121
+ hideNewWorkspace: shouldHideNewWorkspace || favouritesOnly,
8835
9122
  infoOpenPresetId: infoPreset == null ? void 0 : infoPreset.id,
8836
9123
  isAdmin: isAdmin,
8837
9124
  isEditable: isLoggedIn,
9125
+ isFavourite: favourites.isFavourite,
8838
9126
  onClickWorkspacePreset: onClickWorkspacePreset,
8839
9127
  onClickWorkspacePresetOption: onClickWorkspacePresetOption,
8840
9128
  onOpenPresetInfo: onOpenPresetInfo,
9129
+ onToggleFavourite: favourites.toggleFavourite,
8841
9130
  searchQuery: workspaceSearchQuery,
8842
9131
  workspacePresets: filteredPresets
8843
9132
  }), jsx(WorkspacePresetInfo, {
@@ -15,6 +15,9 @@ export interface WorkspaceSelectListProps extends BoxProps {
15
15
  newPresets?: WorkspacePresetListItem[];
16
16
  testIdPrefix?: string;
17
17
  onSelectVersion?: (presetId: string, version: string) => void;
18
+ isFavourite?: (preset: WorkspacePresetListItem) => boolean;
19
+ onToggleFavourite?: (preset: WorkspacePresetListItem) => void;
20
+ favouritesDisabled?: boolean;
18
21
  }
19
22
  declare const WorkspaceSelectList: React.FC<WorkspaceSelectListProps>;
20
23
  export default WorkspaceSelectList;
@@ -5,6 +5,9 @@ export declare const WORKSPACE_SELECT_LIST_ROW_HEIGHT = 40;
5
5
  export declare const getPresetIcon: (preset: WorkspacePresetListItem, currentUsername?: string) => React.ReactElement | null;
6
6
  interface WorkspaceSelectListRowProps {
7
7
  workspacePreset: WorkspacePresetListItem;
8
+ isFavourite?: boolean;
9
+ onToggleFavourite?: (preset: WorkspacePresetListItem) => void;
10
+ favouritesDisabled?: boolean;
8
11
  onClickWorkspacePreset: (id: string) => void;
9
12
  onClickWorkspacePresetOption: (presetId: string, workspaceAction: WorkspacePresetAction, workspacePreset: WorkspacePresetListItem) => void;
10
13
  onOpenPresetInfo?: (workspacePreset: WorkspacePresetListItem) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeoweb/workspace",
3
- "version": "19.6.1-nightly-20260917",
3
+ "version": "20.0.0",
4
4
  "description": "GeoWeb Workspace library for the opengeoweb project",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -21,33 +21,33 @@
21
21
  },
22
22
  "dependencies": {
23
23
  "react-redux": "^9.2.0",
24
- "@opengeoweb/shared": "19.6.1-nightly-20260917",
25
- "@opengeoweb/store": "19.6.1-nightly-20260917",
26
- "@opengeoweb/api": "19.6.1-nightly-20260917",
24
+ "@opengeoweb/shared": "20.0.0",
25
+ "@opengeoweb/store": "20.0.0",
26
+ "@opengeoweb/api": "20.0.0",
27
27
  "react-hook-form": "^7.50.1",
28
- "@opengeoweb/theme": "19.6.1-nightly-20260917",
28
+ "@opengeoweb/theme": "20.0.0",
29
29
  "@reduxjs/toolkit": "^2.6.1",
30
- "@opengeoweb/snackbar": "19.6.1-nightly-20260917",
30
+ "@opengeoweb/snackbar": "20.0.0",
31
31
  "react-window": "^2.2.6",
32
32
  "lodash": "^4.18.1",
33
33
  "axios": "^1.18.0",
34
34
  "react-mosaic-component": "npm:react-mosaic-component-opengeoweb@^6.1.1-opengeoweb.1",
35
- "@opengeoweb/form-fields": "19.6.1-nightly-20260917",
36
- "@opengeoweb/time-series": "19.6.1-nightly-20260917",
37
- "@opengeoweb/authentication": "19.6.1-nightly-20260917",
38
- "@opengeoweb/plugins": "19.6.1-nightly-20260917",
39
- "@opengeoweb/core": "19.6.1-nightly-20260917",
40
- "@opengeoweb/taf": "19.6.1-nightly-20260917",
41
- "@opengeoweb/sigmet-airmet": "19.6.1-nightly-20260917",
42
- "@opengeoweb/warnings": "19.6.1-nightly-20260917",
43
- "@opengeoweb/space-weather": "19.6.1-nightly-20260917",
35
+ "@opengeoweb/form-fields": "20.0.0",
36
+ "@opengeoweb/time-series": "20.0.0",
37
+ "@opengeoweb/authentication": "20.0.0",
38
+ "@opengeoweb/plugins": "20.0.0",
39
+ "@opengeoweb/core": "20.0.0",
40
+ "@opengeoweb/taf": "20.0.0",
41
+ "@opengeoweb/sigmet-airmet": "20.0.0",
42
+ "@opengeoweb/warnings": "20.0.0",
43
+ "@opengeoweb/space-weather": "20.0.0",
44
44
  "i18next": "^25.0.1",
45
45
  "react-i18next": "^15.1.1",
46
46
  "@mui/material": "^9.0.1",
47
- "@opengeoweb/webmap-react": "19.6.1-nightly-20260917",
47
+ "@opengeoweb/webmap-react": "20.0.0",
48
48
  "@tanstack/react-query": "^5.85.5",
49
- "@opengeoweb/soundings": "19.6.1-nightly-20260917",
50
- "@opengeoweb/knmi-components": "19.6.1-nightly-20260917",
49
+ "@opengeoweb/soundings": "20.0.0",
50
+ "@opengeoweb/knmi-components": "20.0.0",
51
51
  "@mui/system": "^9.0.1"
52
52
  },
53
53
  "peerDependencies": {