@instructure/platform-institutional-tagging 8.0.2 → 8.0.4
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/constants/i18n.d.ts +1 -0
- package/dist/constants/i18n.d.ts.map +1 -1
- package/dist/hooks/useAccountTagsScreen.d.ts.map +1 -1
- package/dist/hooks/useAddPeople.d.ts.map +1 -1
- package/dist/hooks/useAllActiveTags.d.ts.map +1 -1
- package/dist/hooks/useAllCategories.d.ts.map +1 -1
- package/dist/hooks/useAllTagNames.d.ts.map +1 -1
- package/dist/hooks/useArchiveCategory.d.ts.map +1 -1
- package/dist/hooks/useArchiveTag.d.ts.map +1 -1
- package/dist/hooks/useAssignTagsToUser.d.ts.map +1 -1
- package/dist/hooks/useCreateCategory.d.ts.map +1 -1
- package/dist/hooks/useFetchAccountUsers.d.ts.map +1 -1
- package/dist/hooks/useFetchExistingTagUserIds.d.ts.map +1 -1
- package/dist/hooks/useFetchTagUsers.d.ts.map +1 -1
- package/dist/hooks/useFetchTagsForCategory.d.ts.map +1 -1
- package/dist/hooks/useFetchUserTags.d.ts.map +1 -1
- package/dist/hooks/useMoveTag.d.ts.map +1 -1
- package/dist/hooks/useRemoveTagUser.d.ts.map +1 -1
- package/dist/hooks/useRemoveUserTag.d.ts.map +1 -1
- package/dist/hooks/useRestoreCategory.d.ts.map +1 -1
- package/dist/hooks/useRestoreTag.d.ts.map +1 -1
- package/dist/index.js +3848 -3710
- package/dist/modals/CategoryModal/hooks/useEditCategoryForm.d.ts.map +1 -1
- package/dist/modals/TagModal/hooks/useCreateTagForm.d.ts.map +1 -1
- package/dist/modals/TagModal/hooks/useEditTagForm.d.ts.map +1 -1
- package/dist/query/__tests__/map.test.d.ts +2 -0
- package/dist/query/__tests__/map.test.d.ts.map +1 -0
- package/dist/query/events.d.ts +71 -0
- package/dist/query/events.d.ts.map +1 -0
- package/dist/query/index.d.ts +5 -0
- package/dist/query/index.d.ts.map +1 -0
- package/dist/query/keys.d.ts +83 -0
- package/dist/query/keys.d.ts.map +1 -0
- package/dist/query/map.d.ts +20 -0
- package/dist/query/map.d.ts.map +1 -0
- package/dist/query/ops.d.ts +41 -0
- package/dist/query/ops.d.ts.map +1 -0
- package/dist/query/useCacheInvalidator.d.ts +49 -0
- package/dist/query/useCacheInvalidator.d.ts.map +1 -0
- package/locales/en.json +1 -0
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useEditCategoryForm.d.ts","sourceRoot":"","sources":["../../../../src/modals/CategoryModal/hooks/useEditCategoryForm.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAGxD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"useEditCategoryForm.d.ts","sourceRoot":"","sources":["../../../../src/modals/CategoryModal/hooks/useEditCategoryForm.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAGxD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAQjD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAE9C,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,UAAU,yBAAyB;IACjC,QAAQ,EAAE,YAAY,CAAA;IACtB,SAAS,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC,CAAA;CAC5D;AAED,UAAU,yBAAyB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,WAAW,EAAE,CAAA;IACxB,mBAAmB,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,CAAA;IAC3C,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACrC,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CAC7C;AAED,eAAO,MAAM,mBAAmB,GAAI,0BAGjC,yBAAyB,KAAG,yBAmF9B,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCreateTagForm.d.ts","sourceRoot":"","sources":["../../../../src/modals/TagModal/hooks/useCreateTagForm.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAGxD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"useCreateTagForm.d.ts","sourceRoot":"","sources":["../../../../src/modals/TagModal/hooks/useCreateTagForm.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAGxD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAOjD,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,UAAU,sBAAsB;IAC9B,SAAS,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC,CAAA;IAC3D,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED,UAAU,sBAAsB;IAC9B,YAAY,EAAE,WAAW,EAAE,CAAA;IAC3B,mBAAmB,EAAE,WAAW,EAAE,CAAA;IAClC,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACxC,sBAAsB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/C,kBAAkB,EAAE,OAAO,CAAA;IAC3B,aAAa,EAAE,WAAW,EAAE,CAAA;IAC5B,eAAe,EAAE,MAAM,CAAA;IACvB,oBAAoB,EAAE,WAAW,EAAE,CAAA;IACnC,mBAAmB,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,CAAA;IAC3C,eAAe,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,CAAA;IACvC,iBAAiB,EAAE,MAAM,CAAA;IACzB,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,iBAAiB,EAAE,OAAO,CAAA;IAC1B,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACtC,uBAAuB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAChD,8BAA8B,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACxD;AAED,eAAO,MAAM,gBAAgB,GAAI,mCAG9B,sBAAsB,KAAG,sBA8H3B,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useEditTagForm.d.ts","sourceRoot":"","sources":["../../../../src/modals/TagModal/hooks/useEditTagForm.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAGxD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"useEditTagForm.d.ts","sourceRoot":"","sources":["../../../../src/modals/TagModal/hooks/useEditTagForm.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAGxD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAMjD,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEpC,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,UAAU,oBAAoB;IAC5B,GAAG,EAAE,OAAO,CAAA;IACZ,SAAS,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC,CAAA;CAC5D;AAED,UAAU,oBAAoB;IAC5B,YAAY,EAAE,WAAW,EAAE,CAAA;IAC3B,mBAAmB,EAAE,WAAW,EAAE,CAAA;IAClC,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACxC,sBAAsB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/C,kBAAkB,EAAE,OAAO,CAAA;IAC3B,aAAa,EAAE,WAAW,EAAE,CAAA;IAC5B,eAAe,EAAE,MAAM,CAAA;IACvB,oBAAoB,EAAE,WAAW,EAAE,CAAA;IACnC,mBAAmB,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,CAAA;IAC3C,eAAe,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,CAAA;IACvC,iBAAiB,EAAE,MAAM,CAAA;IACzB,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAA;IACxC,iBAAiB,EAAE,OAAO,CAAA;IAC1B,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACtC,uBAAuB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAChD,8BAA8B,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACxD;AAED,eAAO,MAAM,cAAc,GAAI,oBAAoB,oBAAoB,KAAG,oBAsIzE,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"map.test.d.ts","sourceRoot":"","sources":["../../../src/query/__tests__/map.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The taxonomy of cache-affecting mutations in this package, mapped to the
|
|
3
|
+
* context each one needs to resolve its invalidation set.
|
|
4
|
+
*
|
|
5
|
+
* Association events are split by *view side* on purpose. `AccountTags` (tag
|
|
6
|
+
* side) and `UserProfileTags` (user side) are separate exported entry points
|
|
7
|
+
* that Canvas mounts in different features / on different pages — separate page
|
|
8
|
+
* loads, so their query caches are never live at the same time. A tag-side write
|
|
9
|
+
* therefore never needs to touch user-side reads and vice versa; splitting lets
|
|
10
|
+
* each side invalidate only what its own page can display.
|
|
11
|
+
*
|
|
12
|
+
* An empty context (`{}`) means the event invalidates only bare-prefix roots and
|
|
13
|
+
* needs no entity ids; `useCacheInvalidator` lets callers omit the ctx argument
|
|
14
|
+
* for those events.
|
|
15
|
+
*/
|
|
16
|
+
export interface InvalidationEventContext {
|
|
17
|
+
'category.created': Record<string, never>;
|
|
18
|
+
'category.updated': Record<string, never>;
|
|
19
|
+
'category.archived': {
|
|
20
|
+
categoryId: string;
|
|
21
|
+
};
|
|
22
|
+
'category.restored': {
|
|
23
|
+
categoryId: string;
|
|
24
|
+
};
|
|
25
|
+
/** `categoryCreated` when a brand-new category was created inline as part of tag creation. */
|
|
26
|
+
'tag.created': {
|
|
27
|
+
categoryId: string;
|
|
28
|
+
categoryCreated?: boolean;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* `previousCategoryId` when an edit moved the tag between categories;
|
|
32
|
+
* `categoryCreated` when a brand-new category was created inline during the edit.
|
|
33
|
+
*/
|
|
34
|
+
'tag.updated': {
|
|
35
|
+
tagId: string;
|
|
36
|
+
categoryId: string;
|
|
37
|
+
previousCategoryId?: string;
|
|
38
|
+
categoryCreated?: boolean;
|
|
39
|
+
};
|
|
40
|
+
'tag.archived': {
|
|
41
|
+
tagId: string;
|
|
42
|
+
categoryId: string;
|
|
43
|
+
};
|
|
44
|
+
/** `newCategoryId` when a restore also moves the tag to a different category. */
|
|
45
|
+
'tag.restored': {
|
|
46
|
+
tagId: string;
|
|
47
|
+
categoryId: string;
|
|
48
|
+
newCategoryId?: string;
|
|
49
|
+
};
|
|
50
|
+
'tag.moved': {
|
|
51
|
+
fromCategoryId: string;
|
|
52
|
+
toCategoryId: string;
|
|
53
|
+
};
|
|
54
|
+
/** `categoryId` scopes the tag-cache eviction to one category; omit to fall back to all. */
|
|
55
|
+
'people.addedToTag': {
|
|
56
|
+
tagId: string;
|
|
57
|
+
categoryId?: string;
|
|
58
|
+
};
|
|
59
|
+
'people.removedFromTag': {
|
|
60
|
+
tagId: string;
|
|
61
|
+
categoryId?: string;
|
|
62
|
+
};
|
|
63
|
+
'tags.addedToUser': {
|
|
64
|
+
userId: string;
|
|
65
|
+
};
|
|
66
|
+
'tags.removedFromUser': {
|
|
67
|
+
userId: string;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export type InvalidationEvent = keyof InvalidationEventContext;
|
|
71
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/query/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,wBAAwB;IACvC,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;IACzC,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;IACzC,mBAAmB,EAAE;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAA;IAC3C,mBAAmB,EAAE;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAA;IAC3C,8FAA8F;IAC9F,aAAa,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,CAAA;IAChE;;;OAGG;IACH,aAAa,EAAE;QACb,KAAK,EAAE,MAAM,CAAA;QACb,UAAU,EAAE,MAAM,CAAA;QAClB,kBAAkB,CAAC,EAAE,MAAM,CAAA;QAC3B,eAAe,CAAC,EAAE,OAAO,CAAA;KAC1B,CAAA;IACD,cAAc,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAA;IACrD,iFAAiF;IACjF,cAAc,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC7E,WAAW,EAAE;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAA;IAC7D,4FAA4F;IAC5F,mBAAmB,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC3D,uBAAuB,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/D,kBAAkB,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACtC,sBAAsB,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAC3C;AAED,MAAM,MAAM,iBAAiB,GAAG,MAAM,wBAAwB,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { queryKeys } from './keys';
|
|
2
|
+
export { useCacheInvalidator, type InvalidateOptions } from './useCacheInvalidator';
|
|
3
|
+
export type { InvalidationEvent, InvalidationEventContext } from './events';
|
|
4
|
+
export type { CacheOp } from './ops';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAClC,OAAO,EAAE,mBAAmB,EAAE,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AACnF,YAAY,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAC3E,YAAY,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { InstitutionalTagUsersSortInput, InstitutionalTagWorkflowState } from '@instructure/platform-graphql-types';
|
|
2
|
+
import { WorkflowState } from '../types/state';
|
|
3
|
+
/**
|
|
4
|
+
* Single source of truth for every TanStack Query key used in this package.
|
|
5
|
+
*
|
|
6
|
+
* Each namespace exposes two shapes:
|
|
7
|
+
* - `root` (and scoped prefixes like `inCategory`/`forTag`): the bare prefix
|
|
8
|
+
* used for INVALIDATION. TanStack matches keys by array prefix, so
|
|
9
|
+
* `['tags']` matches every `['tags', categoryId, cursor, workflowState]`
|
|
10
|
+
* variant and `['userTags', userId]` matches `['userTags', userId, accountId]`.
|
|
11
|
+
* This is why invalidation never needs `accountId` — the prefix matches
|
|
12
|
+
* regardless.
|
|
13
|
+
* - `list`/`of`: the FULL key used by a read hook's `useQuery`.
|
|
14
|
+
*
|
|
15
|
+
* The full-key builders reproduce the exact array shapes the hooks used before
|
|
16
|
+
* this factory existed, so migrating a read hook to the factory is
|
|
17
|
+
* behavior-preserving (same cache identity). Standardizing the `accountId`
|
|
18
|
+
* position across keys is a deliberately deferred follow-up.
|
|
19
|
+
*/
|
|
20
|
+
export declare const queryKeys: {
|
|
21
|
+
/** Paginated category list on the AccountTags screen. */
|
|
22
|
+
readonly categories: {
|
|
23
|
+
readonly root: readonly ["categories"];
|
|
24
|
+
readonly list: (cursor: string | null, searchTerm: string, workflowState: WorkflowState) => readonly ["categories", string | null, string, WorkflowState];
|
|
25
|
+
};
|
|
26
|
+
/** Full active-category list (autocompletes); account-scoped. */
|
|
27
|
+
readonly allCategories: {
|
|
28
|
+
readonly root: readonly ["allCategories"];
|
|
29
|
+
readonly of: (accountId: string) => readonly ["allCategories", string];
|
|
30
|
+
};
|
|
31
|
+
/** Per-category paginated tag list. */
|
|
32
|
+
readonly tags: {
|
|
33
|
+
readonly root: readonly ["tags"];
|
|
34
|
+
readonly inCategory: (categoryId: string) => readonly ["tags", string];
|
|
35
|
+
readonly list: (categoryId: string, cursor: string | null, workflowState?: InstitutionalTagWorkflowState) => readonly ["tags", string, string | null, InstitutionalTagWorkflowState | undefined];
|
|
36
|
+
};
|
|
37
|
+
/** Flat list of active tag names (duplicate-suggestion combobox); account-scoped. */
|
|
38
|
+
readonly allTagNames: {
|
|
39
|
+
readonly root: readonly ["allTagNames"];
|
|
40
|
+
readonly of: (accountId: string) => readonly ["allTagNames", string];
|
|
41
|
+
};
|
|
42
|
+
/** All active tags grouped by category (AssignTagsModal); account-scoped. */
|
|
43
|
+
readonly allActiveTags: {
|
|
44
|
+
readonly root: readonly ["allActiveTags"];
|
|
45
|
+
readonly of: (accountId: string) => readonly ["allActiveTags", string];
|
|
46
|
+
};
|
|
47
|
+
/** Users tagged with a single tag (TagDetail people table). */
|
|
48
|
+
readonly tagUsers: {
|
|
49
|
+
readonly root: readonly ["tagUsers"];
|
|
50
|
+
readonly forTag: (tagId: string) => readonly ["tagUsers", string];
|
|
51
|
+
readonly list: (tagId: string, cursor: string | null, sort?: InstitutionalTagUsersSortInput, searchTerm?: string) => readonly ["tagUsers", string, string | null, InstitutionalTagUsersSortInput | undefined, string | undefined];
|
|
52
|
+
};
|
|
53
|
+
/** The already-tagged user-id set used to exclude users in AddPeopleModal. */
|
|
54
|
+
readonly tagExistingUsers: {
|
|
55
|
+
readonly root: readonly ["tagExistingUsers"];
|
|
56
|
+
readonly forTag: (tagId: string) => readonly ["tagExistingUsers", string];
|
|
57
|
+
};
|
|
58
|
+
/** Tags applied to a single user (UserProfileTags); account-scoped. */
|
|
59
|
+
readonly userTags: {
|
|
60
|
+
readonly root: readonly ["userTags"];
|
|
61
|
+
readonly forUser: (userId: string) => readonly ["userTags", string];
|
|
62
|
+
readonly of: (userId: string, accountId: string) => readonly ["userTags", string, string];
|
|
63
|
+
};
|
|
64
|
+
/** Account users for the AddPeopleModal manual search; account-scoped. */
|
|
65
|
+
readonly accountUsers: {
|
|
66
|
+
readonly root: readonly ["accountUsers"];
|
|
67
|
+
readonly list: (accountId: string, searchTerm: string, cursor: string | null) => readonly ["accountUsers", string, string, string | null];
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* The union of every key shape the factory can produce — each namespace's
|
|
72
|
+
* `root` tuple plus every builder's return tuple. `inv()`/`remove()` accept only
|
|
73
|
+
* this, so a hand-written array literal in the invalidation map (e.g. a typo'd
|
|
74
|
+
* `['tag']`) fails to type-check and every invalidation is forced through the
|
|
75
|
+
* factory. Keeps the factory the single source of truth at compile time, not
|
|
76
|
+
* just by convention.
|
|
77
|
+
*/
|
|
78
|
+
type ExtractQueryKey<T> = T extends readonly unknown[] ? T : T extends (...args: never[]) => infer R ? R extends readonly unknown[] ? R : never : T extends object ? {
|
|
79
|
+
[K in keyof T]: ExtractQueryKey<T[K]>;
|
|
80
|
+
}[keyof T] : never;
|
|
81
|
+
export type FactoryQueryKey = ExtractQueryKey<typeof queryKeys>;
|
|
82
|
+
export {};
|
|
83
|
+
//# sourceMappingURL=keys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/query/keys.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,8BAA8B,EAC9B,6BAA6B,EAC9B,MAAM,qCAAqC,CAAA;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAEjD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,SAAS;IACpB,yDAAyD;;;gCAGxC,MAAM,GAAG,IAAI,cAAc,MAAM,iBAAiB,aAAa;;IAGhF,iEAAiE;;;iCAG/C,MAAM;;IAExB,uCAAuC;;;0CAGZ,MAAM;oCAEjB,MAAM,UACV,MAAM,GAAG,IAAI,kBACL,6BAA6B;;IAGjD,qFAAqF;;;iCAGnE,MAAM;;IAExB,6EAA6E;;;iCAG3D,MAAM;;IAExB,+DAA+D;;;iCAG7C,MAAM;+BAEb,MAAM,UACL,MAAM,GAAG,IAAI,SACd,8BAA8B,eACxB,MAAM;;IAGvB,8EAA8E;;;iCAG5D,MAAM;;IAExB,uEAAuE;;;mCAGnD,MAAM;8BACX,MAAM,aAAa,MAAM;;IAExC,0EAA0E;;;mCAGtD,MAAM,cAAc,MAAM,UAAU,MAAM,GAAG,IAAI;;CAG7D,CAAA;AAEV;;;;;;;GAOG;AACH,KAAK,eAAe,CAAC,CAAC,IAAI,CAAC,SAAS,SAAS,OAAO,EAAE,GAClD,CAAC,GACD,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,MAAM,CAAC,GACrC,CAAC,SAAS,SAAS,OAAO,EAAE,GAC1B,CAAC,GACD,KAAK,GACP,CAAC,SAAS,MAAM,GACd;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,CAAC,MAAM,CAAC,CAAC,GAClD,KAAK,CAAA;AAEb,MAAM,MAAM,eAAe,GAAG,eAAe,CAAC,OAAO,SAAS,CAAC,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { InvalidationEvent, InvalidationEventContext } from './events';
|
|
2
|
+
import { CacheOp } from './ops';
|
|
3
|
+
/**
|
|
4
|
+
* THE invalidation contract. For each mutation event, the exact set of cache
|
|
5
|
+
* operations that keeps every dependent read coherent. This is the single place
|
|
6
|
+
* a developer edits when a mutation's data footprint changes — hooks just fire
|
|
7
|
+
* the event.
|
|
8
|
+
*
|
|
9
|
+
* `inv()` ops use TanStack's default `'active'` refetch scope: they refresh the
|
|
10
|
+
* consumers mounted right now and mark everything else stale. Canvas runs these
|
|
11
|
+
* components under the `@instructure/platform-query` client (`staleTime: 0` +
|
|
12
|
+
* `refetchOnMount: true`), so an unmounted consumer refetches when it remounts —
|
|
13
|
+
* the map only needs to name the reads each mutation affects.
|
|
14
|
+
*/
|
|
15
|
+
type InvalidationMap = {
|
|
16
|
+
[E in InvalidationEvent]: (ctx: InvalidationEventContext[E]) => readonly CacheOp[];
|
|
17
|
+
};
|
|
18
|
+
export declare const invalidationMap: InvalidationMap;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=map.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"map.d.ts","sourceRoot":"","sources":["../../src/query/map.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAC3E,OAAO,EAAE,KAAK,OAAO,EAAc,MAAM,OAAO,CAAA;AAGhD;;;;;;;;;;;GAWG;AACH,KAAK,eAAe,GAAG;KACpB,CAAC,IAAI,iBAAiB,GAAG,CAAC,GAAG,EAAE,wBAAwB,CAAC,CAAC,CAAC,KAAK,SAAS,OAAO,EAAE;CACnF,CAAA;AAwED,eAAO,MAAM,eAAe,EAAE,eA+C7B,CAAA"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { FactoryQueryKey } from './keys';
|
|
2
|
+
/**
|
|
3
|
+
* A single cache mutation the invalidator applies after a mutation settles.
|
|
4
|
+
*
|
|
5
|
+
* - `invalidate`: mark the (prefix-matched) key stale; the invalidator uses
|
|
6
|
+
* TanStack's default `'active'` refetch scope, so currently-mounted consumers
|
|
7
|
+
* refetch immediately and everything else is left stale to refetch on its next
|
|
8
|
+
* mount. That is sufficient because Canvas runs these components under the
|
|
9
|
+
* `@instructure/platform-query` client (`staleTime: 0` + `refetchOnMount: true`),
|
|
10
|
+
* so an unmounted consumer (a closed modal, another screen) always refetches
|
|
11
|
+
* when it remounts. The map therefore encodes *which reads a mutation affects*;
|
|
12
|
+
* its job is to refresh the views that are on screen right now.
|
|
13
|
+
* - `reset`: discard the cached data for every prefix match, then refetch the
|
|
14
|
+
* mounted ones. For keys where a *stale cached page* would be wrong rather than
|
|
15
|
+
* merely dated — in practice the cursor-paginated per-category tag list (see
|
|
16
|
+
* `perCategoryTagCache` in map.ts).
|
|
17
|
+
*/
|
|
18
|
+
export type CacheOp = {
|
|
19
|
+
readonly kind: 'invalidate';
|
|
20
|
+
readonly queryKey: FactoryQueryKey;
|
|
21
|
+
} | {
|
|
22
|
+
readonly kind: 'reset';
|
|
23
|
+
readonly queryKey: FactoryQueryKey;
|
|
24
|
+
};
|
|
25
|
+
/** Invalidate a key (prefix match). Accepts only factory-produced keys. */
|
|
26
|
+
export declare const inv: (queryKey: FactoryQueryKey) => CacheOp;
|
|
27
|
+
/**
|
|
28
|
+
* Drop the cached data behind a key (prefix match) and refetch whatever is
|
|
29
|
+
* mounted. Use only where a stale cached page is *incorrect* rather than merely
|
|
30
|
+
* dated — the per-category tag list, where replaying a cursor captured before the
|
|
31
|
+
* write duplicates or drops a tag across pages.
|
|
32
|
+
*
|
|
33
|
+
* Backed by `resetQueries`, deliberately not `removeQueries`. Both drop the cached
|
|
34
|
+
* pages, but `removeQueries` detaches a mounted observer from the cache without
|
|
35
|
+
* refetching it, leaving an on-screen tag list showing the pre-mutation tags
|
|
36
|
+
* (covered in staleness.regression.test.tsx). `resetQueries` clears the same
|
|
37
|
+
* entries and refetches the active ones, so the eviction cannot silently cost us
|
|
38
|
+
* the refresh.
|
|
39
|
+
*/
|
|
40
|
+
export declare const reset: (queryKey: FactoryQueryKey) => CacheOp;
|
|
41
|
+
//# sourceMappingURL=ops.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ops.d.ts","sourceRoot":"","sources":["../../src/query/ops.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAA;AAE7C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,OAAO,GACf;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAA;CAAE,GACnE;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAA;CAAE,CAAA;AAElE,2EAA2E;AAC3E,eAAO,MAAM,GAAG,GAAI,UAAU,eAAe,KAAG,OAA6C,CAAA;AAE7F;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,KAAK,GAAI,UAAU,eAAe,KAAG,OAAwC,CAAA"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { InvalidationEvent, InvalidationEventContext } from './events';
|
|
2
|
+
type EmptyCtx = Record<string, never>;
|
|
3
|
+
export interface InvalidateOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Await the invalidation + refetch pass. Needed where downstream cache
|
|
6
|
+
* ordering depends on it (e.g. `useMoveTag` must finish evicting/refetching
|
|
7
|
+
* before the drag UI settles). Defaults to fire-and-forget, matching the
|
|
8
|
+
* behavior of the hooks this replaces.
|
|
9
|
+
*/
|
|
10
|
+
await?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Arguments after the event name. Events whose context is empty (`{}`) may omit
|
|
14
|
+
* the ctx argument entirely; all others must supply it. `options` is always
|
|
15
|
+
* optional.
|
|
16
|
+
*/
|
|
17
|
+
type InvalidateArgs<E extends InvalidationEvent> = InvalidationEventContext[E] extends EmptyCtx ? [ctx?: InvalidationEventContext[E], options?: InvalidateOptions] : [ctx: InvalidationEventContext[E], options?: InvalidateOptions];
|
|
18
|
+
/**
|
|
19
|
+
* The single entry point mutations use to keep the cache coherent. Resolves the
|
|
20
|
+
* declarative {@link invalidationMap} for the given event and applies each cache
|
|
21
|
+
* operation — `invalidateQueries` (TanStack's default `'active'` scope: refetch
|
|
22
|
+
* the mounted consumers now, mark the rest stale so they refetch on next mount)
|
|
23
|
+
* or `resetQueries`.
|
|
24
|
+
*
|
|
25
|
+
* const invalidate = useCacheInvalidator()
|
|
26
|
+
* invalidate('tag.archived', { tagId, categoryId }) // fire-and-forget
|
|
27
|
+
* await invalidate('tag.moved', { fromCategoryId, toCategoryId }, { await: true })
|
|
28
|
+
*
|
|
29
|
+
* Fire the event on a mutation's **error** paths too, not just onSuccess:
|
|
30
|
+
*
|
|
31
|
+
* - `onError` (transport failure / rejection) — **always**. The outcome is
|
|
32
|
+
* unknown; the write may have committed before the connection dropped, so the
|
|
33
|
+
* cache cannot be trusted.
|
|
34
|
+
* - payload `errors` (the server answered and refused) — only when the refusal
|
|
35
|
+
* itself proves the cache disagrees with the server: "already archived",
|
|
36
|
+
* "already active", "association not found". A plain validation refusal on a
|
|
37
|
+
* create/update ("has already been taken", "can't be blank") changed nothing
|
|
38
|
+
* server-side, so there is nothing to resync.
|
|
39
|
+
*
|
|
40
|
+
* Inverse pairs have to match on all three paths. A symmetric `invalidationMap`
|
|
41
|
+
* does not help if only one half of a pair fires the event — that just moves the
|
|
42
|
+
* drift this layer exists to remove up to the call sites.
|
|
43
|
+
*
|
|
44
|
+
* For an empty-context event, ctx is optional; to await one, pass `undefined`
|
|
45
|
+
* explicitly for ctx: `await invalidate('category.created', undefined, { await: true })`.
|
|
46
|
+
*/
|
|
47
|
+
export declare const useCacheInvalidator: () => <E extends InvalidationEvent>(event: E, ...args: InvalidateArgs<E>) => Promise<void>;
|
|
48
|
+
export {};
|
|
49
|
+
//# sourceMappingURL=useCacheInvalidator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCacheInvalidator.d.ts","sourceRoot":"","sources":["../../src/query/useCacheInvalidator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAI3E,KAAK,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;AAErC,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED;;;;GAIG;AACH,KAAK,cAAc,CAAC,CAAC,SAAS,iBAAiB,IAAI,wBAAwB,CAAC,CAAC,CAAC,SAAS,QAAQ,GAC3F,CAAC,GAAG,CAAC,EAAE,wBAAwB,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,iBAAiB,CAAC,GAChE,CAAC,GAAG,EAAE,wBAAwB,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,iBAAiB,CAAC,CAAA;AAEnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,mBAAmB,SAI3B,CAAC,SAAS,iBAAiB,SAAS,CAAC,WAAW,cAAc,CAAC,CAAC,CAAC,KAAG,OAAO,CAAC,IAAI,CA2BpF,CAAA"}
|
package/locales/en.json
CHANGED
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"restoreTagCategoryRequired": "Select a category to restore the tag.",
|
|
56
56
|
"restoreTagFailed": "Failed to restore tag.",
|
|
57
57
|
"saveCategoryFailed": "Failed to save category. Please try again.",
|
|
58
|
+
"saveTagFailed": "Failed to save tag. Please try again.",
|
|
58
59
|
"tagAlreadyExists": "This tag name already exists.",
|
|
59
60
|
"tagDescriptionRequired": "Tag description is required.",
|
|
60
61
|
"tagMoveConflict": "A tag with this name already exists in the selected category.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@instructure/platform-institutional-tagging",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"@tanstack/react-query": "^5.0.0",
|
|
50
50
|
"react": "^18.0.0",
|
|
51
51
|
"react-dom": "^18.0.0",
|
|
52
|
-
"@instructure/platform-instui-bindings": "0.6.
|
|
52
|
+
"@instructure/platform-instui-bindings": "0.6.4",
|
|
53
53
|
"@instructure/platform-provider": "0.5.2"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"@instructure/ui-truncate-text": "11.6.0",
|
|
100
100
|
"@instructure/ui-utils": "11.6.0",
|
|
101
101
|
"@instructure/platform-graphql-types": "0.2.0",
|
|
102
|
-
"@instructure/platform-instui-bindings": "0.6.
|
|
102
|
+
"@instructure/platform-instui-bindings": "0.6.4"
|
|
103
103
|
},
|
|
104
104
|
"dependencies": {
|
|
105
105
|
"@dnd-kit/core": "^6.3.1",
|