@qoretechnologies/reqraft 0.10.65-pr.148.gf86d88c → 0.10.65

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 (70) hide show
  1. package/.claude/CLAUDE.md +0 -1
  2. package/dist/components/supportTicket/InterfaceReferenceTags.d.ts +1 -13
  3. package/dist/components/supportTicket/InterfaceReferenceTags.d.ts.map +1 -1
  4. package/dist/components/supportTicket/InterfaceReferenceTags.js +4 -11
  5. package/dist/components/supportTicket/InterfaceReferenceTags.js.map +1 -1
  6. package/dist/components/supportTicket/ReferencePicker.d.ts.map +1 -1
  7. package/dist/components/supportTicket/ReferencePicker.js +1 -1
  8. package/dist/components/supportTicket/ReferencePicker.js.map +1 -1
  9. package/dist/components/supportTicket/index.d.ts +0 -2
  10. package/dist/components/supportTicket/index.d.ts.map +1 -1
  11. package/dist/components/supportTicket/index.js +0 -2
  12. package/dist/components/supportTicket/index.js.map +1 -1
  13. package/dist/components/supportTicket/meta.d.ts +2 -62
  14. package/dist/components/supportTicket/meta.d.ts.map +1 -1
  15. package/dist/components/supportTicket/meta.js +3 -116
  16. package/dist/components/supportTicket/meta.js.map +1 -1
  17. package/dist/components/supportTicket/ticketModel.d.ts +0 -10
  18. package/dist/components/supportTicket/ticketModel.d.ts.map +1 -1
  19. package/dist/components/ticketReferences/TicketReferences.d.ts +1 -10
  20. package/dist/components/ticketReferences/TicketReferences.d.ts.map +1 -1
  21. package/dist/components/ticketReferences/TicketReferences.js +8 -12
  22. package/dist/components/ticketReferences/TicketReferences.js.map +1 -1
  23. package/dist/components/ticketThread/TicketThread.d.ts +1 -30
  24. package/dist/components/ticketThread/TicketThread.d.ts.map +1 -1
  25. package/dist/components/ticketThread/TicketThread.js +13 -51
  26. package/dist/components/ticketThread/TicketThread.js.map +1 -1
  27. package/dist/components/ticketThread/index.d.ts +1 -1
  28. package/dist/components/ticketThread/index.d.ts.map +1 -1
  29. package/dist/index.d.ts +1 -1
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js.map +1 -1
  32. package/dist/providers/StorageProvider.d.ts +0 -11
  33. package/dist/providers/StorageProvider.d.ts.map +1 -1
  34. package/dist/providers/StorageProvider.js +3 -21
  35. package/dist/providers/StorageProvider.js.map +1 -1
  36. package/dist/stores/currentUser/currentUser.d.ts +0 -42
  37. package/dist/stores/currentUser/currentUser.d.ts.map +1 -1
  38. package/dist/stores/currentUser/currentUser.js.map +1 -1
  39. package/package.json +9 -9
  40. package/src/components/form/engine/FormEngine.stories.tsx +5 -8
  41. package/src/components/form/fields/array/ArrayAutoField.stories.tsx +3 -6
  42. package/src/components/form/fields/boolean/Boolean.stories.tsx +3 -7
  43. package/src/components/form/fields/markdown/Markdown.stories.tsx +0 -6
  44. package/src/components/form/fields/radio-group/RadioGroup.stories.tsx +1 -4
  45. package/src/components/form/fields/template/TemplateField.stories.tsx +0 -4
  46. package/src/components/supportTicket/InterfaceReferenceTags.stories.tsx +0 -56
  47. package/src/components/supportTicket/InterfaceReferenceTags.tsx +7 -27
  48. package/src/components/supportTicket/ReferencePicker.tsx +1 -4
  49. package/src/components/supportTicket/index.ts +0 -2
  50. package/src/components/supportTicket/meta.ts +4 -156
  51. package/src/components/supportTicket/ticketModel.ts +0 -10
  52. package/src/components/ticketReferences/TicketReferences.stories.tsx +0 -40
  53. package/src/components/ticketReferences/TicketReferences.tsx +10 -24
  54. package/src/components/ticketThread/TicketThread.stories.tsx +1 -103
  55. package/src/components/ticketThread/TicketThread.tsx +15 -131
  56. package/src/components/ticketThread/index.ts +0 -1
  57. package/src/index.tsx +0 -1
  58. package/src/providers/StorageProvider.tsx +3 -20
  59. package/src/stores/currentUser/currentUser.tsx +0 -43
  60. package/dist/components/supportTicket/WorkspaceAccessStatus.d.ts +0 -55
  61. package/dist/components/supportTicket/WorkspaceAccessStatus.d.ts.map +0 -1
  62. package/dist/components/supportTicket/WorkspaceAccessStatus.js +0 -79
  63. package/dist/components/supportTicket/WorkspaceAccessStatus.js.map +0 -1
  64. package/dist/components/supportTicket/accessMeta.d.ts +0 -50
  65. package/dist/components/supportTicket/accessMeta.d.ts.map +0 -1
  66. package/dist/components/supportTicket/accessMeta.js +0 -174
  67. package/dist/components/supportTicket/accessMeta.js.map +0 -1
  68. package/src/components/supportTicket/WorkspaceAccessStatus.stories.tsx +0 -105
  69. package/src/components/supportTicket/WorkspaceAccessStatus.tsx +0 -176
  70. package/src/components/supportTicket/accessMeta.ts +0 -210
@@ -1 +1 @@
1
- {"version":3,"file":"currentUser.js","sourceRoot":"","sources":["../../../src/stores/currentUser/currentUser.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,mCAAiC;AACjC,2CAAmF;AA6EtE,QAAA,gBAAgB,GAAG,IAAA,gBAAM,EAAoB,UAAC,GAAG,EAAE,GAAG,IAAK,OAAA,CAAC;IACvE,WAAW,EAAE,SAAS;IACtB,OAAO,EAAE,KAAK;IACd,KAAK,EAAE,SAAS;IAChB,IAAI,EAAE;;;;;oBACJ,GAAG,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;;;;oBAKV,qBAAM,IAAA,aAAK,EAAe,EAAE,GAAG,EAAE,sBAAsB,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAA;;oBAAnF,QAAQ,GAAG,SAAwE,CAAC;;;;oBAEpF;;;;gFAI4D;oBAC5D,IAAI,IAAA,wBAAgB,EAAC,OAAK,CAAC,EAAE,CAAC;wBAC5B,GAAG,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;oBAC1B,CAAC;yBAAM,CAAC;wBACN,GAAG,CAAC;4BACF,OAAO,EAAE,KAAK;4BACd,KAAK,EAAE,OAAc;4BACrB,WAAW,EAAE,SAAS;4BACtB,SAAS,EAAE,SAAS;yBACrB,CAAC,CAAC;oBACL,CAAC;oBAED,sBAAO,OAAO,CAAC,MAAM,CAAC,OAAK,CAAC,EAAC;;oBAG/B,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;wBACjB,GAAG,CAAC;4BACF,OAAO,EAAE,KAAK;4BACd,KAAK,EAAE,QAAQ,CAAC,KAAK;4BACrB,WAAW,EAAE,SAAS;4BACtB,SAAS,EAAE,QAAQ,CAAC,IAAI;yBACzB,CAAC,CAAC;wBAEH,sBAAO,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAC;oBACxC,CAAC;oBAED,GAAG,CAAC,EAAE,WAAW,EAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;oBAE5F,sBAAO,QAAQ,CAAC,IAAI,EAAC;;;SACtB;IACD,gBAAgB,EAAE,UAAC,WAAW;QAC5B,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC;YACvB,OAAO,KAAK,CAAC;QACf,CAAC;QAEO,IAAA,WAAW,GAAK,GAAG,EAAE,YAAV,CAAW;QAE9B,OAAO,WAAW,CAAC,IAAI,CAAC,UAAC,UAAU,YAAK,OAAA,MAAA,WAAW,CAAC,WAAW,0CAAE,QAAQ,CAAC,UAAU,CAAC,CAAA,EAAA,CAAC,CAAC;IACzF,CAAC;IACD,aAAa,EAAE,UAAC,OAAO;QACrB,GAAG,CAAC,UAAC,KAAK,IAAK,OAAA,CAAC,EAAE,WAAW,wBAAO,KAAK,CAAC,WAAW,KAAE,OAAO,SAAA,GAAE,EAAE,CAAC,EAApD,CAAoD,CAAC,CAAC;IACvE,CAAC;CACF,CAAC,EA1DsE,CA0DtE,CAAC,CAAC"}
1
+ {"version":3,"file":"currentUser.js","sourceRoot":"","sources":["../../../src/stores/currentUser/currentUser.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,mCAAiC;AACjC,2CAAmF;AAkCtE,QAAA,gBAAgB,GAAG,IAAA,gBAAM,EAAoB,UAAC,GAAG,EAAE,GAAG,IAAK,OAAA,CAAC;IACvE,WAAW,EAAE,SAAS;IACtB,OAAO,EAAE,KAAK;IACd,KAAK,EAAE,SAAS;IAChB,IAAI,EAAE;;;;;oBACJ,GAAG,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;;;;oBAKV,qBAAM,IAAA,aAAK,EAAe,EAAE,GAAG,EAAE,sBAAsB,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAA;;oBAAnF,QAAQ,GAAG,SAAwE,CAAC;;;;oBAEpF;;;;gFAI4D;oBAC5D,IAAI,IAAA,wBAAgB,EAAC,OAAK,CAAC,EAAE,CAAC;wBAC5B,GAAG,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;oBAC1B,CAAC;yBAAM,CAAC;wBACN,GAAG,CAAC;4BACF,OAAO,EAAE,KAAK;4BACd,KAAK,EAAE,OAAc;4BACrB,WAAW,EAAE,SAAS;4BACtB,SAAS,EAAE,SAAS;yBACrB,CAAC,CAAC;oBACL,CAAC;oBAED,sBAAO,OAAO,CAAC,MAAM,CAAC,OAAK,CAAC,EAAC;;oBAG/B,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;wBACjB,GAAG,CAAC;4BACF,OAAO,EAAE,KAAK;4BACd,KAAK,EAAE,QAAQ,CAAC,KAAK;4BACrB,WAAW,EAAE,SAAS;4BACtB,SAAS,EAAE,QAAQ,CAAC,IAAI;yBACzB,CAAC,CAAC;wBAEH,sBAAO,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAC;oBACxC,CAAC;oBAED,GAAG,CAAC,EAAE,WAAW,EAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;oBAE5F,sBAAO,QAAQ,CAAC,IAAI,EAAC;;;SACtB;IACD,gBAAgB,EAAE,UAAC,WAAW;QAC5B,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC;YACvB,OAAO,KAAK,CAAC;QACf,CAAC;QAEO,IAAA,WAAW,GAAK,GAAG,EAAE,YAAV,CAAW;QAE9B,OAAO,WAAW,CAAC,IAAI,CAAC,UAAC,UAAU,YAAK,OAAA,MAAA,WAAW,CAAC,WAAW,0CAAE,QAAQ,CAAC,UAAU,CAAC,CAAA,EAAA,CAAC,CAAC;IACzF,CAAC;IACD,aAAa,EAAE,UAAC,OAAO;QACrB,GAAG,CAAC,UAAC,KAAK,IAAK,OAAA,CAAC,EAAE,WAAW,wBAAO,KAAK,CAAC,WAAW,KAAE,OAAO,SAAA,GAAE,EAAE,CAAC,EAApD,CAAoD,CAAC,CAAC;IACvE,CAAC;CACF,CAAC,EA1DsE,CA0DtE,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qoretechnologies/reqraft",
3
- "version": "0.10.65-pr.148.gf86d88c",
3
+ "version": "0.10.65",
4
4
  "description": "ReQraft is a collection of React components and hooks that are used across Qore Technologies' products made using the ReQore component library from Qore.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -57,12 +57,12 @@
57
57
  "@chromatic-com/storybook": "^5.2.1",
58
58
  "@netsells/storybook-mockdate": "^0.3.3",
59
59
  "@qoretechnologies/qlip": "^0.1.3-beta.20260929120101",
60
- "@qoretechnologies/reqore": "^0.78.10",
61
- "@storybook/addon-docs": "^10.4.6",
62
- "@storybook/addon-links": "^10.4.6",
63
- "@storybook/addon-vitest": "^10.4.6",
64
- "@storybook/react": "^10.4.6",
65
- "@storybook/react-vite": "^10.4.6",
60
+ "@qoretechnologies/reqore": "^0.77.2",
61
+ "@storybook/addon-docs": "^10.6.3",
62
+ "@storybook/addon-links": "^10.6.3",
63
+ "@storybook/addon-vitest": "^10.6.3",
64
+ "@storybook/react": "^10.6.3",
65
+ "@storybook/react-vite": "^10.6.3",
66
66
  "@testing-library/jest-dom": "^5.16.5",
67
67
  "@testing-library/react": "^13.4.0",
68
68
  "@types/js-yaml": "^4.0.9",
@@ -80,7 +80,7 @@
80
80
  "chromatic": "^11.3.0",
81
81
  "eslint": "^8.46.0",
82
82
  "eslint-plugin-react": "^7.33.1",
83
- "eslint-plugin-storybook": "10.4.6",
83
+ "eslint-plugin-storybook": "10.6.3",
84
84
  "jsdom": "^29.1.1",
85
85
  "mock-socket": "^9.3.1",
86
86
  "playwright": "^1.60.0",
@@ -89,7 +89,7 @@
89
89
  "react-dom": "^18.3.1",
90
90
  "react-intersection-observer": "^9.4.2",
91
91
  "react-test-renderer": "^18.2.0",
92
- "storybook": "^10.4.6",
92
+ "storybook": "^10.6.3",
93
93
  "storybook-addon-mock": "^6.0.1",
94
94
  "ts-node": "^9.1.1",
95
95
  "tsc-watch": "^7.2.0",
@@ -7264,11 +7264,9 @@ export const CompactAutoFocusNonFocusableFirstField: Story = {
7264
7264
  },
7265
7265
  { timeout: 10000 }
7266
7266
  );
7267
- // On the control itself, which is not a text box: that is the whole case. Since reqore 0.78 the switch
7268
- // is a native checkbox input.
7267
+ // On the control itself, which is not a text box: that is the whole case.
7269
7268
  const active = document.activeElement as HTMLElement;
7270
- expect(active.tagName).not.toBe('TEXTAREA');
7271
- expect((active as HTMLInputElement).type).toBe('checkbox');
7269
+ expect(['INPUT', 'TEXTAREA']).not.toContain(active.tagName);
7272
7270
  // It did not settle for the focusable text field further down instead.
7273
7271
  expect(document.querySelector('[data-field="name"]')?.contains(active)).toBe(false);
7274
7272
  },
@@ -7332,10 +7330,9 @@ export const CompactAutoFocusPickOneFirstQuestion: Story = {
7332
7330
  { timeout: 10000 }
7333
7331
  );
7334
7332
  const active = document.activeElement as HTMLElement;
7335
- // The control the row actually offers: a choice, not a text box — since reqore 0.78 the first choice,
7336
- // a native checkbox input under the drawn control.
7337
- expect(active.tagName).not.toBe('TEXTAREA');
7338
- expect((active as HTMLInputElement).type).toBe('checkbox');
7333
+ // The control the row actually offers: a choice, not a text box.
7334
+ expect(['INPUT', 'TEXTAREA']).not.toContain(active.tagName);
7335
+ expect(active.getAttribute('tabindex')).toBe('0');
7339
7336
  },
7340
7337
  };
7341
7338
 
@@ -147,15 +147,12 @@ export const CompactEmpty: Story = {
147
147
  const canvas = within(canvasElement);
148
148
 
149
149
  // Should show the input field but no tags
150
+ await expect(canvas.queryByRole('button', { name: /add item/i })).not.toBeInTheDocument();
150
151
  await expect(document.querySelectorAll('.array-auto-compact-tag').length).toBe(0);
151
152
 
152
- // The confirm button is the one way to add an item, and it is disabled while the input is empty.
153
- // reqore names an icon-only button by its tooltip, so it is the only button called "Add item".
154
- const confirmBtn = canvasElement.querySelector<HTMLButtonElement>(
155
- '.array-auto-compact-confirm'
156
- );
153
+ // Confirm button should be disabled when input is empty
154
+ const confirmBtn = document.querySelector('.array-auto-compact-confirm') as HTMLButtonElement;
157
155
  await expect(confirmBtn).toBeInTheDocument();
158
- await expect(canvas.getAllByRole('button', { name: /add item/i })).toEqual([confirmBtn]);
159
156
  await expect(confirmBtn).toBeDisabled();
160
157
  },
161
158
  };
@@ -5,10 +5,6 @@ import { useState } from 'react';
5
5
  import { StoryMeta } from '../../../../types';
6
6
  import { BooleanFormField } from './Boolean';
7
7
 
8
- /** The switch as a user clicks it: since reqore 0.78 it is a native input under its drawn track. */
9
- const switchTrack = (input: HTMLElement): HTMLElement =>
10
- (input.closest('.reqore-checkbox') as HTMLElement | null) ?? input.parentElement!;
11
-
12
8
  const meta = {
13
9
  component: BooleanFormField,
14
10
  title: 'Components/Form/Boolean',
@@ -52,7 +48,7 @@ export const Checked: Story = {
52
48
  await expect(canvas.getByText('Yes')).toBeInTheDocument();
53
49
  await expect(canvas.getByText('No')).toBeInTheDocument();
54
50
 
55
- await userEvent.click(switchTrack(canvas.getByLabelText('Boolean')));
51
+ await userEvent.click(canvas.getByLabelText('Boolean'));
56
52
  await expect(args.onChange).toHaveBeenLastCalledWith(false);
57
53
  },
58
54
  };
@@ -74,7 +70,7 @@ export const Unchecked: Story = {
74
70
 
75
71
  await expect(canvas.getByText('No')).toBeInTheDocument();
76
72
 
77
- await userEvent.click(switchTrack(canvas.getByLabelText('Boolean')));
73
+ await userEvent.click(canvas.getByLabelText('Boolean'));
78
74
  await expect(args.onChange).toHaveBeenLastCalledWith(true);
79
75
  },
80
76
  };
@@ -108,7 +104,7 @@ export const UnsetSelectsYes: Story = {
108
104
  async play({ canvasElement, args }) {
109
105
  const canvas = within(canvasElement);
110
106
 
111
- await userEvent.click(switchTrack(canvas.getByLabelText('Boolean')));
107
+ await userEvent.click(canvas.getByLabelText('Boolean'));
112
108
  await expect(args.onChange).toHaveBeenLastCalledWith(true);
113
109
  },
114
110
  };
@@ -35,13 +35,7 @@ export const Default: Story = {
35
35
  args: {
36
36
  'aria-label': 'MarkdownEditor',
37
37
  },
38
- // A desktop: the preview is drawn beside the editor only above reqore's tablet width (1200px), and the
39
- // story run's default viewport is 1200px wide. Reqore answers media queries in a story run since 0.78.
40
- globals: { viewport: { value: 'desktop1440' } },
41
38
  parameters: {
42
- viewport: {
43
- options: { desktop1440: { name: 'Desktop', styles: { width: '1440px', height: '900px' } } },
44
- },
45
39
  docs: {
46
40
  description: {
47
41
  story:
@@ -53,10 +53,7 @@ export const Default: Story = {
53
53
  async play({ canvasElement, args }) {
54
54
  const canvas = within(canvasElement);
55
55
  const java = canvas.getByLabelText('Java');
56
- // a native radio since reqore 0.78, under the control a user clicks
57
- await userEvent.click(
58
- (java.closest('.reqore-checkbox') as HTMLElement | null) ?? java.parentElement!
59
- );
56
+ await userEvent.click(java);
60
57
  await expect(args.onChange).toHaveBeenLastCalledWith('Java');
61
58
  },
62
59
  };
@@ -903,10 +903,6 @@ const longExampleTemplates = {
903
903
  };
904
904
 
905
905
  export const LongExampleValueTruncatedWithModal: StoryObj<typeof meta> = {
906
- /* A field in a narrow column, as a form's field is: the picker is as wide as the field (since reqore 0.78 it
907
- follows the field's width as it is laid out), and the preview is cut at that width. Across a whole
908
- desktop page the field is wider than the preview itself, and nothing has to be cut. */
909
- decorators: [(Story) => <div style={{ width: 480 }}>{Story()}</div>],
910
906
  args: {
911
907
  component: LongStringField,
912
908
  value: 'Some string',
@@ -255,59 +255,3 @@ export const KindImageFailsToLoad: Story = {
255
255
  await expect(canvasElement.querySelector('.reqore-tag .reqore-icon')).toBeTruthy();
256
256
  },
257
257
  };
258
-
259
- /**
260
- * A viewer that can open SOME references: the IDE under a support grant, or any viewer
261
- * after an interface moved group or was deleted since it was cited. `isInterfaceLinkable`
262
- * keeps the refused chips in place — they are still what was cited — but without the
263
- * click, with an unlink glyph, and with `unlinkableReason` in the tooltip.
264
- */
265
- export const MixedLinkability: Story = {
266
- parameters: {
267
- docs: {
268
- description: {
269
- story:
270
- 'Renders four chips of which two can be opened: the refused ones keep their place and look but carry an unlink glyph and no click, with the reason in their tooltip (qorus#693).',
271
- },
272
- },
273
- },
274
- args: {
275
- onInterfaceClick: fn(),
276
- isInterfaceLinkable: (reference: IInterfaceReference) => reference.interface_kind !== 'workflow',
277
- unlinkableReason: (reference: IInterfaceReference) =>
278
- reference.interface_kind === 'workflow' ? 'not covered by the support grant' : undefined,
279
- },
280
- async play({ canvasElement, args }) {
281
- const canvas = within(canvasElement);
282
- await userEvent.click(canvas.getByText('order-sync:1.2'));
283
- await expect(args.onInterfaceClick).not.toHaveBeenCalled();
284
- await userEvent.click(canvas.getByText('notification-svc'));
285
- await waitFor(() =>
286
- expect(args.onInterfaceClick).toHaveBeenCalledWith(
287
- expect.objectContaining({ interface_kind: 'service', interface_name: 'notification-svc' })
288
- )
289
- );
290
- await expect(args.onInterfaceClick).toHaveBeenCalledTimes(1);
291
- },
292
- };
293
-
294
- /** The same mixed chips at phone width: the glyph is what tells the two apart on a
295
- * screen with no hover, so it has to survive the wrap. */
296
- export const MixedLinkabilityMobile: Story = {
297
- parameters: {
298
- qlip: { viewport: { width: 390, height: 844 } },
299
- docs: {
300
- description: {
301
- story:
302
- 'Renders the mixed linkable and unlinkable chips at 390px: they wrap, and the refused ones still carry the unlink glyph, which is the only cue on a screen without hover.',
303
- },
304
- },
305
- },
306
- args: MixedLinkability.args,
307
- async play({ canvasElement }) {
308
- const canvas = within(canvasElement);
309
- await expect(canvas.getByText('order-sync:1.2')).toBeInTheDocument();
310
- await expect(canvas.getByText('nightly-cleanup')).toBeInTheDocument();
311
- },
312
- };
313
-
@@ -4,7 +4,6 @@ import { ComponentProps } from 'react';
4
4
  import {
5
5
  defaultInterfaceIcon,
6
6
  IInterfaceReference,
7
- interfaceReferenceKey,
8
7
  toInterfaceKindMark,
9
8
  TResolveInterfaceIcon,
10
9
  } from './meta';
@@ -23,18 +22,6 @@ export interface IInterfaceReferenceTagsProps {
23
22
  /** Open a referenced interface; chips are static (informational) when omitted —
24
23
  * e.g. the staff view, which can't reach the customer's instance. */
25
24
  onInterfaceClick?: (reference: IInterfaceReference) => void;
26
- /**
27
- * Whether a reference can be opened right now; consulted only when `onInterfaceClick`
28
- * is given, and every reference is linkable when it is omitted. A chip it refuses
29
- * renders without the click and with an unlink glyph, and its tooltip carries
30
- * `unlinkableReason` when there is one. A support reader can open only what the
31
- * customer's grant covers, and an interface that moved group or was deleted since it
32
- * was cited is a reference with nowhere to go — the chip still shows what was cited.
33
- */
34
- isInterfaceLinkable?: (reference: IInterfaceReference) => boolean;
35
- /** Why a reference is not linkable, for the chip's tooltip ("not covered by the
36
- * grant", "no longer on the instance"). Consulted only for refused references. */
37
- unlinkableReason?: (reference: IInterfaceReference) => string | undefined;
38
25
  /**
39
26
  * Detach a reference. Each chip grows an "×" when given — for the composer,
40
27
  * where the chips are the references you're about to send and so are still
@@ -81,8 +68,6 @@ export const InterfaceReferenceTags = ({
81
68
  label,
82
69
  resolveInterfaceIcon,
83
70
  onInterfaceClick,
84
- isInterfaceLinkable,
85
- unlinkableReason,
86
71
  onRemove,
87
72
  size = 'small',
88
73
  intent,
@@ -115,30 +100,25 @@ export const InterfaceReferenceTags = ({
115
100
  // The chosen image (see `preferKindImage`) once it has loaded; the kind's
116
101
  // font icon until then, and if it fails.
117
102
  const loaded = isLoaded(image);
118
- // Linkable: a click handler is wired AND the consumer does not refuse this one.
119
- // A refused chip keeps its look and says why, instead of opening nothing.
120
- const linkable = !!onInterfaceClick && (isInterfaceLinkable?.(reference) ?? true);
121
- const reason = onInterfaceClick && !linkable ? unlinkableReason?.(reference) : undefined;
122
- const described = `${reference.interface_kind}: ${reference.interface_name}`;
123
103
  return (
124
104
  <ReqoreTag
125
- key={reference.reference_id ?? interfaceReferenceKey(reference)}
105
+ key={
106
+ reference.reference_id ??
107
+ `${reference.interface_kind}:${reference.interface_name}`
108
+ }
126
109
  icon={icon}
127
110
  leftIconProps={loaded ? { image } : undefined}
128
- rightIcon={onInterfaceClick && !linkable ? 'LinkUnlinkM' : undefined}
129
111
  labelKey={reference.interface_kind}
130
112
  label={reference.interface_name}
131
113
  size={size}
132
114
  intent={intent}
133
115
  customTheme={customTheme}
134
116
  tooltip={
135
- linkable
117
+ onInterfaceClick
136
118
  ? `Open ${reference.interface_kind} ${reference.interface_name}`
137
- : reason
138
- ? `${described} — ${reason}`
139
- : described
119
+ : `${reference.interface_kind}: ${reference.interface_name}`
140
120
  }
141
- onClick={linkable ? () => onInterfaceClick(reference) : undefined}
121
+ onClick={onInterfaceClick ? () => onInterfaceClick(reference) : undefined}
142
122
  onRemoveClick={onRemove ? () => onRemove(reference) : undefined}
143
123
  removeTooltip={`Remove ${reference.interface_kind} ${reference.interface_name}`}
144
124
  />
@@ -16,7 +16,6 @@ import {
16
16
  IInterfaceReference,
17
17
  toInterfaceKindMark,
18
18
  TResolveInterfaceIcon,
19
- normalizeInterfaceKind,
20
19
  } from './meta';
21
20
  import { useLoadedImages } from './useLoadedImages';
22
21
 
@@ -343,9 +342,7 @@ export const ReferencePicker = ({
343
342
  () =>
344
343
  new Set(
345
344
  (picked ?? [])
346
- .filter(
347
- (reference) => normalizeInterfaceKind(reference.interface_kind) === normalizeInterfaceKind(kind)
348
- )
345
+ .filter((reference) => reference.interface_kind === kind)
349
346
  .map((reference) => reference.interface_name)
350
347
  ),
351
348
  [picked, kind]
@@ -1,5 +1,4 @@
1
1
  export * from './meta';
2
- export * from './accessMeta';
3
2
  export * from './ticketModel';
4
3
  export * from './attachmentAccess';
5
4
  export * from './AttachmentChips';
@@ -9,4 +8,3 @@ export * from './InterfaceReferenceTags';
9
8
  export * from './ReferencePicker';
10
9
  export * from './fileToAttachment';
11
10
  export * from './TicketReplyBox';
12
- export * from './WorkspaceAccessStatus';
@@ -13,39 +13,7 @@ import { IReqoreIconName } from '@qoretechnologies/reqore/dist/types/icons';
13
13
  export type TTicketStatus = 'new' | 'open' | 'awaiting_customer' | 'resolved' | 'closed';
14
14
  export type TTicketPriority = 'low' | 'normal' | 'high' | 'urgent';
15
15
  export type TTicketCategory = 'bug' | 'question' | 'billing' | 'feature' | 'other';
16
- export type TTicketAuditAction =
17
- | 'replied'
18
- | 'noted'
19
- | 'status_changed'
20
- | 'assigned'
21
- | 'updated'
22
- // staff reads (qorus#693 Layer 0): a ticket, its thread or its attachment list was opened,
23
- // or a file was downloaded — coalesced server-side per staff member and window
24
- | 'viewed'
25
- | 'attachment_downloaded'
26
- // delegated workspace access (qorus#693 Layers 1–3): the customer's grant lifecycle, a
27
- // staff read of the workspace under it, and a read-only IDE session launched from it
28
- | 'workspace_viewed'
29
- | 'access_requested'
30
- | 'access_granted'
31
- | 'access_extended'
32
- | 'access_revoked'
33
- | 'access_expired'
34
- | 'session_launched';
35
-
36
- /**
37
- * The `system_event` a system message in a ticket thread may carry (qorus#693): the
38
- * delegated-access lifecycle, written by the control plane as a thread message so the
39
- * customer and the staff member see the same record in the conversation. A thread
40
- * renders a known event with its own mark; an unknown one falls back to a plain line.
41
- */
42
- export type TTicketSystemEvent =
43
- | 'support_access.requested'
44
- | 'support_access.granted'
45
- | 'support_access.extended'
46
- | 'support_access.first_used'
47
- | 'support_access.revoked'
48
- | 'support_access.expired';
16
+ export type TTicketAuditAction = 'replied' | 'noted' | 'status_changed' | 'assigned' | 'updated';
49
17
 
50
18
  /** A message author. Staff identities are masked from the customer by the backend. */
51
19
  export type TTicketMessageAuthor = 'customer' | 'staff' | 'system';
@@ -100,72 +68,8 @@ export const TICKET_AUDIT_ACTION_META: Record<TTicketAuditAction, ITicketEnumMet
100
68
  status_changed: { label: 'Status changed', intent: 'warning', icon: 'ExchangeLine' },
101
69
  assigned: { label: 'Assigned', intent: 'pending', icon: 'UserFollowLine' },
102
70
  updated: { label: 'Updated', intent: 'muted', icon: 'Edit2Line' },
103
- viewed: { label: 'Viewed', intent: 'muted', icon: 'EyeLine' },
104
- attachment_downloaded: { label: 'Attachment downloaded', intent: 'muted', icon: 'Download2Line' },
105
- workspace_viewed: { label: 'Workspace viewed', intent: 'info', icon: 'Search2Line' },
106
- access_requested: { label: 'Access requested', intent: 'pending', icon: 'ShieldUserLine' },
107
- access_granted: { label: 'Access granted', intent: 'success', icon: 'ShieldCheckLine' },
108
- access_extended: { label: 'Access extended', intent: 'info', icon: 'TimerLine' },
109
- access_revoked: { label: 'Access revoked', intent: 'danger', icon: 'ShieldCrossLine' },
110
- access_expired: { label: 'Access expired', intent: 'muted', icon: 'HourglassLine' },
111
- session_launched: { label: 'IDE session launched', intent: 'info', icon: 'ExternalLinkLine' },
112
- };
113
-
114
- /** The mark for an audit action the server writes but this vocabulary has not caught up
115
- * with: a muted, generic row that still names the action. It exists because the staff
116
- * audit tab used to index `TICKET_AUDIT_ACTION_META` directly, and one unknown action
117
- * took the whole tab down (qorus#693). */
118
- export const UNKNOWN_TICKET_AUDIT_ACTION_META: ITicketEnumMeta = {
119
- label: 'Activity',
120
- intent: 'muted',
121
- icon: 'HistoryLine',
122
- };
123
-
124
- /** A wire value humanised for reading: `attachment_downloaded` → "Attachment downloaded". */
125
- export const humaniseWireValue = (value: string): string => {
126
- const words = value.replace(/[._-]+/g, ' ').trim();
127
- return words ? words.charAt(0).toUpperCase() + words.slice(1) : value;
128
71
  };
129
72
 
130
- /**
131
- * The mark for an audit action, whatever the server sent. A known action gets its
132
- * entry; an unknown one gets the muted generic entry with the action's own wire value
133
- * humanised as the label, so a new server action renders as a readable row instead
134
- * of failing the surface that lists it.
135
- */
136
- export const ticketAuditActionMeta = (action: string): ITicketEnumMeta =>
137
- (TICKET_AUDIT_ACTION_META as Record<string, ITicketEnumMeta>)[action] ?? {
138
- ...UNKNOWN_TICKET_AUDIT_ACTION_META,
139
- label: humaniseWireValue(action),
140
- };
141
-
142
- /** How each delegated-access thread event renders: the mark on its system line or card. */
143
- export const TICKET_SYSTEM_EVENT_META: Record<TTicketSystemEvent, ITicketEnumMeta> = {
144
- 'support_access.requested': {
145
- label: 'Workspace access requested',
146
- intent: 'info',
147
- icon: 'ShieldUserLine',
148
- },
149
- 'support_access.granted': { label: 'Workspace access granted', intent: 'success', icon: 'ShieldCheckLine' },
150
- 'support_access.extended': { label: 'Workspace access extended', intent: 'info', icon: 'TimerLine' },
151
- 'support_access.first_used': { label: 'Workspace opened by support', intent: 'info', icon: 'EyeLine' },
152
- 'support_access.revoked': { label: 'Workspace access revoked', intent: 'danger', icon: 'ShieldCrossLine' },
153
- 'support_access.expired': { label: 'Workspace access expired', intent: 'muted', icon: 'HourglassLine' },
154
- };
155
-
156
- /** The generic mark for a system message with no event, or an event this vocabulary
157
- * does not know: the plain informational line every system message used to be. */
158
- export const DEFAULT_TICKET_SYSTEM_EVENT_META: ITicketEnumMeta = {
159
- label: 'System',
160
- intent: 'muted',
161
- icon: 'InformationLine',
162
- };
163
-
164
- /** The mark for a system message's `system_event`, with the generic fallback. */
165
- export const ticketSystemEventMeta = (event?: string): ITicketEnumMeta =>
166
- (event && (TICKET_SYSTEM_EVENT_META as Record<string, ITicketEnumMeta>)[event]) ||
167
- DEFAULT_TICKET_SYSTEM_EVENT_META;
168
-
169
73
  /** The status label for a given viewer — the customer sees "Awaiting your reply"
170
74
  * where staff see "Awaiting customer"; all other values are audience-neutral. */
171
75
  export const ticketStatusLabel = (
@@ -200,28 +104,12 @@ export interface IAttachmentUpload {
200
104
  * `{kind, name}` snapshot (the interface itself lives on the instance, not the
201
105
  * SaaS plane). Attaches to a ticket (at creation) or a message (in a reply). */
202
106
  export interface IInterfaceReference {
203
- /**
204
- * The interface's kind. On READ this is the normalized Qorus `TypeMap` key the server
205
- * stores (`fsm`, never `qog`; `step`, never `workflow-step`), so two surfaces compare
206
- * equal; a writer may still send the spelling it has, and the server normalizes it.
207
- * Compare kinds through `normalizeInterfaceKind()` rather than by string.
208
- */
107
+ /** interface type: workflow / service / job / fsm / qog / connection / ... */
209
108
  interface_kind: string;
210
109
  /** interface name (may include a version) */
211
110
  interface_name: string;
212
111
  /** server-assigned reference UUID (present on read, absent when submitting) */
213
112
  reference_id?: string;
214
- /**
215
- * The interface's id on the subscriber's instance at the time it was referenced, when
216
- * the writer knew it (the IDE's picker does). A viewer that can reach the instance
217
- * prefers it over the name, which may have been renamed or versioned since.
218
- */
219
- interface_id?: number;
220
- /** The group the interface lived in when referenced — set by the server on read. */
221
- groupid?: number;
222
- /** That group's portable namespace — set by the server on read; absent for the host's
223
- * DEFAULT group. What a support reader needs to find the interface after a move. */
224
- group_namespace?: number;
225
113
  /** For an app-triggered interface (a qog): the triggering app's name. A viewer
226
114
  * with the app catalogue (the customer's IDE) resolves it to the app's logo the
227
115
  * same way the qogs list does — see `resolveInterfaceImage` on the tags. */
@@ -232,47 +120,6 @@ export interface IInterfaceReference {
232
120
  logo?: string;
233
121
  }
234
122
 
235
- // Kind spellings a writer may still send, and the normalized `TypeMap` key the server
236
- // stores for each. The IDE's menus and older references say `qog`; the engine's type
237
- // is `fsm`. A `workflow-step` is a `step`.
238
- const INTERFACE_KIND_ALIASES: Record<string, string> = {
239
- qog: 'fsm',
240
- 'workflow-step': 'step',
241
- };
242
-
243
- /**
244
- * The normalized `TypeMap` key for a kind, however a writer spelled it: `qog` → `fsm`,
245
- * `workflow-step` → `step`; anything else is returned trimmed and lower-cased. Every
246
- * comparison of two references' kinds goes through this, so a reference written as a
247
- * `qog` and one read back as an `fsm` are the same interface.
248
- */
249
- export const normalizeInterfaceKind = (kind: string): string => {
250
- const key = kind.trim().toLowerCase();
251
- return INTERFACE_KIND_ALIASES[key] ?? key;
252
- };
253
-
254
- /**
255
- * A reference's identity for keys and dedupe: its normalized kind and its name. Not the
256
- * `reference_id` (absent when submitting) and not the `interface_id` (absent on older
257
- * references), so the same interface cited twice is one key whatever each copy carries.
258
- */
259
- export const interfaceReferenceKey = (reference: IInterfaceReference): string =>
260
- `${normalizeInterfaceKind(reference.interface_kind)}:${reference.interface_name}`;
261
-
262
- /** The references with duplicates dropped — first occurrence wins, order kept —
263
- * where two references are the same interface by `interfaceReferenceKey()`. */
264
- export const dedupeInterfaceReferences = <T extends IInterfaceReference>(references: T[]): T[] => {
265
- const seen = new Set<string>();
266
- return references.filter((reference) => {
267
- const key = interfaceReferenceKey(reference);
268
- if (seen.has(key)) {
269
- return false;
270
- }
271
- seen.add(key);
272
- return true;
273
- });
274
- };
275
-
276
123
  // Built-in per-kind icons for referenced interfaces, kept in step with the
277
124
  // qorus-ide interface vocabulary. Used when a consumer doesn't pass its own
278
125
  // `resolveInterfaceIcon`, so the staff view and the Qonsole renderer show the
@@ -352,7 +199,8 @@ export const defaultInterfaceKindLabel = (kind: string): string => {
352
199
  return known;
353
200
  }
354
201
 
355
- const sentenceCase = humaniseWireValue(kind);
202
+ const words = kind.replace(/[-_]+/g, ' ').trim();
203
+ const sentenceCase = words.charAt(0).toUpperCase() + words.slice(1);
356
204
 
357
205
  return sentenceCase.endsWith('s') ? sentenceCase : `${sentenceCase}s`;
358
206
  };
@@ -61,16 +61,6 @@ export interface ITicketMessage {
61
61
  attachments?: ITicketAttachment[];
62
62
  /** interfaces referenced in this message, as `{kind, name}` snapshots */
63
63
  referenced_interfaces?: IInterfaceReference[];
64
- /**
65
- * For a `system` message: the event it records (qorus#693), e.g.
66
- * `support_access.requested`. A thread renders a known event with its own mark, and the
67
- * `support_access.requested` event as a card that can carry the customer's Grant action;
68
- * absent on the plain system lines (status changes, assignments).
69
- */
70
- system_event?: string;
71
- /** For a `system` message: the event's structured payload (a grant id, an expiry, the
72
- * requesting staff member's reason), as the server wrote it. */
73
- system_detail?: Record<string, unknown>;
74
64
  }
75
65
 
76
66
  /**
@@ -313,43 +313,3 @@ export const ShowInChat: Story = {
313
313
  await expect(args.onShowInChat).toHaveBeenCalledTimes(1);
314
314
  },
315
315
  };
316
-
317
- /**
318
- * A viewer that can open some references but not others: a refused row offers no Open
319
- * action and says why in its metadata line, next to the kind — in the row, so it reads on
320
- * a touch screen, where a tooltip never shows.
321
- */
322
- export const MixedLinkability: Story = {
323
- parameters: {
324
- docs: {
325
- description: {
326
- story:
327
- 'Renders the linked-interface rows with two refusals: those rows have no Open action and carry the reason in their metadata line after the kind, visible without hover (qorus#693).',
328
- },
329
- },
330
- },
331
- args: {
332
- attachments: [],
333
- onInterfaceClick: fn(),
334
- isInterfaceLinkable: (reference: IInterfaceReference) => reference.interface_kind !== 'workflow',
335
- unlinkableReason: (reference: IInterfaceReference) =>
336
- reference.interface_kind === 'workflow' ? 'moved to another group' : undefined,
337
- },
338
- play: async ({ canvasElement, args }) => {
339
- const canvas = within(canvasElement);
340
- await expect(canvas.getByText('Linked interfaces')).toBeInTheDocument();
341
- // the reason is in the row's text, not only a tooltip
342
- await expect(canvas.getAllByText('workflow · moved to another group')).toHaveLength(2);
343
- // the refused rows have no Open action; the three others do
344
- await waitFor(() =>
345
- expect(canvasElement.querySelectorAll('.reqore-entity-row-actions button')).toHaveLength(3)
346
- );
347
- await userEvent.click(canvasElement.querySelectorAll('.reqore-entity-row-actions button')[0]);
348
- await waitFor(() =>
349
- expect(args.onInterfaceClick).toHaveBeenCalledWith(
350
- expect.objectContaining({ interface_kind: 'connection' })
351
- )
352
- );
353
- },
354
- };
355
-