@sanity/workflow-studio 0.27.0 → 0.29.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/CHANGELOG.md +75 -0
- package/README.md +10 -4
- package/dist/index.cjs +8 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +9 -2
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,80 @@
|
|
|
1
1
|
# @sanity/workflow-studio
|
|
2
2
|
|
|
3
|
+
## 0.29.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [f44fc33]
|
|
8
|
+
- Updated dependencies [26f25e0]
|
|
9
|
+
- Updated dependencies [25bd1fb]
|
|
10
|
+
- Updated dependencies [3fd04f1]
|
|
11
|
+
- @sanity/workflow-engine@0.29.0
|
|
12
|
+
- @sanity/workflow-react@0.29.0
|
|
13
|
+
- @sanity/workflow-sdk@0.29.0
|
|
14
|
+
|
|
15
|
+
## 0.28.0
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- 6584554: **BREAKING:** assignment surfaces now read the project's role catalog, so a role
|
|
20
|
+
with no current holders is assignable and carries its project title.
|
|
21
|
+
|
|
22
|
+
Previously the only role vocabulary was the roles loaded members happened to
|
|
23
|
+
hold. A role the project defines but nobody has yet could not be offered at all,
|
|
24
|
+
and a role named by a stored value rendered as its bare machine name because no
|
|
25
|
+
membership record carried a title for it. Both are fixed by reading
|
|
26
|
+
`GET /projects/{projectId}/roles`. That read is gated on
|
|
27
|
+
`sanity-project-roles: read`, which the default user-facing project roles carry
|
|
28
|
+
down to viewer, so it is not expected to need an administrator.
|
|
29
|
+
|
|
30
|
+
The catalog also becomes the bound on what a picker offers, which subtracts as
|
|
31
|
+
well as adds: a role a member holds that the catalog does not list stops being
|
|
32
|
+
offerable, though it still labels correctly wherever it is already assigned. On
|
|
33
|
+
a complete catalog nothing is lost, since every held role is in it.
|
|
34
|
+
|
|
35
|
+
Three API changes, all in `@sanity/workflow-components`:
|
|
36
|
+
- `ProjectMembersState` gains a required `roles` field, the project's assignable
|
|
37
|
+
roles. Anything constructing this state by hand must supply it; `roles: []`
|
|
38
|
+
preserves the previous behaviour, since resolution falls back to the roles
|
|
39
|
+
members hold. `MemberPicker` does not take it — it lists members only, and its
|
|
40
|
+
props were narrowed to the three fields it reads.
|
|
41
|
+
- `memberRoleFor` and `roleLabelFor` take a `RoleVocabulary` (`{members, roles}`)
|
|
42
|
+
in place of a bare member array. The state either adapter returns satisfies it,
|
|
43
|
+
so a caller holding one can pass it straight through.
|
|
44
|
+
- `AssigneeBadge` and `AssigneeBadges` take `vocabulary` in place of `members`,
|
|
45
|
+
for the same reason.
|
|
46
|
+
|
|
47
|
+
Not migrating leaves a type error at each call site rather than a silent
|
|
48
|
+
behaviour change.
|
|
49
|
+
|
|
50
|
+
Hosts using `@sanity/workflow-studio` or `@sanity/workflow-sdk` get the catalog
|
|
51
|
+
without changes: both adapters fetch it beside the member list, each behind a
|
|
52
|
+
per-client, per-project cache, so it costs one extra request per project per page
|
|
53
|
+
load however many surfaces read it. A failed roles read is deliberately
|
|
54
|
+
non-fatal — it degrades to the previous member-derived behaviour rather than
|
|
55
|
+
taking down the member list, and therefore every assignment control, with it. It
|
|
56
|
+
is reported once on the console with its cause, because nothing downstream can
|
|
57
|
+
tell an unreadable catalog from a project that defines no assignable roles. That
|
|
58
|
+
empty result is cached too, so a project whose catalog cannot be read stays on
|
|
59
|
+
the member-derived behaviour until the page reloads.
|
|
60
|
+
|
|
61
|
+
**Docs impact:** Update the assignment concepts and any Studio plugin guidance
|
|
62
|
+
that describes which roles can be assigned, to say the catalog is the source,
|
|
63
|
+
that a role with no holders is offered, and that a held role missing from the
|
|
64
|
+
catalog is not. The `@sanity/workflow-components` README covers the new
|
|
65
|
+
`RoleVocabulary` shape and the picker's behaviour.
|
|
66
|
+
|
|
67
|
+
### Patch Changes
|
|
68
|
+
|
|
69
|
+
- Updated dependencies [1e4a5da]
|
|
70
|
+
- Updated dependencies [6584554]
|
|
71
|
+
- Updated dependencies [f4405b4]
|
|
72
|
+
- Updated dependencies [5050b06]
|
|
73
|
+
- Updated dependencies [a044ba5]
|
|
74
|
+
- @sanity/workflow-engine@0.28.0
|
|
75
|
+
- @sanity/workflow-sdk@0.28.0
|
|
76
|
+
- @sanity/workflow-react@0.28.0
|
|
77
|
+
|
|
3
78
|
## 0.27.0
|
|
4
79
|
|
|
5
80
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -33,10 +33,16 @@ Studio source context (`useSource` / `useClient`).
|
|
|
33
33
|
errors surface reactively through `error`.
|
|
34
34
|
- `useStudioProjectUsers` — the shared Studio project-user directory used by
|
|
35
35
|
actor resolution and member pickers. It returns the upstream membership and
|
|
36
|
-
profile records without an Editorial Workflows projection,
|
|
37
|
-
`ProjectUserDirectory` integration.
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
profile records without an Editorial Workflows projection, the project's
|
|
37
|
+
assignable `roles`, and the engine's `ProjectUserDirectory` integration. The
|
|
38
|
+
role catalog is read alongside the memberships and is the only account of a
|
|
39
|
+
role nobody currently holds; it is filtered to roles a person can be assigned,
|
|
40
|
+
and it is empty when the read is unavailable, which leaves role labels to the
|
|
41
|
+
roles members hold and is reported once on the console with its cause.
|
|
42
|
+
Concurrent loads are coalesced, the settled successful directory is reused for
|
|
43
|
+
the client/project lifetime, and a failed membership load retries after a
|
|
44
|
+
30-second backoff. That backoff does not cover the catalog: an unavailable one
|
|
45
|
+
is held empty for the client's lifetime rather than re-read. A directory that has not
|
|
40
46
|
answered reports `loading`, including before its fetch starts (the fetch
|
|
41
47
|
begins in a consumer's effect), so an empty `users` with `loading: false`
|
|
42
48
|
and no `error` is a confirmed "no members" rather than a directory nobody
|
package/dist/index.cjs
CHANGED
|
@@ -226,6 +226,7 @@ const projectUsersByClient = /* @__PURE__ */ new WeakMap;
|
|
|
226
226
|
function createProjectUsersStore(client, projectId) {
|
|
227
227
|
let snapshot = {
|
|
228
228
|
users: [],
|
|
229
|
+
roles: [],
|
|
229
230
|
loading: !0,
|
|
230
231
|
error: void 0
|
|
231
232
|
}, pending, retryAt = 0, usersById = /* @__PURE__ */ new Map, usersByEmail = /* @__PURE__ */ new Map;
|
|
@@ -238,18 +239,23 @@ function createProjectUsersStore(client, projectId) {
|
|
|
238
239
|
...snapshot,
|
|
239
240
|
loading: !0,
|
|
240
241
|
error: void 0
|
|
241
|
-
}), pending = fetchProjectUsers(client, projectId)
|
|
242
|
+
}), pending = Promise.all([ fetchProjectUsers(client, projectId), projectUsers.loadProjectRolesOrNone({
|
|
243
|
+
client: client,
|
|
244
|
+
projectId: projectId
|
|
245
|
+
}) ]).then(([users, roles]) => (usersById = new Map(users.flatMap(user => {
|
|
242
246
|
const entries = [ [ user.membership.id, user ] ], globalId = user.profile?.sanityUserId;
|
|
243
247
|
return globalId !== void 0 && globalId !== user.membership.id && entries.push([ globalId, user ]),
|
|
244
248
|
entries;
|
|
245
249
|
})), usersByEmail = new Map(users.flatMap(user => user.profile?.email ? [ [ user.profile.email.toLowerCase(), user ] ] : [])),
|
|
246
250
|
retryAt = 1 / 0, setSnapshot({
|
|
247
251
|
users: users,
|
|
252
|
+
roles: roles,
|
|
248
253
|
loading: !1,
|
|
249
254
|
error: void 0
|
|
250
255
|
}), pending = void 0, users), error => {
|
|
251
256
|
throw retryAt = Date.now() + PROJECT_USERS_RETRY_MS, setSnapshot({
|
|
252
257
|
users: [],
|
|
258
|
+
roles: [],
|
|
253
259
|
loading: !1,
|
|
254
260
|
error: error
|
|
255
261
|
}), pending = void 0, error;
|
|
@@ -316,6 +322,7 @@ function studioProjectUserDirectory(client, projectId) {
|
|
|
316
322
|
|
|
317
323
|
const missingProjectSnapshot = {
|
|
318
324
|
users: [],
|
|
325
|
+
roles: [],
|
|
319
326
|
loading: !1,
|
|
320
327
|
error: new Error("No projectId on the Studio client")
|
|
321
328
|
}, noopSubscribe = () => () => {};
|
package/dist/index.d.cts
CHANGED
|
@@ -6,6 +6,7 @@ import type { GdrUri } from "@sanity/workflow-engine";
|
|
|
6
6
|
import type { InstancesQueryFilter } from "@sanity/workflow-engine";
|
|
7
7
|
import { MissingHandlerPolicy } from "@sanity/workflow-engine";
|
|
8
8
|
import { MutationGuardDoc } from "@sanity/workflow-react";
|
|
9
|
+
import { ProjectRole } from "@sanity/workflow-sdk/project-users";
|
|
9
10
|
import { ProjectUserDirectory } from "@sanity/workflow-engine";
|
|
10
11
|
import { ProjectUserProfile } from "@sanity/workflow-sdk/project-users";
|
|
11
12
|
import { ResourceClientResolver } from "@sanity/workflow-engine";
|
|
@@ -61,6 +62,9 @@ export declare function studioProjectUserDirectory(
|
|
|
61
62
|
|
|
62
63
|
export declare interface StudioProjectUsersState {
|
|
63
64
|
readonly users: readonly StudioProjectUser[];
|
|
65
|
+
/** The project's assignable roles, whether or not anyone holds them. Empty
|
|
66
|
+
* when the read is unavailable — see {@link loadProjectRolesOrNone}. */
|
|
67
|
+
readonly roles: readonly ProjectRole[];
|
|
64
68
|
/** True while the directory has not answered, including before its load
|
|
65
69
|
* starts — the fetch begins in a consumer's effect or the first directory
|
|
66
70
|
* lookup, one commit after the first render reads this state. An empty
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { GdrUri } from "@sanity/workflow-engine";
|
|
|
6
6
|
import type { InstancesQueryFilter } from "@sanity/workflow-engine";
|
|
7
7
|
import { MissingHandlerPolicy } from "@sanity/workflow-engine";
|
|
8
8
|
import { MutationGuardDoc } from "@sanity/workflow-react";
|
|
9
|
+
import { ProjectRole } from "@sanity/workflow-sdk/project-users";
|
|
9
10
|
import { ProjectUserDirectory } from "@sanity/workflow-engine";
|
|
10
11
|
import { ProjectUserProfile } from "@sanity/workflow-sdk/project-users";
|
|
11
12
|
import { ResourceClientResolver } from "@sanity/workflow-engine";
|
|
@@ -61,6 +62,9 @@ export declare function studioProjectUserDirectory(
|
|
|
61
62
|
|
|
62
63
|
export declare interface StudioProjectUsersState {
|
|
63
64
|
readonly users: readonly StudioProjectUser[];
|
|
65
|
+
/** The project's assignable roles, whether or not anyone holds them. Empty
|
|
66
|
+
* when the read is unavailable — see {@link loadProjectRolesOrNone}. */
|
|
67
|
+
readonly roles: readonly ProjectRole[];
|
|
64
68
|
/** True while the directory has not answered, including before its load
|
|
65
69
|
* starts — the fetch begins in a consumer's effect or the first directory
|
|
66
70
|
* lookup, one commit after the first render reads this state. An empty
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import { useSource, useClient } from "sanity";
|
|
|
12
12
|
|
|
13
13
|
import { useWorkflowTelemetry, useWorkflowSession as useWorkflowSession$1, useDocumentWorkflows as useDocumentWorkflows$1, useWorkflowInstances as useWorkflowInstances$1 } from "@sanity/workflow-react";
|
|
14
14
|
|
|
15
|
-
import { loadProjectUserProfiles } from "@sanity/workflow-sdk/project-users";
|
|
15
|
+
import { loadProjectRolesOrNone, loadProjectUserProfiles } from "@sanity/workflow-sdk/project-users";
|
|
16
16
|
|
|
17
17
|
function makeStudioObserver(sdk, options) {
|
|
18
18
|
const {client: client, engineResource: engineResource} = options;
|
|
@@ -234,6 +234,7 @@ const projectUsersByClient = /* @__PURE__ */ new WeakMap;
|
|
|
234
234
|
function createProjectUsersStore(client, projectId) {
|
|
235
235
|
let snapshot = {
|
|
236
236
|
users: [],
|
|
237
|
+
roles: [],
|
|
237
238
|
loading: !0,
|
|
238
239
|
error: void 0
|
|
239
240
|
}, pending, retryAt = 0, usersById = /* @__PURE__ */ new Map, usersByEmail = /* @__PURE__ */ new Map;
|
|
@@ -246,18 +247,23 @@ function createProjectUsersStore(client, projectId) {
|
|
|
246
247
|
...snapshot,
|
|
247
248
|
loading: !0,
|
|
248
249
|
error: void 0
|
|
249
|
-
}), pending = fetchProjectUsers(client, projectId)
|
|
250
|
+
}), pending = Promise.all([ fetchProjectUsers(client, projectId), loadProjectRolesOrNone({
|
|
251
|
+
client: client,
|
|
252
|
+
projectId: projectId
|
|
253
|
+
}) ]).then(([users, roles]) => (usersById = new Map(users.flatMap(user => {
|
|
250
254
|
const entries = [ [ user.membership.id, user ] ], globalId = user.profile?.sanityUserId;
|
|
251
255
|
return globalId !== void 0 && globalId !== user.membership.id && entries.push([ globalId, user ]),
|
|
252
256
|
entries;
|
|
253
257
|
})), usersByEmail = new Map(users.flatMap(user => user.profile?.email ? [ [ user.profile.email.toLowerCase(), user ] ] : [])),
|
|
254
258
|
retryAt = 1 / 0, setSnapshot({
|
|
255
259
|
users: users,
|
|
260
|
+
roles: roles,
|
|
256
261
|
loading: !1,
|
|
257
262
|
error: void 0
|
|
258
263
|
}), pending = void 0, users), error => {
|
|
259
264
|
throw retryAt = Date.now() + PROJECT_USERS_RETRY_MS, setSnapshot({
|
|
260
265
|
users: [],
|
|
266
|
+
roles: [],
|
|
261
267
|
loading: !1,
|
|
262
268
|
error: error
|
|
263
269
|
}), pending = void 0, error;
|
|
@@ -324,6 +330,7 @@ function studioProjectUserDirectory(client, projectId) {
|
|
|
324
330
|
|
|
325
331
|
const missingProjectSnapshot = {
|
|
326
332
|
users: [],
|
|
333
|
+
roles: [],
|
|
327
334
|
loading: !1,
|
|
328
335
|
error: new Error("No projectId on the Studio client")
|
|
329
336
|
}, noopSubscribe = () => () => {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/workflow-studio",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"description": "React adapter that drives the @sanity/workflow-engine reactive session in Sanity Studio through the App SDK store.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -50,17 +50,17 @@
|
|
|
50
50
|
"react-dom": "^19.2.7",
|
|
51
51
|
"sanity": "^6",
|
|
52
52
|
"vitest": "^4.1.8",
|
|
53
|
-
"@sanity/workflow-
|
|
54
|
-
"@sanity/workflow-
|
|
55
|
-
"@sanity/workflow-sdk": "0.
|
|
53
|
+
"@sanity/workflow-engine": "0.29.0",
|
|
54
|
+
"@sanity/workflow-react": "0.29.0",
|
|
55
|
+
"@sanity/workflow-sdk": "0.29.0"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"@sanity/sdk": "^2.12.0",
|
|
59
59
|
"react": "^19.2.7",
|
|
60
60
|
"sanity": "^6",
|
|
61
|
-
"@sanity/workflow-react": "0.
|
|
62
|
-
"@sanity/workflow-
|
|
63
|
-
"@sanity/workflow-
|
|
61
|
+
"@sanity/workflow-react": "0.29.0",
|
|
62
|
+
"@sanity/workflow-engine": "0.29.0",
|
|
63
|
+
"@sanity/workflow-sdk": "0.29.0"
|
|
64
64
|
},
|
|
65
65
|
"engines": {
|
|
66
66
|
"node": ">=20"
|