@stoker-platform/web-app 0.5.90 → 0.5.92

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/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @stoker-platform/web-app
2
2
 
3
+ ## 0.5.92
4
+
5
+ ### Patch Changes
6
+
7
+ - feat: add addToUserToken option to fields
8
+ - feat: add ability to restrict list view access
9
+ - Updated dependencies
10
+ - @stoker-platform/node-client@0.5.51
11
+ - @stoker-platform/utils@0.5.43
12
+ - @stoker-platform/web-client@0.5.51
13
+
14
+ ## 0.5.91
15
+
16
+ ### Patch Changes
17
+
18
+ - fix: minor fixes to Dashboard and Form
19
+
3
20
  ## 0.5.90
4
21
 
5
22
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stoker-platform/web-app",
3
- "version": "0.5.90",
3
+ "version": "0.5.92",
4
4
  "type": "module",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "scripts": {
@@ -51,9 +51,9 @@
51
51
  "@radix-ui/react-tooltip": "^1.2.8",
52
52
  "@react-google-maps/api": "^2.20.8",
53
53
  "@sentry/react": "^10.50.0",
54
- "@stoker-platform/node-client": "0.5.50",
55
- "@stoker-platform/utils": "0.5.42",
56
- "@stoker-platform/web-client": "0.5.50",
54
+ "@stoker-platform/node-client": "0.5.51",
55
+ "@stoker-platform/utils": "0.5.43",
56
+ "@stoker-platform/web-client": "0.5.51",
57
57
  "@tanstack/react-table": "^8.21.3",
58
58
  "@types/react": "18.3.13",
59
59
  "@types/react-dom": "18.3.1",
@@ -220,6 +220,11 @@ function Collection({
220
220
  const [imagesConfig, setImagesConfig] = useState<ImagesConfig | undefined>(undefined)
221
221
  const [mapConfig, setMapConfig] = useState<MapConfig | undefined>(undefined)
222
222
  const [calendarConfig, setCalendarConfig] = useState<CalendarConfig | undefined>(undefined)
223
+ const [showList, setShowList] = useState(false)
224
+ const [showCards, setShowCards] = useState(false)
225
+ const [showImages, setShowImages] = useState(false)
226
+ const [showMap, setShowMap] = useState(false)
227
+ const [showCalendar, setShowCalendar] = useState(false)
223
228
 
224
229
  const [search, setSearch] = useState("")
225
230
  const [tab, setTab] = useState<string | undefined>("list")
@@ -758,54 +763,6 @@ function Collection({
758
763
  const cacheState = state[`collection-range-field-${labels.collection.toLowerCase()}`]
759
764
  const rangeState = state[`collection-range-${labels.collection.toLowerCase()}`]
760
765
  const defaultView = tryFunction(customization.admin?.defaultView, [relationCollection, relationParent])
761
- if (!relationList) {
762
- if (tabState) {
763
- setTab(tabState)
764
- tabRef.current = tabState
765
- setState(`collection-tab-${labels.collection.toLowerCase()}`, "tab", tabState)
766
- } else if (defaultView) {
767
- setTab(defaultView)
768
- tabRef.current = defaultView
769
- setState(`collection-tab-${labels.collection.toLowerCase()}`, "tab", defaultView)
770
- } else {
771
- setTab("list")
772
- tabRef.current = "list"
773
- }
774
- if (searchState) {
775
- setSearch(searchState)
776
- setState(`collection-search-${labels.collection.toLowerCase()}`, "search", searchState)
777
- }
778
- if (statusFilterState) {
779
- setStatusFilter(statusFilterState as "active" | "archived" | "all" | "trash")
780
- setState(
781
- `collection-status-filter-${labels.collection.toLowerCase()}`,
782
- "status-filter",
783
- statusFilterState,
784
- )
785
- }
786
- if (tabState === "cards") {
787
- setFirstTabLoadCards(true)
788
- }
789
- if (cacheState) {
790
- setState(`collection-range-field-${labels.collection.toLowerCase()}`, "field", cacheState)
791
- }
792
- if (rangeState) {
793
- setState(`collection-range-${labels.collection.toLowerCase()}`, "range", rangeState)
794
- }
795
- } else {
796
- if (defaultView) {
797
- setTab(defaultView)
798
- tabRef.current = defaultView
799
- setState(`collection-tab-${labels.collection.toLowerCase()}`, "tab", defaultView)
800
- } else {
801
- setTab("list")
802
- tabRef.current = "list"
803
- }
804
- }
805
- if (rangeSelectorState) {
806
- setRangeSelector(rangeSelectorState as "range" | "week" | "month" | undefined)
807
- setState(`collection-range-selector-${labels.collection.toLowerCase()}`, "selector", rangeSelectorState)
808
- }
809
766
 
810
767
  const offlineDisabled = await getCachedConfigValue(customization, [
811
768
  "collections",
@@ -832,6 +789,7 @@ function Collection({
832
789
  }
833
790
  const icon = await getCachedConfigValue(customization, [...collectionAdminPath, "icon"])
834
791
  setIcon(icon)
792
+
835
793
  const listConfig = (await getCachedConfigValue(customization, [...collectionAdminPath, "list"])) as
836
794
  | ListConfig
837
795
  | undefined
@@ -852,6 +810,53 @@ function Collection({
852
810
  | CalendarConfig
853
811
  | undefined
854
812
  setCalendarConfig(calendarConfig)
813
+
814
+ const showListConfig =
815
+ !!permissions.Role && (!listConfig?.roles || listConfig.roles.includes(permissions.Role))
816
+ setShowList(showListConfig)
817
+ const showCardsConfig =
818
+ !!cardsConfig &&
819
+ !!permissions.Role &&
820
+ (!cardsConfig.roles || cardsConfig.roles.includes(permissions.Role))
821
+ setShowCards(showCardsConfig)
822
+ const showImagesConfig =
823
+ !!imagesConfig &&
824
+ !!permissions.Role &&
825
+ (!imagesConfig.roles || imagesConfig.roles.includes(permissions.Role)) &&
826
+ !!imagesConfig.imageField &&
827
+ fields.map((field) => field.name).includes(imagesConfig.imageField)
828
+ setShowImages(showImagesConfig)
829
+ const showMapConfig =
830
+ !!mapConfig &&
831
+ !!permissions.Role &&
832
+ (!mapConfig.roles || mapConfig.roles.includes(permissions.Role)) &&
833
+ ((!!mapConfig.addressField && fields.map((field) => field.name).includes(mapConfig.addressField)) ||
834
+ (!!mapConfig.coordinatesField &&
835
+ fields.map((field) => field.name).includes(mapConfig.coordinatesField)))
836
+ setShowMap(showMapConfig)
837
+ const systemFieldsSchema = getSystemFieldsSchema()
838
+ const resourceField = getField(fields, calendarConfig?.resourceField)
839
+ const showCalendarConfig =
840
+ !!calendarConfig &&
841
+ !!permissions.Role &&
842
+ (!calendarConfig.roles || calendarConfig.roles.includes(permissions.Role)) &&
843
+ !!calendarConfig.startField &&
844
+ fields
845
+ .concat(systemFieldsSchema)
846
+ .map((field) => field.name)
847
+ .includes(calendarConfig.startField) &&
848
+ (!calendarConfig.endField ||
849
+ fields
850
+ .concat(systemFieldsSchema)
851
+ .map((field) => field.name)
852
+ .includes(calendarConfig.endField)) &&
853
+ (!calendarConfig.allDayField ||
854
+ fields.map((field) => field.name).includes(calendarConfig.allDayField)) &&
855
+ (!calendarConfig.resourceField ||
856
+ (resourceField &&
857
+ (!isRelationField(resourceField) || !!schema.collections[resourceField.collection])))
858
+ setShowCalendar(showCalendarConfig)
859
+
855
860
  const restrictExport = await getCachedConfigValue(customization, [...collectionAdminPath, "restrictExport"])
856
861
  setRestrictExport(restrictExport)
857
862
  const disableCreate = await getCachedConfigValue(
@@ -971,6 +976,69 @@ function Collection({
971
976
  }
972
977
  }
973
978
 
979
+ if (!relationList) {
980
+ if (tabState) {
981
+ setTab(tabState)
982
+ tabRef.current = tabState
983
+ setState(`collection-tab-${labels.collection.toLowerCase()}`, "tab", tabState)
984
+ } else if (defaultView) {
985
+ setTab(defaultView)
986
+ tabRef.current = defaultView
987
+ setState(`collection-tab-${labels.collection.toLowerCase()}`, "tab", defaultView)
988
+ } else {
989
+ if (showListConfig) {
990
+ setTab("list")
991
+ tabRef.current = "list"
992
+ } else if (showCardsConfig) {
993
+ setTab("cards")
994
+ tabRef.current = "cards"
995
+ } else if (showImagesConfig) {
996
+ setTab("images")
997
+ tabRef.current = "images"
998
+ } else if (showMapConfig) {
999
+ setTab("map")
1000
+ tabRef.current = "map"
1001
+ } else if (showCalendarConfig) {
1002
+ setTab("calendar")
1003
+ tabRef.current = "calendar"
1004
+ }
1005
+ }
1006
+ if (searchState) {
1007
+ setSearch(searchState)
1008
+ setState(`collection-search-${labels.collection.toLowerCase()}`, "search", searchState)
1009
+ }
1010
+ if (statusFilterState) {
1011
+ setStatusFilter(statusFilterState as "active" | "archived" | "all" | "trash")
1012
+ setState(
1013
+ `collection-status-filter-${labels.collection.toLowerCase()}`,
1014
+ "status-filter",
1015
+ statusFilterState,
1016
+ )
1017
+ }
1018
+ if (tabState === "cards") {
1019
+ setFirstTabLoadCards(true)
1020
+ }
1021
+ if (cacheState) {
1022
+ setState(`collection-range-field-${labels.collection.toLowerCase()}`, "field", cacheState)
1023
+ }
1024
+ if (rangeState) {
1025
+ setState(`collection-range-${labels.collection.toLowerCase()}`, "range", rangeState)
1026
+ }
1027
+ } else {
1028
+ if (defaultView) {
1029
+ setTab(defaultView)
1030
+ tabRef.current = defaultView
1031
+ setState(`collection-tab-${labels.collection.toLowerCase()}`, "tab", defaultView)
1032
+ } else {
1033
+ setTab("list")
1034
+ tabRef.current = "list"
1035
+ }
1036
+ }
1037
+ if (rangeSelectorState) {
1038
+ setRangeSelector(rangeSelectorState as "range" | "week" | "month" | undefined)
1039
+ setState(`collection-range-selector-${labels.collection.toLowerCase()}`, "selector", rangeSelectorState)
1040
+ }
1041
+
974
1042
  const rangeFilter = filtersClone.find((filter: Filter) => filter.type === "range") as
975
1043
  | RangeFilter
976
1044
  | undefined
@@ -1313,49 +1381,6 @@ function Collection({
1313
1381
  return !(isPreloadCacheEnabled && cardsConfig?.statusField && cardsConfig.statusField !== statusField?.field)
1314
1382
  }, [isPreloadCacheEnabled, cardsConfig, statusField])
1315
1383
 
1316
- const showCards = useMemo(() => {
1317
- if (!cardsConfig || !permissions.Role) return false
1318
- if (cardsConfig.roles && !cardsConfig.roles.includes(permissions.Role)) return false
1319
- return true
1320
- }, [cardsConfig, permissions.Role])
1321
-
1322
- const showImages = useMemo(() => {
1323
- if (!imagesConfig || !permissions.Role) return false
1324
- if (imagesConfig.roles && !imagesConfig.roles.includes(permissions.Role)) return false
1325
- return imagesConfig?.imageField && fields.map((field) => field.name).includes(imagesConfig.imageField)
1326
- }, [imagesConfig, permissions.Role])
1327
-
1328
- const showMap = useMemo(() => {
1329
- if (!mapConfig || !permissions.Role) return false
1330
- if (mapConfig.roles && !mapConfig.roles.includes(permissions.Role)) return false
1331
- return (
1332
- (mapConfig?.addressField && fields.map((field) => field.name).includes(mapConfig.addressField)) ||
1333
- (mapConfig?.coordinatesField && fields.map((field) => field.name).includes(mapConfig.coordinatesField))
1334
- )
1335
- }, [mapConfig])
1336
-
1337
- const showCalendar = useMemo(() => {
1338
- if (!calendarConfig || !permissions.Role) return false
1339
- if (calendarConfig.roles && !calendarConfig.roles.includes(permissions.Role)) return false
1340
- const systemFieldsSchema = getSystemFieldsSchema()
1341
- const resourceField = getField(fields, calendarConfig?.resourceField)
1342
- return (
1343
- calendarConfig?.startField &&
1344
- fields
1345
- .concat(systemFieldsSchema)
1346
- .map((field) => field.name)
1347
- .includes(calendarConfig.startField) &&
1348
- (!calendarConfig?.endField ||
1349
- fields
1350
- .concat(systemFieldsSchema)
1351
- .map((field) => field.name)
1352
- .includes(calendarConfig.endField)) &&
1353
- (!calendarConfig?.allDayField || fields.map((field) => field.name).includes(calendarConfig.allDayField)) &&
1354
- (!calendarConfig?.resourceField ||
1355
- (resourceField && (!isRelationField(resourceField) || schema.collections[resourceField.collection])))
1356
- )
1357
- }, [calendarConfig, schema])
1358
-
1359
1384
  const canAddRecords =
1360
1385
  permissions.collections?.[labels.collection]?.operations.includes("Create") &&
1361
1386
  !hasEntityRestrictions.some((entityRestriction) => entityRestriction.type === "Individual") &&
@@ -1801,29 +1826,36 @@ function Collection({
1801
1826
  </Badge>
1802
1827
  )}
1803
1828
  <div className="lg:h-9">
1804
- {!formList && (showCards || showImages || showMap || showCalendar) && (
1805
- <TabsList>
1806
- <TabsTrigger value="list">{listConfig?.title || "List"}</TabsTrigger>
1807
- {showCards && cardsStatusField.current && (
1808
- <TabsTrigger value="cards">
1809
- {cardsConfig?.title || "Board"}
1810
- </TabsTrigger>
1811
- )}
1812
- {showImages && (
1813
- <TabsTrigger value="images">
1814
- {imagesConfig?.title || "Pics"}
1815
- </TabsTrigger>
1816
- )}
1817
- {showMap && (
1818
- <TabsTrigger value="map">{mapConfig?.title || "Map"}</TabsTrigger>
1819
- )}
1820
- {showCalendar && (
1821
- <TabsTrigger value="calendar">
1822
- {calendarConfig?.title || "Calendar"}
1823
- </TabsTrigger>
1824
- )}
1825
- </TabsList>
1826
- )}
1829
+ {!formList &&
1830
+ (showList || showCards || showImages || showMap || showCalendar) && (
1831
+ <TabsList>
1832
+ {showList && (
1833
+ <TabsTrigger value="list">
1834
+ {listConfig?.title || "List"}
1835
+ </TabsTrigger>
1836
+ )}
1837
+ {showCards && cardsStatusField.current && (
1838
+ <TabsTrigger value="cards">
1839
+ {cardsConfig?.title || "Board"}
1840
+ </TabsTrigger>
1841
+ )}
1842
+ {showImages && (
1843
+ <TabsTrigger value="images">
1844
+ {imagesConfig?.title || "Pics"}
1845
+ </TabsTrigger>
1846
+ )}
1847
+ {showMap && (
1848
+ <TabsTrigger value="map">
1849
+ {mapConfig?.title || "Map"}
1850
+ </TabsTrigger>
1851
+ )}
1852
+ {showCalendar && (
1853
+ <TabsTrigger value="calendar">
1854
+ {calendarConfig?.title || "Calendar"}
1855
+ </TabsTrigger>
1856
+ )}
1857
+ </TabsList>
1858
+ )}
1827
1859
  </div>
1828
1860
  {!formList &&
1829
1861
  !relationList?.loadAll &&
package/src/Dashboard.tsx CHANGED
@@ -15,7 +15,7 @@ import { preloadCacheEnabled } from "./utils/preloadCacheEnabled"
15
15
  import { DashboardReminder } from "./DashboardReminder"
16
16
  import { cn } from "./lib/utils"
17
17
  import { Helmet } from "react-helmet"
18
- import { getField } from "@stoker-platform/utils"
18
+ import { collectionAccess, getField } from "@stoker-platform/utils"
19
19
 
20
20
  export const Dashboard = () => {
21
21
  const globalConfig = getGlobalConfigModule()
@@ -43,7 +43,13 @@ export const Dashboard = () => {
43
43
  setCollectionTitles((prev) => ({ ...prev, [labels.collection]: titles?.collection }))
44
44
  }
45
45
  const metrics = await getCachedConfigValue(globalConfig, ["global", "admin", "dashboard"])
46
- setMetrics(metrics)
46
+ setMetrics(
47
+ metrics.filter((metric: DashboardItem) => {
48
+ const collectionPermissions = permissions?.collections?.[metric.collection]
49
+ if (!collectionPermissions) return false
50
+ return collectionAccess("Read", collectionPermissions)
51
+ }),
52
+ )
47
53
  }
48
54
  initialize()
49
55
  }, [])
package/src/Form.tsx CHANGED
@@ -2266,7 +2266,11 @@ function RelationField({
2266
2266
  collection,
2267
2267
  record,
2268
2268
  )
2269
- : relation[relationCollection.recordTitleField || "id"]}
2269
+ : relation[
2270
+ (field as RelationFieldType).titleField ||
2271
+ relationCollection.recordTitleField ||
2272
+ "id"
2273
+ ]}
2270
2274
  </span>
2271
2275
  </Button>
2272
2276
  <Button
@@ -3212,7 +3216,7 @@ function RecordForm({
3212
3216
  (restriction) => restriction.userRole === permissions.Role && restriction.recordRole.includes(role),
3213
3217
  )
3214
3218
  )
3215
- }, [permissions, record])
3219
+ }, [permissions, record, form.watch("Role")])
3216
3220
 
3217
3221
  useEffect(() => {
3218
3222
  const load = async () => {
@@ -20,10 +20,14 @@ export const loadRoutes = (): RouteObject[] => {
20
20
  const homePages = tryFunction(globalConfig.admin?.homePage)
21
21
  const dashboard = tryFunction(globalConfig.admin?.dashboard)
22
22
  const homePage = homePages?.[permissions.Role]
23
- const hasDashboard = dashboard?.some(
24
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
25
- (item: DashboardItem) => !item.roles || item.roles?.includes(permissions.Role!),
26
- )
23
+ const hasDashboard = dashboard?.some((item: DashboardItem) => {
24
+ const collectionPermissions = permissions.collections?.[item.collection]
25
+ if (!collectionPermissions) return false
26
+ return (
27
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
28
+ (!item.roles || item.roles?.includes(permissions.Role!)) && collectionAccess("Read", collectionPermissions)
29
+ )
30
+ })
27
31
 
28
32
  const dynamicRoutes: RouteObject[] = []
29
33