@ossy/resources 1.12.2 → 1.12.3

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.
Files changed (79) hide show
  1. package/package.json +11 -3
  2. package/src/AudioResource.jsx +1 -1
  3. package/src/CreateDirectory.jsx +2 -10
  4. package/src/CreateDocument.jsx +2 -2
  5. package/src/Definition.js +2 -1
  6. package/src/DocumentEdit.jsx +10 -38
  7. package/src/DocumentView.jsx +3 -4
  8. package/src/GenericResourceCard.jsx +25 -7
  9. package/src/GenericResourceDetail.jsx +6 -60
  10. package/src/GenericResourceForm.jsx +66 -31
  11. package/src/ImageResource.jsx +1 -1
  12. package/src/PDFResource.jsx +1 -1
  13. package/src/PlatformFileField.jsx +239 -0
  14. package/src/ResourceContentPage.jsx +3 -3
  15. package/src/ResourceDescription.jsx +1 -1
  16. package/src/ResourceDetails.jsx +3 -4
  17. package/src/ResourceDialogMove.jsx +2 -2
  18. package/src/ResourceFactory.jsx +11 -64
  19. package/src/ResourceGenericView.jsx +1 -1
  20. package/src/ResourceList.jsx +89 -106
  21. package/src/ResourcePanel.jsx +40 -57
  22. package/src/ResourceTags.jsx +1 -1
  23. package/src/ResourcesPage.jsx +26 -35
  24. package/src/SchemaPresenter.jsx +215 -0
  25. package/src/Upload.jsx +6 -25
  26. package/src/UploadResources.jsx +2 -2
  27. package/src/VideoResource.jsx +1 -1
  28. package/src/access-filter.spec.js +1 -1
  29. package/src/create-page-view.action.js +1 -1
  30. package/src/create-page-view.task.js +10 -9
  31. package/src/create.action.js +1 -1
  32. package/src/create.task.js +28 -29
  33. package/src/delete.action.js +1 -1
  34. package/src/delete.task.js +10 -13
  35. package/src/en.translations.json +24 -24
  36. package/src/get-page-view-stats.action.js +1 -1
  37. package/src/get-page-view-stats.task.js +3 -4
  38. package/src/get-resource-alias.api.js +8 -0
  39. package/src/get-resource-info-alias.api.js +8 -0
  40. package/src/get-resource-info.api.js +36 -0
  41. package/src/get-resource-variant.api.js +8 -0
  42. package/src/get-resource.api.js +51 -0
  43. package/src/get.action.js +1 -1
  44. package/src/get.task.js +6 -6
  45. package/src/index.js +6 -0
  46. package/src/list.action.js +1 -1
  47. package/src/list.task.js +1 -1
  48. package/src/platform-file-field.component.jsx +5 -0
  49. package/src/platform-image-field.component.jsx +5 -0
  50. package/src/resource-create.page.jsx +4 -4
  51. package/src/resource-read.helpers.js +151 -0
  52. package/src/resource-stream.helpers.js +20 -0
  53. package/src/resource-stream.js +108 -0
  54. package/src/resource.helpers.js +9 -9
  55. package/src/resources.attach-media-urls.js +9 -3
  56. package/src/resources.events.js +42 -81
  57. package/src/{resources.spec.js → resources.integration.spec.js} +19 -19
  58. package/src/resources.queries.js +5 -2
  59. package/src/search.action.js +1 -1
  60. package/src/search.task.js +1 -1
  61. package/src/server.js +2 -1
  62. package/src/sv.translations.json +24 -24
  63. package/src/update-access.action.js +1 -1
  64. package/src/update-access.task.js +9 -8
  65. package/src/update-content.action.js +1 -1
  66. package/src/update-content.task.js +25 -27
  67. package/src/update-location.action.js +1 -1
  68. package/src/update-location.task.js +9 -8
  69. package/src/update-name.action.js +1 -1
  70. package/src/update-name.task.js +9 -8
  71. package/src/upload-named-version.action.js +1 -1
  72. package/src/upload-named-version.task.js +16 -22
  73. package/src/useActivePath.jsx +3 -8
  74. package/src/useDocumentValidator.js +16 -0
  75. package/src/useSchemaEngine.js +9 -0
  76. package/src/useSchemas.js +29 -0
  77. package/src/useSelectedResourceId.jsx +36 -0
  78. package/src/ResourceContentPage.stories.jsx +0 -19
  79. package/src/resource.aggregate.js +0 -86
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ossy/resources",
3
3
  "description": "Resource domain — aggregate and events for the Ossy resource model",
4
- "version": "1.12.2",
4
+ "version": "1.12.3",
5
5
  "private": false,
6
6
  "type": "module",
7
7
  "main": "./src/index.js",
@@ -11,14 +11,22 @@
11
11
  "./server": "./src/server.js"
12
12
  },
13
13
  "scripts": {
14
- "test": "NODE_OPTIONS=--experimental-vm-modules jest --verbose"
14
+ "test": "NODE_OPTIONS=--experimental-vm-modules jest --verbose",
15
+ "test:integration": "NODE_OPTIONS=--experimental-vm-modules jest --config jest.integration.config.js --verbose"
15
16
  },
16
17
  "author": "Ossy <yourfriends@ossy.se> (https://ossy.se)",
17
18
  "license": "MIT",
18
19
  "ossy": {
19
20
  "src": "./src"
20
21
  },
22
+ "dependencies": {
23
+ "@ossy/event-store": "^1.8.3",
24
+ "@ossy/fold": "^1.0.1",
25
+ "@ossy/platform": "^1.39.3",
26
+ "@ossy/schema": "^1.0.1"
27
+ },
21
28
  "peerDependencies": {
29
+ "@ossy/schema": "*",
22
30
  "@ossy/sdk-react": ">=1.0.0",
23
31
  "@ossy/workspaces": ">=1.0.0",
24
32
  "react": ">=19.0.0 <20.0.0"
@@ -37,5 +45,5 @@
37
45
  "/src",
38
46
  "README.md"
39
47
  ],
40
- "gitHead": "2b8745d57fee8b6c08787e2755b4df489291a5cd"
48
+ "gitHead": "a0d89185a17f8de8ce328c3a648c108ff1d61d8f"
41
49
  }
@@ -8,7 +8,7 @@ export const AudioResource = ({
8
8
  onClose: _onClose
9
9
  }) => {
10
10
  const sdk = useSdk()
11
- const { data: resource } = sdk.read(GetResource, { id: resourceId }, { enabled: !!resourceId })
11
+ const { data: resource } = sdk.read(GetResource, { resourceId }, { enabled: !!resourceId })
12
12
 
13
13
  return (
14
14
  <View stack bordered>
@@ -1,15 +1,7 @@
1
1
  import React, { useState, useRef } from 'react'
2
2
  import { createDirectory } from './resource.helpers.js'
3
3
  import { useSdk } from '@ossy/sdk-react'
4
- import {
5
- Input,
6
- Title,
7
- Button,
8
- View,
9
- useInputValue,
10
- Text,
11
- useLocale,
12
- } from '@ossy/design-system'
4
+ import { Input, Button, View, useInputValue, Text, useLocale } from '@ossy/design-system'
13
5
  import { useRouter } from '@ossy/router-react'
14
6
 
15
7
  export const CreateDirectory = () => {
@@ -51,7 +43,7 @@ export const CreateDirectory = () => {
51
43
  return (
52
44
  <View gap="s" style={{ height: '100%' }}>
53
45
 
54
- <Title variant="primary" style={{ marginBottom: 'var(--space-m)' }}>{t('resources.createDirectory.title')}</Title>
46
+ <Text variant="heading-primary" style={{ marginBottom: 'var(--space-m)' }} as="h1" text="resources.createDirectory.title" />
55
47
 
56
48
  <Text style={{ marginBottom: 'var(--space-m)' }}>
57
49
  {t('resources.createDirectory.description', { location: directoryLocation })}
@@ -8,7 +8,7 @@ import { GenericResourceForm } from './GenericResourceForm.jsx'
8
8
  export const CreateDocument = () => {
9
9
  const { t } = useLocale()
10
10
  const router = useRouter()
11
- const templateId = router.searchParams.templateId
11
+ const schemaId = router.searchParams.schemaId
12
12
  const location = router.searchParams.location
13
13
  const sdk = useSdk()
14
14
  const [error, setError] = useState()
@@ -27,7 +27,7 @@ export const CreateDocument = () => {
27
27
  return (
28
28
  <>
29
29
  <GenericResourceForm
30
- templateId={templateId}
30
+ schemaId={schemaId}
31
31
  mode="create"
32
32
  onSubmit={onSubmit}
33
33
  onCancel={onCancel}
package/src/Definition.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export const Definition = {
2
2
  id: 'resources',
3
- title: 'Free Resources',
3
+ title: 'Resources',
4
4
  description: `
5
5
  We believe in providing value at every step of your journey with us.
6
6
  That's why we've curated a collection of free resources.
@@ -10,4 +10,5 @@ export const Definition = {
10
10
  `,
11
11
  icon: 'image',
12
12
  statuses: ['beta'],
13
+ entitlementRequired: false,
13
14
  }
@@ -1,51 +1,23 @@
1
1
  import React from 'react'
2
2
  import { metadata as GetResource } from './get.action.js'
3
- import { GetWorkspace } from '@ossy/workspaces'
4
3
  import { useSdk } from '@ossy/sdk-react'
5
- import {
6
- Text,
7
- View,
8
- DelayedRender,
9
- Fields,
10
- } from '@ossy/design-system'
4
+ import { GenericResourceForm } from './GenericResourceForm.jsx'
11
5
 
6
+ /** @deprecated Prefer SchemaPresenter flow="Edit" or GenericResourceForm directly. */
12
7
  export const DocumentEdit = ({
13
8
  resourceId,
14
9
  form,
15
10
  }) => {
16
11
  const sdk = useSdk()
17
- const { data: resource } = sdk.read(GetResource, { id: resourceId }, { enabled: !!resourceId })
18
- const { data: workspace } = sdk.read(GetWorkspace)
19
- const template = workspace?.resourceTemplates?.find(t => t.id === resource?.type)
20
-
21
- if (template?.fields && form.data) {
22
- return (
23
- <View style={{ padding: '16px 0' }}>
24
- <Fields data={form.data} onChange={form.onChange} fields={template.fields} />
25
- </View>
26
- )
27
- }
28
-
29
- // Loading
30
- if (template?.fields && !form.data) {
31
- return (
32
- <DelayedRender>
33
- <View style={{ padding: '16px 0' }}>
34
- Loading...
35
- </View>
36
- </DelayedRender>
37
- )
38
- }
12
+ const { data: resource } = sdk.read(GetResource, { resourceId }, { enabled: !!resourceId })
39
13
 
40
14
  return (
41
- <View style={{ padding: '16px 0' }}>
42
- <View inset="m" >
43
- <Text>
44
- This documents template has been deleted and can therefore not be edited
45
- </Text>
46
- </View>
47
- </View>
15
+ <GenericResourceForm
16
+ schemaId={resource?.type}
17
+ mode="edit"
18
+ resourceId={resourceId}
19
+ resource={resource}
20
+ form={form}
21
+ />
48
22
  )
49
-
50
-
51
23
  }
@@ -1,17 +1,16 @@
1
1
  import React from 'react'
2
2
  import { pipe, keys, map } from 'ramda'
3
3
  import { metadata as GetResource } from './get.action.js'
4
- import { GetWorkspace } from '@ossy/workspaces'
5
4
  import { useSdk } from '@ossy/sdk-react'
5
+ import { useSchema } from './useSchemas.js'
6
6
  import { Text, View } from '@ossy/design-system'
7
7
 
8
8
  export const DocumentView = ({
9
9
  resourceId
10
10
  }) => {
11
11
  const sdk = useSdk()
12
- const { data: resource } = sdk.read(GetResource, { id: resourceId }, { enabled: !!resourceId })
13
- const { data: workspace } = sdk.read(GetWorkspace)
14
- const template = workspace?.resourceTemplates?.find(t => t.id === resource?.type)
12
+ const { data: resource } = sdk.read(GetResource, { resourceId }, { enabled: !!resourceId })
13
+ const template = useSchema(resource?.type)
15
14
 
16
15
  return (
17
16
  <View style={{ padding: '16px 0' }}>
@@ -1,13 +1,14 @@
1
- import React from 'react'
1
+ import React, { useMemo } from 'react'
2
2
  import { metadata as GetResource } from './get.action.js'
3
3
  import { useSdk } from '@ossy/sdk-react'
4
- import { Slot, resourceSlot, View, Title, Text, DelayedRender } from '@ossy/design-system'
4
+ import { resolveViewComponentChain } from '@ossy/schema/resolve'
5
+ import { Slot, View, Text, DelayedRender } from '@ossy/design-system'
5
6
 
6
7
  function GenericResourceCardFallback ({ resource }) {
7
8
  if (!resource) return null
8
9
  return (
9
10
  <View surface="secondary" roundness="m" inset="m" gap="xs">
10
- <Title variant="secondary">{resource.name}</Title>
11
+ <Text variant="heading-secondary" as="h2">{resource.name}</Text>
11
12
  {resource.content?.description && (
12
13
  <Text size="s" color="secondary">{resource.content.description}</Text>
13
14
  )}
@@ -15,11 +16,15 @@ function GenericResourceCardFallback ({ resource }) {
15
16
  )
16
17
  }
17
18
 
18
- /** Card-sized resource preview `resource:{type}/card`. */
19
+ /** Card projection for a schema-backed resource — ADR 0006. */
19
20
  export function GenericResourceCard ({ resourceId, resource: resourceProp }) {
20
21
  const sdk = useSdk()
21
- const { data: loaded } = sdk.read(GetResource, { id: resourceId }, { enabled: !!resourceId && !resourceProp })
22
+ const { data: loaded } = sdk.read(GetResource, { resourceId }, { enabled: !!resourceId && !resourceProp })
22
23
  const resource = resourceProp ?? loaded
24
+ const chain = useMemo(
25
+ () => (resource?.type ? resolveViewComponentChain(resource.type, 'card') : []),
26
+ [resource?.type],
27
+ )
23
28
 
24
29
  if (!resource) {
25
30
  return (
@@ -29,12 +34,25 @@ export function GenericResourceCard ({ resourceId, resource: resourceProp }) {
29
34
  )
30
35
  }
31
36
 
37
+ const [primary, secondary] = chain
38
+
32
39
  return (
33
40
  <Slot
34
- name={resourceSlot(resource.type, 'card')}
41
+ name={primary}
35
42
  resourceId={resourceId}
36
43
  resource={resource}
37
- fallback={<GenericResourceCardFallback resource={resource} />}
44
+ schemaId={resource.type}
45
+ projection="card"
46
+ fallback={
47
+ <Slot
48
+ name={secondary}
49
+ resourceId={resourceId}
50
+ resource={resource}
51
+ schemaId={resource.type}
52
+ projection="card"
53
+ fallback={<GenericResourceCardFallback resource={resource} />}
54
+ />
55
+ }
38
56
  />
39
57
  )
40
58
  }
@@ -1,66 +1,12 @@
1
- import React from 'react'
2
- import { metadata as GetResource } from './get.action.js'
3
- import { GetWorkspace } from '@ossy/workspaces'
4
- import { useSdk } from '@ossy/sdk-react'
5
- import {
6
- Slot,
7
- resourceSlot,
8
- View,
9
- Title,
10
- Text,
11
- DelayedRender,
12
- Fields,
13
- } from '@ossy/design-system'
14
- import { ResourceGenericView } from './ResourceGenericView.jsx'
15
-
16
- function GenericResourceDetailFallback ({ resourceId }) {
17
- const sdk = useSdk()
18
- const { data: resource } = sdk.read(GetResource, { id: resourceId }, { enabled: !!resourceId })
19
- const { data: workspace } = sdk.read(GetWorkspace)
20
- const template = workspace?.resourceTemplates?.find(t => t.id === resource?.type)
21
-
22
- if (!resource) {
23
- return (
24
- <DelayedRender>
25
- <Text>Loading…</Text>
26
- </DelayedRender>
27
- )
28
- }
29
-
30
- if (template?.fields?.length) {
31
- return (
32
- <View stack gap="m" inset="m">
33
- <Title>{resource.name}</Title>
34
- <Fields data={resource.content || {}} fields={template.fields} />
35
- </View>
36
- )
37
- }
38
-
39
- return <ResourceGenericView resourceId={resourceId} />
40
- }
41
-
42
- /**
43
- * Generic resource detail host — resolves `resource:{type}/detail` from the slot
44
- * registry; falls back to template fields or a minimal placeholder.
45
- */
46
- export function GenericResourceDetail ({ resourceId }) {
47
- const sdk = useSdk()
48
- const { data: resource } = sdk.read(GetResource, { id: resourceId }, { enabled: !!resourceId })
49
-
50
- if (!resource) {
51
- return (
52
- <DelayedRender>
53
- <Text>Loading…</Text>
54
- </DelayedRender>
55
- )
56
- }
1
+ import { SchemaPresenter } from './SchemaPresenter.jsx'
57
2
 
3
+ /** Read view for a schema-backed resource — ADR 0006 component id chain. */
4
+ export function GenericResourceDetail ({ resourceId, projection }) {
58
5
  return (
59
- <Slot
60
- name={resourceSlot(resource.type, 'detail')}
6
+ <SchemaPresenter
61
7
  resourceId={resourceId}
62
- resource={resource}
63
- fallback={<GenericResourceDetailFallback resourceId={resourceId} />}
8
+ flow="View"
9
+ projection={projection}
64
10
  />
65
11
  )
66
12
  }
@@ -1,24 +1,14 @@
1
1
  import React, { useState } from 'react'
2
- import { GetWorkspace } from '@ossy/workspaces'
3
- import { useSdk } from '@ossy/sdk-react'
4
- import {
5
- Slot,
6
- resourceSlot,
7
- View,
8
- Title,
9
- Text,
10
- InputTitle,
11
- Button,
12
- Alert,
13
- Fields,
14
- applyFieldChange,
15
- useInputValue,
16
- useLocale,
17
- } from '@ossy/design-system'
2
+ import { useSchema } from './useSchemas.js'
3
+ import { useSchemaEngine } from './useSchemaEngine.js'
4
+ import { validateContent } from '@ossy/schema'
5
+ import { resolveFormComponentId } from '@ossy/schema/resolve'
6
+ import { Slot, View, Text, InputTitle, Button, Alert, Fields, applyFieldChange, useInputValue, useLocale, DelayedRender } from '@ossy/design-system'
18
7
 
19
8
  function GenericResourceFormFallback ({
20
- templateId,
9
+ schemaId,
21
10
  mode = 'create',
11
+ form,
22
12
  initialName = '',
23
13
  initialContent = {},
24
14
  onSubmit,
@@ -26,20 +16,59 @@ function GenericResourceFormFallback ({
26
16
  submitLabel,
27
17
  }) {
28
18
  const { t } = useLocale()
29
- const sdk = useSdk()
30
- const { data: workspace } = sdk.read(GetWorkspace)
31
- const template = workspace?.resourceTemplates?.find(t => t.id === templateId)
19
+ const template = useSchema(schemaId)
20
+ const engine = useSchemaEngine()
32
21
  const [name, setName] = useInputValue(initialName)
33
22
  const [content, setContent] = useState(initialContent)
34
23
  const [error, setError] = useState()
35
24
 
25
+ if (form && mode === 'edit') {
26
+ if (template?.fields && form.data) {
27
+ return (
28
+ <View style={{ padding: '16px 0' }}>
29
+ <Fields data={form.data} onChange={form.onChange} fields={template.fields} />
30
+ </View>
31
+ )
32
+ }
33
+
34
+ if (template?.fields && !form.data) {
35
+ return (
36
+ <DelayedRender>
37
+ <View style={{ padding: '16px 0' }}>
38
+ <Text>Loading...</Text>
39
+ </View>
40
+ </DelayedRender>
41
+ )
42
+ }
43
+
44
+ return (
45
+ <View style={{ padding: '16px 0' }}>
46
+ <View inset="m">
47
+ <Text>
48
+ This documents template has been deleted and can therefore not be edited
49
+ </Text>
50
+ </View>
51
+ </View>
52
+ )
53
+ }
54
+
36
55
  const handleSubmit = () => {
37
56
  if (!name?.trim()) {
38
57
  setError(t('resources.form.nameRequired'))
39
58
  return
40
59
  }
60
+ if (template) {
61
+ const result = validateContent(engine, template, content)
62
+ if (!result.ok) {
63
+ setError(result.message)
64
+ return
65
+ }
66
+ setError(undefined)
67
+ onSubmit?.({ name: name.trim(), content: result.data, type: schemaId })
68
+ return
69
+ }
41
70
  setError(undefined)
42
- onSubmit?.({ name: name.trim(), content, type: templateId })
71
+ onSubmit?.({ name: name.trim(), content, type: schemaId })
43
72
  }
44
73
 
45
74
  return (
@@ -53,12 +82,15 @@ function GenericResourceFormFallback ({
53
82
  />
54
83
  <Fields
55
84
  data={content}
56
- onChange={(event) => setContent((prev) => applyFieldChange(prev, event))}
85
+ onChange={(event) => {
86
+ setError(undefined)
87
+ setContent((prev) => applyFieldChange(prev, event))
88
+ }}
57
89
  fields={template?.fields || []}
58
90
  />
59
- {error && <Alert>{error}</Alert>}
91
+ {error && <Alert variant="danger">{error}</Alert>}
60
92
  <View layout="row" gap="s" justifyContent="flex-end">
61
- {onCancel && <Button variant="link" onClick={onCancel}>{t('design-system.cancel')}</Button>}
93
+ {onCancel && <Button variant="link" onClick={onCancel} label="design-system.cancel" />}
62
94
  <Button variant="cta" onClick={handleSubmit}>
63
95
  {submitLabel || (mode === 'edit' ? t('design-system.save') : (template?.name ? `${t('design-system.add')} ${template.name}` : t('resources.form.createResource')))}
64
96
  </Button>
@@ -68,14 +100,15 @@ function GenericResourceFormFallback ({
68
100
  }
69
101
 
70
102
  /**
71
- * Generic resource create/edit host — resolves `resource:{type}/form` from the
103
+ * Generic resource create/edit host — resolves `@ossy/…/form/{concept}` via
72
104
  * slot registry; falls back to template-driven Fields.
73
105
  */
74
106
  export function GenericResourceForm ({
75
- templateId,
107
+ schemaId,
76
108
  mode = 'create',
77
109
  resourceId,
78
110
  resource,
111
+ form,
79
112
  initialName,
80
113
  initialContent,
81
114
  onSubmit,
@@ -84,23 +117,25 @@ export function GenericResourceForm ({
84
117
  }) {
85
118
  const { t } = useLocale()
86
119
 
87
- if (!templateId) {
88
- return <Text>{t('resources.form.selectType')}</Text>
120
+ if (!schemaId) {
121
+ return <Text text="resources.form.selectType" />
89
122
  }
90
123
 
91
124
  return (
92
125
  <Slot
93
- name={resourceSlot(templateId, 'form')}
94
- templateId={templateId}
126
+ name={resolveFormComponentId(schemaId)}
127
+ schemaId={schemaId}
95
128
  mode={mode}
96
129
  resourceId={resourceId}
97
130
  resource={resource}
131
+ form={form}
98
132
  onSubmit={onSubmit}
99
133
  onCancel={onCancel}
100
134
  fallback={
101
135
  <GenericResourceFormFallback
102
- templateId={templateId}
136
+ schemaId={schemaId}
103
137
  mode={mode}
138
+ form={form}
104
139
  initialName={initialName ?? resource?.name}
105
140
  initialContent={initialContent ?? resource?.content ?? {}}
106
141
  onSubmit={onSubmit}
@@ -9,7 +9,7 @@ export const ImageResource = ({
9
9
  resourceId
10
10
  }) => {
11
11
  const sdk = useSdk()
12
- const { data: resource } = sdk.read(GetResource, { id: resourceId }, { enabled: !!resourceId })
12
+ const { data: resource } = sdk.read(GetResource, { resourceId }, { enabled: !!resourceId })
13
13
 
14
14
  return (
15
15
  <div style={{ display: 'flex', justifyContent: 'center', padding: 'var(--space-m) var(--space-s) var(--space-xl)' }}>
@@ -7,7 +7,7 @@ export const PDFResource = ({
7
7
  resourceId
8
8
  }) => {
9
9
  const sdk = useSdk()
10
- const { data: resource } = sdk.read(GetResource, { id: resourceId }, { enabled: !!resourceId })
10
+ const { data: resource } = sdk.read(GetResource, { resourceId }, { enabled: !!resourceId })
11
11
 
12
12
  return (
13
13
  <View stack bordered>