Skip to content

Commit 5aa5bf1

Browse files
committed
feat(shape-7911): add request user context action, demo example and sandbox functionality
1 parent 0e67f5d commit 5aa5bf1

27 files changed

+304
-165
lines changed

packages/demo/src/components/ContextRequester.tsx

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,6 @@ export const ContextRequester: PluginComponent = (props) => {
99
<Typography textAlign="center">
1010
{JSON.stringify(data.story, null, 2)}
1111
</Typography>
12-
<Typography variant="subtitle1">Permissions: </Typography>
13-
<Typography textAlign="center">
14-
{JSON.stringify(data.userPermissions, null, 2)}
15-
</Typography>
16-
<Typography variant="subtitle1">Is admin: </Typography>
17-
<Typography textAlign="center">
18-
{data.isSpaceAdmin ? 'Yes' : 'No'}
19-
</Typography>
2012
<Typography variant="subtitle1">Is AI enabled: </Typography>
2113
<Typography textAlign="center">
2214
{data.isAIEnabled ? 'Yes' : 'No'}

packages/demo/src/components/NonModalView.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { ValueMutator } from './ValueMutator'
44
import { HeightChangeDemo } from './HeightChangeDemo'
55
import { AssetSelector } from './AssetSelector'
66
import { ContextRequester } from './ContextRequester'
7+
import { UserContextRequester } from './UserContextRequester'
78
import { PluginComponent } from './FieldPluginDemo'
89
import { LanguageView } from './LanguageView'
910

@@ -15,6 +16,7 @@ export const NonModalView: PluginComponent = (props) => (
1516
<ModalToggle {...props} />
1617
<AssetSelector {...props} />
1718
<ContextRequester {...props} />
19+
<UserContextRequester {...props} />
1820
<HeightChangeDemo {...props} />
1921
<LanguageView {...props} />
2022
</Stack>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { useState } from 'react'
2+
import { Button, Stack, Typography } from '@mui/material'
3+
import { PluginComponent } from './FieldPluginDemo'
4+
import { UserData } from '@storyblok/field-plugin'
5+
6+
export const UserContextRequester: PluginComponent = (props) => {
7+
const { actions } = props
8+
const [user, setUser] = useState<UserData>({
9+
isSpaceAdmin: false,
10+
permissions: undefined,
11+
})
12+
return (
13+
<Stack gap={2}>
14+
<Typography variant="subtitle1">User data: </Typography>
15+
<Typography>Permissions: </Typography>
16+
<Typography textAlign="center">
17+
{JSON.stringify(user.permissions, null, 2)}
18+
</Typography>
19+
<Typography>Is space admin? </Typography>
20+
<Typography textAlign="center">
21+
{user.isSpaceAdmin ? 'Yes' : 'No'}
22+
</Typography>
23+
<Button
24+
variant="outlined"
25+
color="secondary"
26+
onClick={async () => setUser(await actions.requestUserContext())}
27+
>
28+
Request User Context
29+
</Button>
30+
</Stack>
31+
)
32+
}

packages/field-plugin/src/createFieldPlugin/FieldPluginActions.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Asset, StoryData, ModalSize } from '../messaging'
1+
import type { Asset, StoryData, UserData, ModalSize } from '../messaging'
22
import type { FieldPluginData } from './FieldPluginData'
33

44
export type SetContent<Content> = (
@@ -9,12 +9,14 @@ export type SetModalOpen<Content> = (
99
modalSize?: ModalSize,
1010
) => Promise<FieldPluginData<Content>>
1111
export type RequestContext = () => Promise<StoryData>
12+
export type RequestUserContext = () => Promise<UserData>
1213
export type SelectAsset = () => Promise<Asset>
1314
export type Initialize<Content> = () => Promise<FieldPluginData<Content>>
1415

1516
export type FieldPluginActions<Content> = {
1617
setContent: SetContent<Content>
1718
setModalOpen: SetModalOpen<Content>
1819
requestContext: RequestContext
20+
requestUserContext: RequestUserContext
1921
selectAsset: SelectAsset
2022
}

packages/field-plugin/src/createFieldPlugin/FieldPluginData.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ export type FieldPluginData<Content> = {
99
options: Record<string, string>
1010
spaceId: number | undefined
1111
userId: number | undefined
12-
userPermissions: Record<string, string[] | number[]> | undefined
13-
isSpaceAdmin: boolean
1412
interfaceLang: string
1513
storyLang: string
1614
story: StoryData

packages/field-plugin/src/createFieldPlugin/createPluginActions/callbackQueue.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
AssetSelectedMessage,
33
ContextRequestMessage,
4+
UserContextRequestMessage,
45
LoadedMessage,
56
OnMessage,
67
StateChangedMessage,
@@ -12,6 +13,7 @@ export type CallbackId = string
1213
type CallbackMap = {
1314
asset: Record<CallbackId, OnMessage<AssetSelectedMessage>>
1415
context: Record<CallbackId, OnMessage<ContextRequestMessage>>
16+
userContext: Record<CallbackId, OnMessage<UserContextRequestMessage>>
1517
stateChanged: Record<CallbackId, OnMessage<StateChangedMessage>>
1618
loaded: Record<CallbackId, OnMessage<LoadedMessage>>
1719
}
@@ -21,6 +23,7 @@ export const callbackQueue = () => {
2123
let callbackMap: CallbackMap = {
2224
asset: {},
2325
context: {},
26+
userContext: {},
2427
stateChanged: {},
2528
loaded: {},
2629
}

packages/field-plugin/src/createFieldPlugin/createPluginActions/createPluginActions.test.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { createPluginActions } from './createPluginActions'
2-
import {
2+
import type {
33
AssetModalChangeMessage,
44
GetContextMessage,
5+
GetUserContextMessage,
56
ModalChangeMessage,
67
ValueChangeMessage,
78
} from '../../messaging'
@@ -71,8 +72,6 @@ describe('createPluginActions', () => {
7172
model: randomString,
7273
spaceId: null,
7374
userId: undefined,
74-
userPermissions: undefined,
75-
isSpaceAdmin: false,
7675
blockId: undefined,
7776
isAIEnabled: false,
7877
releases: [],
@@ -216,6 +215,7 @@ describe('createPluginActions', () => {
216215
)
217216
})
218217
})
218+
219219
describe('requestContext()', () => {
220220
it('send a message to the container to request the story', () => {
221221
const { uid, postToContainer, onUpdateState } = mock()
@@ -235,6 +235,27 @@ describe('createPluginActions', () => {
235235
)
236236
})
237237
})
238+
239+
describe('requestUserContext()', () => {
240+
it('send a message to the container to request the user info', () => {
241+
const { uid, postToContainer, onUpdateState } = mock()
242+
const {
243+
actions: { requestUserContext },
244+
} = createPluginActions({
245+
uid,
246+
postToContainer,
247+
onUpdateState,
248+
validateContent,
249+
})
250+
requestUserContext()
251+
expect(postToContainer).toHaveBeenLastCalledWith(
252+
expect.objectContaining({
253+
event: 'getUserContext',
254+
} satisfies Partial<GetUserContextMessage>),
255+
)
256+
})
257+
})
258+
238259
describe('selectAsset()', () => {
239260
it('send a message to the container to open the asset selector', () => {
240261
const { uid, postToContainer, onUpdateState } = mock()

packages/field-plugin/src/createFieldPlugin/createPluginActions/createPluginActions.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import {
44
assetFromAssetSelectedMessage,
55
assetModalChangeMessage,
66
getContextMessage,
7+
getUserContextMessage,
78
heightChangeMessage,
89
modalChangeMessage,
910
OnAssetSelectMessage,
1011
OnContextRequestMessage,
12+
OnUserContextRequestMessage,
1113
OnLoadedMessage,
1214
OnStateChangeMessage,
1315
OnUnknownPluginMessage,
@@ -62,15 +64,17 @@ export const createPluginActions: CreatePluginActions = ({
6264
const onContextRequest: OnContextRequestMessage = (data) => {
6365
popCallback('context', data.callbackId)?.(data)
6466
}
67+
const onUserContextRequest: OnUserContextRequestMessage = (data) => {
68+
popCallback('userContext', data.callbackId)?.(data)
69+
}
6570
const onAssetSelect: OnAssetSelectMessage = (data) => {
6671
popCallback('asset', data.callbackId)?.(data)
6772
}
6873
const onUnknownMessage: OnUnknownPluginMessage = (data) => {
6974
// TODO remove side-effect, making functions in this file pure.
7075
// perhaps only show this message in development mode?
7176
console.debug(
72-
`Plugin received a message from container of an unknown action type "${
73-
data.action
77+
`Plugin received a message from container of an unknown action type "${data.action
7478
}". You may need to upgrade the version of the @storyblok/field-plugin library. Full message: ${JSON.stringify(
7579
data,
7680
)}`,
@@ -81,6 +85,7 @@ export const createPluginActions: CreatePluginActions = ({
8185
onStateChange,
8286
onLoaded,
8387
onContextRequest,
88+
onUserContextRequest,
8489
onAssetSelect,
8590
onUnknownMessage,
8691
}
@@ -140,6 +145,14 @@ export const createPluginActions: CreatePluginActions = ({
140145
postToContainer(getContextMessage({ uid, callbackId }))
141146
})
142147
},
148+
requestUserContext: () => {
149+
return new Promise((resolve) => {
150+
const callbackId = pushCallback('userContext', (message) =>
151+
resolve(message.user),
152+
)
153+
postToContainer(getUserContextMessage({ uid, callbackId }))
154+
})
155+
},
143156
},
144157
messageCallbacks,
145158
onHeightChange,

packages/field-plugin/src/createFieldPlugin/createPluginActions/createPluginMessageListener/createPluginMessageListener.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
OnAssetSelectMessage,
33
OnContextRequestMessage,
4+
OnUserContextRequestMessage,
45
OnLoadedMessage,
56
OnStateChangeMessage,
67
OnUnknownPluginMessage,
@@ -11,6 +12,7 @@ export type PluginMessageCallbacks = {
1112
onStateChange: OnStateChangeMessage
1213
onLoaded: OnLoadedMessage
1314
onContextRequest: OnContextRequestMessage
15+
onUserContextRequest: OnUserContextRequestMessage
1416
onAssetSelect: OnAssetSelectMessage
1517
onUnknownMessage: OnUnknownPluginMessage
1618
}

packages/field-plugin/src/createFieldPlugin/createPluginActions/createPluginMessageListener/handlePluginMessage.test.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { PluginMessageCallbacks } from './createPluginMessageListener'
33
import {
44
AssetSelectedMessage,
55
ContextRequestMessage,
6+
UserContextRequestMessage,
67
LoadedMessage,
78
MessageToPlugin,
89
} from '../../../messaging'
@@ -12,6 +13,7 @@ const uid = 'abc123'
1213
const mockCallbacks = (): PluginMessageCallbacks => ({
1314
onStateChange: vi.fn(),
1415
onContextRequest: vi.fn(),
16+
onUserContextRequest: vi.fn(),
1517
onAssetSelect: vi.fn(),
1618
onUnknownMessage: vi.fn(),
1719
onLoaded: vi.fn(),
@@ -24,6 +26,7 @@ describe('handlePluginMessage', () => {
2426
handlePluginMessage(data, uid, callbacks)
2527
expect(callbacks.onStateChange).not.toHaveBeenCalled()
2628
expect(callbacks.onContextRequest).not.toHaveBeenCalled()
29+
expect(callbacks.onUserContextRequest).not.toHaveBeenCalled()
2730
expect(callbacks.onAssetSelect).not.toHaveBeenCalled()
2831
expect(callbacks.onUnknownMessage).not.toHaveBeenCalled()
2932
})
@@ -36,6 +39,7 @@ describe('handlePluginMessage', () => {
3639
handlePluginMessage(data, uid, callbacks)
3740
expect(callbacks.onStateChange).not.toHaveBeenCalled()
3841
expect(callbacks.onContextRequest).not.toHaveBeenCalled()
42+
expect(callbacks.onUserContextRequest).not.toHaveBeenCalled()
3943
expect(callbacks.onAssetSelect).not.toHaveBeenCalled()
4044
expect(callbacks.onUnknownMessage).not.toHaveBeenCalled()
4145
})
@@ -48,6 +52,7 @@ describe('handlePluginMessage', () => {
4852
handlePluginMessage(data, uid, callbacks)
4953
expect(callbacks.onStateChange).not.toHaveBeenCalled()
5054
expect(callbacks.onContextRequest).not.toHaveBeenCalled()
55+
expect(callbacks.onUserContextRequest).not.toHaveBeenCalled()
5156
expect(callbacks.onAssetSelect).not.toHaveBeenCalled()
5257
expect(callbacks.onUnknownMessage).toHaveBeenCalledWith(data)
5358
})
@@ -61,8 +66,6 @@ describe('handlePluginMessage', () => {
6166
model: 123,
6267
spaceId: 1234,
6368
userId: 2345,
64-
userPermissions: {},
65-
isSpaceAdmin: true,
6669
story: { content: {} },
6770
schema: { options: [], field_type: 'avh', translatable: false },
6871
storyId: 1344,
@@ -77,6 +80,7 @@ describe('handlePluginMessage', () => {
7780
expect(callbacks.onLoaded).toHaveBeenCalledWith(data)
7881
expect(callbacks.onStateChange).not.toHaveBeenCalled()
7982
expect(callbacks.onContextRequest).not.toHaveBeenCalled()
83+
expect(callbacks.onUserContextRequest).not.toHaveBeenCalled()
8084
expect(callbacks.onAssetSelect).not.toHaveBeenCalled()
8185
expect(callbacks.onUnknownMessage).not.toHaveBeenCalled()
8286
})
@@ -90,6 +94,21 @@ describe('handlePluginMessage', () => {
9094
handlePluginMessage(data, uid, callbacks)
9195
expect(callbacks.onStateChange).not.toHaveBeenCalled()
9296
expect(callbacks.onContextRequest).toHaveBeenCalledWith(data)
97+
expect(callbacks.onUserContextRequest).not.toHaveBeenCalled()
98+
expect(callbacks.onAssetSelect).not.toHaveBeenCalled()
99+
expect(callbacks.onUnknownMessage).not.toHaveBeenCalled()
100+
})
101+
it('handles user context request messages', () => {
102+
const data: UserContextRequestMessage = {
103+
action: 'get-user-context',
104+
uid,
105+
user: { isSpaceAdmin: true, permissions: {} },
106+
}
107+
const callbacks = mockCallbacks()
108+
handlePluginMessage(data, uid, callbacks)
109+
expect(callbacks.onStateChange).not.toHaveBeenCalled()
110+
expect(callbacks.onContextRequest).not.toHaveBeenCalled()
111+
expect(callbacks.onUserContextRequest).toHaveBeenCalledWith(data)
93112
expect(callbacks.onAssetSelect).not.toHaveBeenCalled()
94113
expect(callbacks.onUnknownMessage).not.toHaveBeenCalled()
95114
})
@@ -106,6 +125,7 @@ describe('handlePluginMessage', () => {
106125
handlePluginMessage(data, uid, callbacks)
107126
expect(callbacks.onStateChange).not.toHaveBeenCalled()
108127
expect(callbacks.onContextRequest).not.toHaveBeenCalled()
128+
expect(callbacks.onUserContextRequest).not.toHaveBeenCalled()
109129
expect(callbacks.onAssetSelect).toHaveBeenCalledWith(data)
110130
expect(callbacks.onUnknownMessage).not.toHaveBeenCalled()
111131
})

0 commit comments

Comments
 (0)