@qoretechnologies/reqraft 0.10.25 → 0.10.26
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/.claude/CLAUDE.md +52 -23
- package/design/COMPACT_ENGINE_REDESIGN.md +156 -0
- package/design/FORM_ENGINE_COMPACT_UX_PLAN.md +353 -0
- package/dist/components/FocusedEditing/index.d.ts +9 -1
- package/dist/components/FocusedEditing/index.d.ts.map +1 -1
- package/dist/components/FocusedEditing/index.js +2 -2
- package/dist/components/FocusedEditing/index.js.map +1 -1
- package/dist/components/composer/Composer.d.ts +108 -0
- package/dist/components/composer/Composer.d.ts.map +1 -0
- package/dist/components/composer/Composer.js +238 -0
- package/dist/components/composer/Composer.js.map +1 -0
- package/dist/components/composer/helpers.d.ts +21 -0
- package/dist/components/composer/helpers.d.ts.map +1 -0
- package/dist/components/composer/helpers.js +75 -0
- package/dist/components/composer/helpers.js.map +1 -0
- package/dist/components/composer/index.d.ts +3 -0
- package/dist/components/composer/index.d.ts.map +1 -0
- package/dist/components/composer/index.js +19 -0
- package/dist/components/composer/index.js.map +1 -0
- package/dist/components/form/engine/CompactRow.d.ts.map +1 -1
- package/dist/components/form/engine/CompactRow.js +307 -110
- package/dist/components/form/engine/CompactRow.js.map +1 -1
- package/dist/components/form/engine/CompactToolbar.d.ts.map +1 -1
- package/dist/components/form/engine/CompactToolbar.js +123 -106
- package/dist/components/form/engine/CompactToolbar.js.map +1 -1
- package/dist/components/form/engine/FormEngine.d.ts +107 -11
- package/dist/components/form/engine/FormEngine.d.ts.map +1 -1
- package/dist/components/form/engine/FormEngine.js +618 -179
- package/dist/components/form/engine/FormEngine.js.map +1 -1
- package/dist/components/form/engine/compactRowContext.d.ts +9 -0
- package/dist/components/form/engine/compactRowContext.d.ts.map +1 -1
- package/dist/components/form/engine/compactRowContext.js.map +1 -1
- package/dist/components/form/engine/compactRowStyles.d.ts +7 -3
- package/dist/components/form/engine/compactRowStyles.d.ts.map +1 -1
- package/dist/components/form/engine/compactRowStyles.js +88 -51
- package/dist/components/form/engine/compactRowStyles.js.map +1 -1
- package/dist/components/form/engine/compactToolbarContext.d.ts +1 -0
- package/dist/components/form/engine/compactToolbarContext.d.ts.map +1 -1
- package/dist/components/form/engine/compactToolbarContext.js.map +1 -1
- package/dist/components/form/engine/optionActions.d.ts +28 -0
- package/dist/components/form/engine/optionActions.d.ts.map +1 -0
- package/dist/components/form/engine/optionActions.js +18 -0
- package/dist/components/form/engine/optionActions.js.map +1 -0
- package/dist/components/form/engine/readFirst.d.ts +63 -2
- package/dist/components/form/engine/readFirst.d.ts.map +1 -1
- package/dist/components/form/engine/readFirst.js +121 -6
- package/dist/components/form/engine/readFirst.js.map +1 -1
- package/dist/components/form/engine/rendererTypes.d.ts +35 -0
- package/dist/components/form/engine/rendererTypes.d.ts.map +1 -0
- package/dist/components/form/engine/rendererTypes.js +63 -0
- package/dist/components/form/engine/rendererTypes.js.map +1 -0
- package/dist/components/form/engine/variants/VariantCalmTable.d.ts +6 -0
- package/dist/components/form/engine/variants/VariantCalmTable.d.ts.map +1 -0
- package/dist/components/form/engine/variants/VariantCalmTable.js +94 -0
- package/dist/components/form/engine/variants/VariantCalmTable.js.map +1 -0
- package/dist/components/form/engine/variants/VariantCards.d.ts +6 -0
- package/dist/components/form/engine/variants/VariantCards.d.ts.map +1 -0
- package/dist/components/form/engine/variants/VariantCards.js +80 -0
- package/dist/components/form/engine/variants/VariantCards.js.map +1 -0
- package/dist/components/form/engine/variants/VariantFocus.d.ts +7 -0
- package/dist/components/form/engine/variants/VariantFocus.d.ts.map +1 -0
- package/dist/components/form/engine/variants/VariantFocus.js +138 -0
- package/dist/components/form/engine/variants/VariantFocus.js.map +1 -0
- package/dist/components/form/engine/variants/VariantMinimal.d.ts +6 -0
- package/dist/components/form/engine/variants/VariantMinimal.d.ts.map +1 -0
- package/dist/components/form/engine/variants/VariantMinimal.js +73 -0
- package/dist/components/form/engine/variants/VariantMinimal.js.map +1 -0
- package/dist/components/form/engine/variants/focusDemo.d.ts +13 -0
- package/dist/components/form/engine/variants/focusDemo.d.ts.map +1 -0
- package/dist/components/form/engine/variants/focusDemo.js +139 -0
- package/dist/components/form/engine/variants/focusDemo.js.map +1 -0
- package/dist/components/form/engine/variants/variantModel.d.ts +70 -0
- package/dist/components/form/engine/variants/variantModel.d.ts.map +1 -0
- package/dist/components/form/engine/variants/variantModel.js +133 -0
- package/dist/components/form/engine/variants/variantModel.js.map +1 -0
- package/dist/components/form/engine/variants/variantParts.d.ts +79 -0
- package/dist/components/form/engine/variants/variantParts.d.ts.map +1 -0
- package/dist/components/form/engine/variants/variantParts.js +191 -0
- package/dist/components/form/engine/variants/variantParts.js.map +1 -0
- package/dist/components/form/expressions/builder/index.d.ts.map +1 -1
- package/dist/components/form/expressions/builder/index.js +13 -2
- package/dist/components/form/expressions/builder/index.js.map +1 -1
- package/dist/components/form/expressions/useExpressions.d.ts.map +1 -1
- package/dist/components/form/expressions/useExpressions.js +4 -1
- package/dist/components/form/expressions/useExpressions.js.map +1 -1
- package/dist/components/form/fields/Field.d.ts.map +1 -1
- package/dist/components/form/fields/Field.js +5 -3
- package/dist/components/form/fields/Field.js.map +1 -1
- package/dist/components/form/fields/allowed-values/AllowedValues.d.ts +2 -1
- package/dist/components/form/fields/allowed-values/AllowedValues.d.ts.map +1 -1
- package/dist/components/form/fields/allowed-values/AllowedValues.js +8 -26
- package/dist/components/form/fields/allowed-values/AllowedValues.js.map +1 -1
- package/dist/components/form/fields/auto/AutoFormField.d.ts +3 -0
- package/dist/components/form/fields/auto/AutoFormField.d.ts.map +1 -1
- package/dist/components/form/fields/auto/AutoFormField.js +42 -8
- package/dist/components/form/fields/auto/AutoFormField.js.map +1 -1
- package/dist/components/form/fields/binary/Binary.d.ts +15 -0
- package/dist/components/form/fields/binary/Binary.d.ts.map +1 -0
- package/dist/components/form/fields/binary/Binary.js +74 -0
- package/dist/components/form/fields/binary/Binary.js.map +1 -0
- package/dist/components/form/fields/boolean/Boolean.js +1 -1
- package/dist/components/form/fields/boolean/Boolean.js.map +1 -1
- package/dist/components/form/fields/multi-select/MultiSelectFormField.d.ts.map +1 -1
- package/dist/components/form/fields/multi-select/MultiSelectFormField.js +5 -4
- package/dist/components/form/fields/multi-select/MultiSelectFormField.js.map +1 -1
- package/dist/components/form/fields/select/Select.d.ts.map +1 -1
- package/dist/components/form/fields/select/Select.js +29 -12
- package/dist/components/form/fields/select/Select.js.map +1 -1
- package/dist/components/form/fields/select/SelectCollection.d.ts +8 -2
- package/dist/components/form/fields/select/SelectCollection.d.ts.map +1 -1
- package/dist/components/form/fields/select/SelectCollection.js +52 -16
- package/dist/components/form/fields/select/SelectCollection.js.map +1 -1
- package/dist/components/form/index.d.ts +2 -0
- package/dist/components/form/index.d.ts.map +1 -1
- package/dist/components/form/index.js +2 -0
- package/dist/components/form/index.js.map +1 -1
- package/dist/components/imageLightbox/ImageLightbox.d.ts +21 -0
- package/dist/components/imageLightbox/ImageLightbox.d.ts.map +1 -0
- package/dist/components/imageLightbox/ImageLightbox.js +169 -0
- package/dist/components/imageLightbox/ImageLightbox.js.map +1 -0
- package/dist/components/imageLightbox/index.d.ts +2 -0
- package/dist/components/imageLightbox/index.d.ts.map +1 -0
- package/dist/components/imageLightbox/index.js +18 -0
- package/dist/components/imageLightbox/index.js.map +1 -0
- package/dist/components/searchFilterBar/SearchFilterBar.d.ts +33 -0
- package/dist/components/searchFilterBar/SearchFilterBar.d.ts.map +1 -0
- package/dist/components/searchFilterBar/SearchFilterBar.js +76 -0
- package/dist/components/searchFilterBar/SearchFilterBar.js.map +1 -0
- package/dist/components/searchFilterBar/index.d.ts +2 -0
- package/dist/components/searchFilterBar/index.d.ts.map +1 -0
- package/dist/components/searchFilterBar/index.js +18 -0
- package/dist/components/searchFilterBar/index.js.map +1 -0
- package/dist/components/supportTicket/AttachmentChips.d.ts +10 -0
- package/dist/components/supportTicket/AttachmentChips.d.ts.map +1 -0
- package/dist/components/supportTicket/AttachmentChips.js +122 -0
- package/dist/components/supportTicket/AttachmentChips.js.map +1 -0
- package/dist/components/supportTicket/InterfaceReferenceTags.d.ts +43 -0
- package/dist/components/supportTicket/InterfaceReferenceTags.d.ts.map +1 -0
- package/dist/components/supportTicket/InterfaceReferenceTags.js +31 -0
- package/dist/components/supportTicket/InterfaceReferenceTags.js.map +1 -0
- package/dist/components/supportTicket/ReferencePicker.d.ts +87 -0
- package/dist/components/supportTicket/ReferencePicker.d.ts.map +1 -0
- package/dist/components/supportTicket/ReferencePicker.js +295 -0
- package/dist/components/supportTicket/ReferencePicker.js.map +1 -0
- package/dist/components/supportTicket/TicketHeader.d.ts +86 -0
- package/dist/components/supportTicket/TicketHeader.d.ts.map +1 -0
- package/dist/components/supportTicket/TicketHeader.js +149 -0
- package/dist/components/supportTicket/TicketHeader.js.map +1 -0
- package/dist/components/supportTicket/TicketMetaTags.d.ts +32 -0
- package/dist/components/supportTicket/TicketMetaTags.d.ts.map +1 -0
- package/dist/components/supportTicket/TicketMetaTags.js +21 -0
- package/dist/components/supportTicket/TicketMetaTags.js.map +1 -0
- package/dist/components/supportTicket/TicketReplyBox.d.ts +63 -0
- package/dist/components/supportTicket/TicketReplyBox.d.ts.map +1 -0
- package/dist/components/supportTicket/TicketReplyBox.js +115 -0
- package/dist/components/supportTicket/TicketReplyBox.js.map +1 -0
- package/dist/components/supportTicket/attachmentAccess.d.ts +37 -0
- package/dist/components/supportTicket/attachmentAccess.d.ts.map +1 -0
- package/dist/components/supportTicket/attachmentAccess.js +132 -0
- package/dist/components/supportTicket/attachmentAccess.js.map +1 -0
- package/dist/components/supportTicket/fileToAttachment.d.ts +9 -0
- package/dist/components/supportTicket/fileToAttachment.d.ts.map +1 -0
- package/dist/components/supportTicket/fileToAttachment.js +28 -0
- package/dist/components/supportTicket/fileToAttachment.js.map +1 -0
- package/dist/components/supportTicket/index.d.ts +11 -0
- package/dist/components/supportTicket/index.d.ts.map +1 -0
- package/dist/components/supportTicket/index.js +27 -0
- package/dist/components/supportTicket/index.js.map +1 -0
- package/dist/components/supportTicket/meta.d.ts +71 -0
- package/dist/components/supportTicket/meta.d.ts.map +1 -0
- package/dist/components/supportTicket/meta.js +115 -0
- package/dist/components/supportTicket/meta.js.map +1 -0
- package/dist/components/supportTicket/ticketModel.d.ts +102 -0
- package/dist/components/supportTicket/ticketModel.d.ts.map +1 -0
- package/dist/components/supportTicket/ticketModel.js +3 -0
- package/dist/components/supportTicket/ticketModel.js.map +1 -0
- package/dist/components/ticketReferences/TicketReferences.d.ts +52 -0
- package/dist/components/ticketReferences/TicketReferences.d.ts.map +1 -0
- package/dist/components/ticketReferences/TicketReferences.js +492 -0
- package/dist/components/ticketReferences/TicketReferences.js.map +1 -0
- package/dist/components/ticketReferences/index.d.ts +3 -0
- package/dist/components/ticketReferences/index.d.ts.map +1 -0
- package/dist/components/ticketReferences/index.js +6 -0
- package/dist/components/ticketReferences/index.js.map +1 -0
- package/dist/components/ticketThread/TicketThread.d.ts +57 -0
- package/dist/components/ticketThread/TicketThread.d.ts.map +1 -0
- package/dist/components/ticketThread/TicketThread.js +299 -0
- package/dist/components/ticketThread/TicketThread.js.map +1 -0
- package/dist/components/ticketThread/index.d.ts +3 -0
- package/dist/components/ticketThread/index.d.ts.map +1 -0
- package/dist/components/ticketThread/index.js +7 -0
- package/dist/components/ticketThread/index.js.map +1 -0
- package/dist/helpers/common.d.ts +5 -0
- package/dist/helpers/common.d.ts.map +1 -1
- package/dist/helpers/common.js +20 -1
- package/dist/helpers/common.js.map +1 -1
- package/dist/helpers/scrollbar.d.ts +2 -0
- package/dist/helpers/scrollbar.d.ts.map +1 -0
- package/dist/helpers/scrollbar.js +25 -0
- package/dist/helpers/scrollbar.js.map +1 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/providers/StorageProvider.d.ts +13 -0
- package/dist/providers/StorageProvider.d.ts.map +1 -1
- package/dist/providers/StorageProvider.js +29 -5
- package/dist/providers/StorageProvider.js.map +1 -1
- package/package.json +6 -5
- package/src/components/FocusedEditing/index.tsx +17 -2
- package/src/components/composer/Composer.stories.tsx +238 -0
- package/src/components/composer/Composer.tsx +545 -0
- package/src/components/composer/helpers.ts +74 -0
- package/src/components/composer/index.ts +2 -0
- package/src/components/dpqlEditor/DpqlEditor.stories.tsx +74 -2
- package/src/components/form/engine/CompactRow.tsx +561 -283
- package/src/components/form/engine/CompactToolbar.tsx +216 -182
- package/src/components/form/engine/FormEngine.stories.tsx +1736 -162
- package/src/components/form/engine/FormEngine.tsx +886 -170
- package/src/components/form/engine/FormEngineRemote.stories.tsx +377 -0
- package/src/components/form/engine/_structuredData/StructuredDataView.stories.tsx +8 -0
- package/src/components/form/engine/compactRowContext.ts +14 -0
- package/src/components/form/engine/compactRowStyles.ts +273 -146
- package/src/components/form/engine/compactToolbarContext.ts +1 -0
- package/src/components/form/engine/optionActions.ts +40 -0
- package/src/components/form/engine/readFirst.ts +169 -10
- package/src/components/form/engine/rendererTypes.ts +55 -0
- package/src/components/form/engine/variants/FormEngineVariants.stories.tsx +159 -0
- package/src/components/form/engine/variants/VariantCalmTable.tsx +242 -0
- package/src/components/form/engine/variants/VariantCards.tsx +212 -0
- package/src/components/form/engine/variants/VariantFocus.tsx +382 -0
- package/src/components/form/engine/variants/VariantMinimal.tsx +170 -0
- package/src/components/form/engine/variants/focusDemo.ts +145 -0
- package/src/components/form/engine/variants/variantModel.ts +216 -0
- package/src/components/form/engine/variants/variantParts.tsx +313 -0
- package/src/components/form/expressions/ExpressionField.stories.tsx +84 -2
- package/src/components/form/expressions/builder/ExpressionBuilder.stories.tsx +213 -19
- package/src/components/form/expressions/builder/index.tsx +12 -1
- package/src/components/form/expressions/useExpressions.ts +4 -1
- package/src/components/form/fields/Field.stories.tsx +40 -0
- package/src/components/form/fields/Field.tsx +10 -1
- package/src/components/form/fields/allowed-values/AllowedValues.tsx +13 -36
- package/src/components/form/fields/array/ArrayAutoField.stories.tsx +64 -0
- package/src/components/form/fields/auto/AutoFormField.stories.tsx +146 -2
- package/src/components/form/fields/auto/AutoFormField.tsx +42 -1
- package/src/components/form/fields/binary/Binary.stories.tsx +122 -0
- package/src/components/form/fields/binary/Binary.tsx +81 -0
- package/src/components/form/fields/boolean/Boolean.stories.tsx +58 -0
- package/src/components/form/fields/boolean/Boolean.tsx +1 -1
- package/src/components/form/fields/byte-size/ByteSize.stories.tsx +24 -0
- package/src/components/form/fields/color/Color.stories.tsx +30 -0
- package/src/components/form/fields/cron/Cron.stories.tsx +8 -0
- package/src/components/form/fields/date/Date.stories.tsx +22 -0
- package/src/components/form/fields/file/File.stories.tsx +48 -0
- package/src/components/form/fields/long-string/LongString.stories.tsx +24 -0
- package/src/components/form/fields/markdown/Markdown.stories.tsx +8 -0
- package/src/components/form/fields/multi-select/MultiSelectFormField.tsx +14 -10
- package/src/components/form/fields/number/Number.stories.tsx +31 -0
- package/src/components/form/fields/object/Object.stories.tsx +88 -0
- package/src/components/form/fields/radio-group/RadioGroup.stories.tsx +24 -0
- package/src/components/form/fields/rich-text/RichText.stories.tsx +23 -0
- package/src/components/form/fields/schema-definition/SchemaDefinitionField.stories.tsx +72 -0
- package/src/components/form/fields/select/Select.stories.tsx +108 -0
- package/src/components/form/fields/select/Select.tsx +38 -12
- package/src/components/form/fields/select/SelectCollection.tsx +78 -17
- package/src/components/form/fields/string/String.stories.tsx +16 -0
- package/src/components/form/fields/template/TemplateField.stories.tsx +160 -0
- package/src/components/form/fields/url/Url.stories.tsx +24 -0
- package/src/components/form/index.tsx +2 -0
- package/src/components/imageLightbox/ImageLightbox.stories.tsx +238 -0
- package/src/components/imageLightbox/ImageLightbox.tsx +236 -0
- package/src/components/imageLightbox/index.ts +1 -0
- package/src/components/log/Log.stories.tsx +96 -0
- package/src/components/menu/Menu.stories.tsx +54 -0
- package/src/components/qonsoleSmartInput/QonsoleSmartInput.stories.tsx +83 -37
- package/src/components/searchFilterBar/SearchFilterBar.tsx +131 -0
- package/src/components/searchFilterBar/index.ts +1 -0
- package/src/components/smartEditor/SmartEditor.stories.tsx +32 -0
- package/src/components/supportTicket/AttachmentChips.stories.tsx +171 -0
- package/src/components/supportTicket/AttachmentChips.tsx +147 -0
- package/src/components/supportTicket/InterfaceReferenceTags.stories.tsx +171 -0
- package/src/components/supportTicket/InterfaceReferenceTags.tsx +96 -0
- package/src/components/supportTicket/ReferencePicker.stories.tsx +519 -0
- package/src/components/supportTicket/ReferencePicker.tsx +563 -0
- package/src/components/supportTicket/TicketConversation.stories.tsx +121 -0
- package/src/components/supportTicket/TicketHeader.stories.tsx +183 -0
- package/src/components/supportTicket/TicketHeader.tsx +247 -0
- package/src/components/supportTicket/TicketMetaTags.stories.tsx +103 -0
- package/src/components/supportTicket/TicketMetaTags.tsx +85 -0
- package/src/components/supportTicket/TicketReplyBox.stories.tsx +351 -0
- package/src/components/supportTicket/TicketReplyBox.tsx +146 -0
- package/src/components/supportTicket/attachmentAccess.ts +97 -0
- package/src/components/supportTicket/fileToAttachment.ts +24 -0
- package/src/components/supportTicket/index.ts +10 -0
- package/src/components/supportTicket/meta.ts +185 -0
- package/src/components/supportTicket/ticketModel.ts +131 -0
- package/src/components/ticketReferences/TicketReferences.stories.tsx +315 -0
- package/src/components/ticketReferences/TicketReferences.tsx +886 -0
- package/src/components/ticketReferences/index.ts +2 -0
- package/src/components/ticketThread/TicketThread.stories.tsx +828 -0
- package/src/components/ticketThread/TicketThread.tsx +704 -0
- package/src/components/ticketThread/index.ts +6 -0
- package/src/helpers/common.ts +19 -0
- package/src/helpers/scrollbar.ts +32 -0
- package/src/hooks/useFetch/useFetch.stories.tsx +30 -0
- package/src/hooks/useStorage/useStorage.stories.tsx +82 -0
- package/src/hooks/useWebSocket/useWebsocket.stories.tsx +127 -1
- package/src/index.tsx +8 -1
- package/src/providers/StorageProvider.tsx +30 -4
- package/src/stores/currentUser/currentUser.stories.tsx +49 -0
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
import { ReqoreButton, ReqoreUIProvider } from '@qoretechnologies/reqore';
|
|
2
|
+
import { StoryObj } from '@storybook/react-vite';
|
|
3
|
+
import { ComponentProps, useState } from 'react';
|
|
4
|
+
import { expect, fn, userEvent, waitFor, within } from 'storybook/test';
|
|
5
|
+
import { StoryMeta } from '../../types';
|
|
6
|
+
import { InterfaceReferenceTags } from './InterfaceReferenceTags';
|
|
7
|
+
import { IInterfaceReference } from './meta';
|
|
8
|
+
import { ReferencePicker, TReferencePickerItem } from './ReferencePicker';
|
|
9
|
+
import { TicketReplyBox } from './TicketReplyBox';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The interface browser — kinds on one side, the selected kind's interfaces on the
|
|
13
|
+
* other, one search bar scoping both. Rendered **on top** of the composer and toggled
|
|
14
|
+
* by its "Reference interfaces" action. Search dims non-matching kinds rather than
|
|
15
|
+
* removing them, picked interfaces stay in the list as selected rows, and the two panes
|
|
16
|
+
* collapse into one column (with a modal on phones) when there isn't width for both.
|
|
17
|
+
*/
|
|
18
|
+
const meta = {
|
|
19
|
+
component: ReferencePicker,
|
|
20
|
+
title: 'Components/ReferencePicker',
|
|
21
|
+
} as StoryMeta<typeof ReferencePicker>;
|
|
22
|
+
export default meta;
|
|
23
|
+
type Story = StoryObj<typeof meta>;
|
|
24
|
+
|
|
25
|
+
const ACCENT = { main: 'custom1' } as const;
|
|
26
|
+
|
|
27
|
+
/* The kind ids a host passes — wire values, not labels. `qog` is the customer-facing
|
|
28
|
+
* kind for what the instance still lists as `fsm`; hosts map that at the fetch
|
|
29
|
+
* boundary, so `fsm` never reaches the picker. */
|
|
30
|
+
const KINDS = [
|
|
31
|
+
'workflow',
|
|
32
|
+
'service',
|
|
33
|
+
'job',
|
|
34
|
+
'connection',
|
|
35
|
+
'mapper',
|
|
36
|
+
'class',
|
|
37
|
+
'value-map',
|
|
38
|
+
'qog',
|
|
39
|
+
'ai-collection',
|
|
40
|
+
'ai-endpoint',
|
|
41
|
+
'ai-guardrail',
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
/* Stands in for the host's fetch: in the IDE these come off the customer's live
|
|
45
|
+
* instance one kind at a time. Services carry the richer item shape — a description
|
|
46
|
+
* and a badge — with `partner-gateway` left as a bare string so the plain row and the
|
|
47
|
+
* mixed list both stay on screen. */
|
|
48
|
+
const CATALOGUE: Record<string, TReferencePickerItem[]> = {
|
|
49
|
+
workflow: ['order-sync:1.2', 'invoice-export:2.0', 'partner-recon:1.1'],
|
|
50
|
+
service: [
|
|
51
|
+
{
|
|
52
|
+
name: 'notifier',
|
|
53
|
+
description: 'Fans order events out to email and Slack',
|
|
54
|
+
badge: '3 running',
|
|
55
|
+
},
|
|
56
|
+
{ name: 'audit-logger', description: 'Writes every state change to the audit table' },
|
|
57
|
+
'partner-gateway',
|
|
58
|
+
],
|
|
59
|
+
job: ['nightly-recon', 'cleanup-temp', 'sla-report'],
|
|
60
|
+
connection: ['sftp-partner', 'pgsql-omq', 'salesforce-prod'],
|
|
61
|
+
mapper: ['csv-to-order', 'order-to-invoice'],
|
|
62
|
+
class: ['OrderUtils', 'PartnerApi'],
|
|
63
|
+
'value-map': ['country-codes', 'currency'],
|
|
64
|
+
qog: ['telegram-intake', 'stripe-billing', 'onboarding', 'escalation'],
|
|
65
|
+
'ai-collection': ['kb-support'],
|
|
66
|
+
'ai-endpoint': ['gpt-router'],
|
|
67
|
+
'ai-guardrail': ['pii-filter'],
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const darkTheme = (Story: () => JSX.Element) => (
|
|
71
|
+
<ReqoreUIProvider theme={{ main: '#121212', intents: { custom1: '#762f7e' } }}>
|
|
72
|
+
<div style={{ padding: 20, background: '#121212' }}>
|
|
73
|
+
<Story />
|
|
74
|
+
</div>
|
|
75
|
+
</ReqoreUIProvider>
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
/** Drives the picker the way a host does: owns the selected kind, resolves that
|
|
79
|
+
* kind's interfaces, and accumulates what gets picked. */
|
|
80
|
+
const Hosted = ({
|
|
81
|
+
withComposer,
|
|
82
|
+
initialKind = 'workflow',
|
|
83
|
+
...pickerProps
|
|
84
|
+
}: { withComposer?: boolean; initialKind?: string } & Partial<
|
|
85
|
+
ComponentProps<typeof ReferencePicker>
|
|
86
|
+
>) => {
|
|
87
|
+
const [kind, setKind] = useState<string>(initialKind);
|
|
88
|
+
const [picked, setPicked] = useState<IInterfaceReference[]>([]);
|
|
89
|
+
const [open, setOpen] = useState<boolean>(true);
|
|
90
|
+
|
|
91
|
+
const isPicked = (reference: IInterfaceReference) =>
|
|
92
|
+
picked.some(
|
|
93
|
+
(existing) =>
|
|
94
|
+
existing.interface_kind === reference.interface_kind &&
|
|
95
|
+
existing.interface_name === reference.interface_name
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const picker = (
|
|
99
|
+
<ReferencePicker
|
|
100
|
+
kinds={KINDS}
|
|
101
|
+
kind={kind}
|
|
102
|
+
onKindChange={setKind}
|
|
103
|
+
items={CATALOGUE[kind] ?? []}
|
|
104
|
+
picked={picked}
|
|
105
|
+
onAdd={(reference) =>
|
|
106
|
+
setPicked((current) => (isPicked(reference) ? current : [...current, reference]))
|
|
107
|
+
}
|
|
108
|
+
onRemove={(reference) =>
|
|
109
|
+
setPicked((current) =>
|
|
110
|
+
current.filter(
|
|
111
|
+
(existing) =>
|
|
112
|
+
!(
|
|
113
|
+
existing.interface_kind === reference.interface_kind &&
|
|
114
|
+
existing.interface_name === reference.interface_name
|
|
115
|
+
)
|
|
116
|
+
)
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
{...pickerProps}
|
|
120
|
+
/>
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
if (!withComposer) {
|
|
124
|
+
return picker;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return (
|
|
128
|
+
<div style={{ maxWidth: 780 }}>
|
|
129
|
+
{open ? <div style={{ marginBottom: 10 }}>{picker}</div> : null}
|
|
130
|
+
<TicketReplyBox
|
|
131
|
+
onSend={fn()}
|
|
132
|
+
placeholder='Write a reply…'
|
|
133
|
+
aboveInput={
|
|
134
|
+
picked.length ? (
|
|
135
|
+
/* Composer chips are the references you're about to send, so they carry
|
|
136
|
+
their own remove — and read a size up from the thread's, where they're
|
|
137
|
+
a record rather than a control. */
|
|
138
|
+
<InterfaceReferenceTags
|
|
139
|
+
customTheme={ACCENT}
|
|
140
|
+
references={picked}
|
|
141
|
+
onRemove={(reference) =>
|
|
142
|
+
setPicked((current) =>
|
|
143
|
+
current.filter(
|
|
144
|
+
(existing) =>
|
|
145
|
+
!(
|
|
146
|
+
existing.interface_kind === reference.interface_kind &&
|
|
147
|
+
existing.interface_name === reference.interface_name
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
/>
|
|
153
|
+
) : undefined
|
|
154
|
+
}
|
|
155
|
+
footerActions={
|
|
156
|
+
<ReqoreButton
|
|
157
|
+
className='references-toggle'
|
|
158
|
+
icon='LinksLine'
|
|
159
|
+
minimal
|
|
160
|
+
flat
|
|
161
|
+
badge={picked.length || undefined}
|
|
162
|
+
active={open}
|
|
163
|
+
customTheme={ACCENT}
|
|
164
|
+
tooltip={open ? 'Hide references' : 'Reference interfaces'}
|
|
165
|
+
onClick={() => setOpen((shown) => !shown)}
|
|
166
|
+
/>
|
|
167
|
+
}
|
|
168
|
+
/>
|
|
169
|
+
</div>
|
|
170
|
+
);
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
/*
|
|
174
|
+
* Queried by role, not by text: ReqoreButton renders its label in a pair of spans (an
|
|
175
|
+
* active one and an aria-hidden inactive one) to cross-fade, so getByText matches twice
|
|
176
|
+
* for every button. The accessible name collapses that pair back to one.
|
|
177
|
+
*/
|
|
178
|
+
const option = (canvas: ReturnType<typeof within>, name: string) =>
|
|
179
|
+
canvas.getByRole('button', { name });
|
|
180
|
+
const missingOption = (canvas: ReturnType<typeof within>, name: string) =>
|
|
181
|
+
canvas.queryByRole('button', { name });
|
|
182
|
+
|
|
183
|
+
/** Picking an interface adds it as a reference and leaves the row in place, selected. */
|
|
184
|
+
export const Default: Story = {
|
|
185
|
+
parameters: {
|
|
186
|
+
docs: {
|
|
187
|
+
description: {
|
|
188
|
+
story:
|
|
189
|
+
'Renders the two-pane reference browser. Picking an interface adds it as a reference and leaves the row in the list, selected and ticked, rather than removing it.',
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
decorators: [darkTheme],
|
|
194
|
+
render: () => <Hosted />,
|
|
195
|
+
async play({ canvasElement }) {
|
|
196
|
+
const canvas = within(canvasElement);
|
|
197
|
+
await userEvent.click(await canvas.findByRole('button', { name: 'order-sync:1.2' }));
|
|
198
|
+
// it stays in the pane, now selected
|
|
199
|
+
await waitFor(() =>
|
|
200
|
+
expect(option(canvas, 'order-sync:1.2')).toHaveClass('reqore-reference-picker-picked')
|
|
201
|
+
);
|
|
202
|
+
// its siblings are untouched
|
|
203
|
+
await expect(option(canvas, 'invoice-export:2.0')).toBeInTheDocument();
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
/** A picked interface can be un-picked from the list it was picked in. */
|
|
208
|
+
export const DeselectsAPickedInterface: Story = {
|
|
209
|
+
parameters: {
|
|
210
|
+
docs: {
|
|
211
|
+
description: {
|
|
212
|
+
story:
|
|
213
|
+
'Renders the browser and picks an interface, then clicks the same row again — the reference comes back off without the user having to click away from the picker.',
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
decorators: [darkTheme],
|
|
218
|
+
render: () => <Hosted />,
|
|
219
|
+
async play({ canvasElement }) {
|
|
220
|
+
const canvas = within(canvasElement);
|
|
221
|
+
const row = await canvas.findByRole('button', { name: 'invoice-export:2.0' });
|
|
222
|
+
|
|
223
|
+
await userEvent.click(row);
|
|
224
|
+
await waitFor(() => expect(row).toHaveClass('reqore-reference-picker-picked'));
|
|
225
|
+
|
|
226
|
+
await userEvent.click(row);
|
|
227
|
+
await waitFor(() => expect(row).not.toHaveClass('reqore-reference-picker-picked'));
|
|
228
|
+
},
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Interfaces can arrive as bare names or as objects carrying a description and a
|
|
233
|
+
* badge — a name alone often isn't enough to tell two of them apart. A picked row
|
|
234
|
+
* tints rather than filling solid, so the ones still up for choosing stay the loudest
|
|
235
|
+
* things in the list.
|
|
236
|
+
*/
|
|
237
|
+
export const WithDescriptionsAndBadges: Story = {
|
|
238
|
+
parameters: {
|
|
239
|
+
docs: {
|
|
240
|
+
description: {
|
|
241
|
+
story:
|
|
242
|
+
'Renders a kind whose interfaces carry descriptions and badges alongside one that has neither. Picking a row tints it rather than filling it solid, keeping the unpicked rows the most prominent.',
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
decorators: [darkTheme],
|
|
247
|
+
render: () => <Hosted initialKind='service' />,
|
|
248
|
+
async play({ canvasElement }) {
|
|
249
|
+
const canvas = within(canvasElement);
|
|
250
|
+
await expect(
|
|
251
|
+
await canvas.findByText('Fans order events out to email and Slack')
|
|
252
|
+
).toBeInTheDocument();
|
|
253
|
+
await expect(canvas.getByText('3 running')).toBeInTheDocument();
|
|
254
|
+
|
|
255
|
+
// a bare-string item in the same list renders as a plain row
|
|
256
|
+
await expect(option(canvas, 'partner-gateway')).toBeInTheDocument();
|
|
257
|
+
|
|
258
|
+
// picking keeps the description and badge in place
|
|
259
|
+
await userEvent.click(canvas.getByRole('button', { name: /audit-logger/ }));
|
|
260
|
+
await waitFor(() =>
|
|
261
|
+
expect(canvas.getByRole('button', { name: /audit-logger/ })).toHaveClass(
|
|
262
|
+
'reqore-reference-picker-picked'
|
|
263
|
+
)
|
|
264
|
+
);
|
|
265
|
+
await expect(
|
|
266
|
+
canvas.getByText('Writes every state change to the audit table')
|
|
267
|
+
).toBeInTheDocument();
|
|
268
|
+
},
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
/** A description is searchable text too, so the search reads it alongside the name. */
|
|
272
|
+
export const SearchMatchesDescriptions: Story = {
|
|
273
|
+
parameters: {
|
|
274
|
+
docs: {
|
|
275
|
+
description: {
|
|
276
|
+
story:
|
|
277
|
+
"Renders a kind with described interfaces and searches for a word that appears only in a description — the matching row survives even though its name doesn't contain the query.",
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
decorators: [darkTheme],
|
|
282
|
+
render: () => <Hosted initialKind='service' />,
|
|
283
|
+
async play({ canvasElement }) {
|
|
284
|
+
const canvas = within(canvasElement);
|
|
285
|
+
const search = canvasElement.querySelector(
|
|
286
|
+
'input[placeholder*="Search types"]'
|
|
287
|
+
) as HTMLInputElement;
|
|
288
|
+
|
|
289
|
+
// "Slack" is only in the notifier's description
|
|
290
|
+
await userEvent.type(search, 'slack');
|
|
291
|
+
await waitFor(() => expect(missingOption(canvas, 'partner-gateway')).not.toBeInTheDocument());
|
|
292
|
+
await expect(canvas.getByRole('button', { name: /notifier/ })).toBeInTheDocument();
|
|
293
|
+
},
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
/** Selecting a kind on the left swaps the right pane to that kind's interfaces. */
|
|
297
|
+
export const SwitchesKind: Story = {
|
|
298
|
+
parameters: {
|
|
299
|
+
docs: {
|
|
300
|
+
description: {
|
|
301
|
+
story:
|
|
302
|
+
"Renders the picker and shows that selecting a kind on the left swaps the right pane to that kind's interfaces.",
|
|
303
|
+
},
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
decorators: [darkTheme],
|
|
307
|
+
render: () => <Hosted />,
|
|
308
|
+
async play({ canvasElement }) {
|
|
309
|
+
const canvas = within(canvasElement);
|
|
310
|
+
await expect(option(canvas, 'order-sync:1.2')).toBeInTheDocument();
|
|
311
|
+
await userEvent.click(option(canvas, 'Connections'));
|
|
312
|
+
await waitFor(() => expect(option(canvas, 'sftp-partner')).toBeInTheDocument());
|
|
313
|
+
await expect(missingOption(canvas, 'order-sync:1.2')).not.toBeInTheDocument();
|
|
314
|
+
},
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* One search scopes both panes: non-matching kinds drop off the left so the matches
|
|
319
|
+
* are the whole list, and the selected kind stays on — dimmed — even when the query
|
|
320
|
+
* doesn't match it, so the interfaces on the right always have a visible owner.
|
|
321
|
+
*/
|
|
322
|
+
export const SearchKeepsTheSelectedKind: Story = {
|
|
323
|
+
parameters: {
|
|
324
|
+
docs: {
|
|
325
|
+
description: {
|
|
326
|
+
story:
|
|
327
|
+
"Renders the picker and types a search. Non-matching kinds drop off the left pane, but the selected kind stays on as a dimmed row so the interfaces still listed on the right can be told apart from the kind they belong to.",
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
decorators: [darkTheme],
|
|
332
|
+
render: () => <Hosted />,
|
|
333
|
+
async play({ canvasElement }) {
|
|
334
|
+
const canvas = within(canvasElement);
|
|
335
|
+
const search = canvasElement.querySelector(
|
|
336
|
+
'input[placeholder*="Search types"]'
|
|
337
|
+
) as HTMLInputElement;
|
|
338
|
+
|
|
339
|
+
await userEvent.type(search, 'sync');
|
|
340
|
+
// right pane: only the matching interface survives
|
|
341
|
+
await waitFor(() =>
|
|
342
|
+
expect(missingOption(canvas, 'invoice-export:2.0')).not.toBeInTheDocument()
|
|
343
|
+
);
|
|
344
|
+
await expect(option(canvas, 'order-sync:1.2')).toBeInTheDocument();
|
|
345
|
+
// left pane: nothing is called "sync", so only the selected kind is left — dimmed,
|
|
346
|
+
// which is what tells you the surviving interface is a workflow
|
|
347
|
+
await expect(option(canvas, 'Workflows')).toHaveClass('reqore-reference-picker-dimmed');
|
|
348
|
+
await expect(missingOption(canvas, 'Services')).not.toBeInTheDocument();
|
|
349
|
+
|
|
350
|
+
// a kind name matches: it joins the list at full strength, next to the still-dimmed
|
|
351
|
+
// selected kind
|
|
352
|
+
await userEvent.clear(search);
|
|
353
|
+
await userEvent.type(search, 'connect');
|
|
354
|
+
await waitFor(() =>
|
|
355
|
+
expect(option(canvas, 'Connections')).not.toHaveClass(
|
|
356
|
+
'reqore-reference-picker-dimmed'
|
|
357
|
+
)
|
|
358
|
+
);
|
|
359
|
+
await expect(option(canvas, 'Workflows')).toHaveClass('reqore-reference-picker-dimmed');
|
|
360
|
+
await expect(missingOption(canvas, 'Jobs')).not.toBeInTheDocument();
|
|
361
|
+
},
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Narrow container: the panes collapse into one column and the selected kind's
|
|
366
|
+
* interfaces render directly under its row. The width measured is the picker's own,
|
|
367
|
+
* not the viewport's — this canvas is 320px wide on a desktop-sized screen, which is
|
|
368
|
+
* exactly the case a viewport media query gets wrong.
|
|
369
|
+
*/
|
|
370
|
+
export const StacksInANarrowContainer: Story = {
|
|
371
|
+
parameters: {
|
|
372
|
+
docs: {
|
|
373
|
+
description: {
|
|
374
|
+
story:
|
|
375
|
+
"Renders the picker in a 320px-wide container on a full-size screen: it collapses to one column on its own measured width, with the selected kind's interfaces indented directly beneath its row instead of in a second pane.",
|
|
376
|
+
},
|
|
377
|
+
},
|
|
378
|
+
},
|
|
379
|
+
decorators: [darkTheme],
|
|
380
|
+
render: () => (
|
|
381
|
+
<div style={{ width: 320 }}>
|
|
382
|
+
<Hosted />
|
|
383
|
+
</div>
|
|
384
|
+
),
|
|
385
|
+
async play({ canvasElement }) {
|
|
386
|
+
const canvas = within(canvasElement);
|
|
387
|
+
const services = option(canvas, 'Services');
|
|
388
|
+
|
|
389
|
+
/* Stacked is a claim about ORDER, not just presence: the workflows sit between
|
|
390
|
+
their own kind row and the next one. Side by side, every kind would come
|
|
391
|
+
first and the interfaces after — so the comparison tells the two apart
|
|
392
|
+
without reaching for a marker class. */
|
|
393
|
+
await waitFor(() => {
|
|
394
|
+
const workflow = option(canvas, 'order-sync:1.2');
|
|
395
|
+
expect(
|
|
396
|
+
workflow.compareDocumentPosition(services) & Node.DOCUMENT_POSITION_FOLLOWING
|
|
397
|
+
).toBeTruthy();
|
|
398
|
+
});
|
|
399
|
+
await expect(option(canvas, 'Workflows')).toBeInTheDocument();
|
|
400
|
+
},
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
/** On a phone the picker lifts into a modal — inline it would own the whole screen. */
|
|
404
|
+
export const OnAPhone: Story = {
|
|
405
|
+
parameters: {
|
|
406
|
+
// capture this one at phone size; the modal portals to the viewport, so a
|
|
407
|
+
// narrow story wrapper wouldn't constrain it
|
|
408
|
+
qlip: { viewport: { width: 390, height: 844 } },
|
|
409
|
+
docs: {
|
|
410
|
+
description: {
|
|
411
|
+
story:
|
|
412
|
+
'Renders the phone presentation: the picker lifts out of the composer into a full-width modal with a close action, stacked into a single column.',
|
|
413
|
+
},
|
|
414
|
+
},
|
|
415
|
+
},
|
|
416
|
+
decorators: [darkTheme],
|
|
417
|
+
render: () => <Hosted presentation='modal' layout='stacked' onClose={fn()} />,
|
|
418
|
+
async play() {
|
|
419
|
+
// the modal portals out of the story canvas, so query the document
|
|
420
|
+
const canvas = within(document.body);
|
|
421
|
+
await expect(await canvas.findByText('Reference interfaces')).toBeInTheDocument();
|
|
422
|
+
await expect(await canvas.findByRole('button', { name: 'order-sync:1.2' })).toBeInTheDocument();
|
|
423
|
+
},
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
/** The right pane says it's still fetching rather than claiming the kind is empty. */
|
|
427
|
+
export const Loading: Story = {
|
|
428
|
+
parameters: {
|
|
429
|
+
docs: {
|
|
430
|
+
description: {
|
|
431
|
+
story:
|
|
432
|
+
"Renders the loading state, where the right pane reports it is still fetching ('Loading workflows…') rather than claiming the kind is empty.",
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
decorators: [darkTheme],
|
|
437
|
+
render: () => (
|
|
438
|
+
<ReferencePicker
|
|
439
|
+
kinds={KINDS}
|
|
440
|
+
kind='workflow'
|
|
441
|
+
onKindChange={fn()}
|
|
442
|
+
items={[]}
|
|
443
|
+
loading
|
|
444
|
+
onAdd={fn()}
|
|
445
|
+
/>
|
|
446
|
+
),
|
|
447
|
+
async play({ canvasElement }) {
|
|
448
|
+
const canvas = within(canvasElement);
|
|
449
|
+
await expect(canvas.getByText('Loading workflows…')).toBeInTheDocument();
|
|
450
|
+
await expect(canvas.queryByText(/No workflows/)).not.toBeInTheDocument();
|
|
451
|
+
},
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* The host's fetch failed. The pane says so and offers a retry — an empty list here
|
|
456
|
+
* would read as "this instance has no connections", which is a different and much more
|
|
457
|
+
* alarming claim than "we couldn't ask". The specific failure is the tooltip.
|
|
458
|
+
*/
|
|
459
|
+
export const LoadFailed: Story = {
|
|
460
|
+
parameters: {
|
|
461
|
+
docs: {
|
|
462
|
+
description: {
|
|
463
|
+
story:
|
|
464
|
+
"Renders the fetch-failure state, where the pane shows the error and a retry action instead of an empty list that would read as 'this instance has no connections'.",
|
|
465
|
+
},
|
|
466
|
+
},
|
|
467
|
+
},
|
|
468
|
+
decorators: [darkTheme],
|
|
469
|
+
render: () => (
|
|
470
|
+
<ReferencePicker
|
|
471
|
+
kinds={KINDS}
|
|
472
|
+
kind='connection'
|
|
473
|
+
onKindChange={fn()}
|
|
474
|
+
items={[]}
|
|
475
|
+
error='Could not reach the Qorus instance'
|
|
476
|
+
onRetry={fn()}
|
|
477
|
+
onAdd={fn()}
|
|
478
|
+
/>
|
|
479
|
+
),
|
|
480
|
+
async play({ canvasElement }) {
|
|
481
|
+
const canvas = within(canvasElement);
|
|
482
|
+
const retry = await canvas.findByRole('button', { name: /Couldn't load connections/ });
|
|
483
|
+
await expect(retry).toBeInTheDocument();
|
|
484
|
+
// the failure replaces the list rather than sitting alongside an empty one
|
|
485
|
+
await expect(canvas.queryByText(/No connections/)).not.toBeInTheDocument();
|
|
486
|
+
},
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
/** In place: above the composer, toggled by the composer's own action, with the picked
|
|
490
|
+
* references shown as chips over the input. */
|
|
491
|
+
export const AboveTheComposer: Story = {
|
|
492
|
+
parameters: {
|
|
493
|
+
docs: {
|
|
494
|
+
description: {
|
|
495
|
+
story:
|
|
496
|
+
"Renders the picker in place above the composer, toggled by the composer's own action, with picked references surfacing as chips over the input that persist when the picker is closed.",
|
|
497
|
+
},
|
|
498
|
+
},
|
|
499
|
+
},
|
|
500
|
+
decorators: [darkTheme],
|
|
501
|
+
render: () => <Hosted withComposer />,
|
|
502
|
+
async play({ canvasElement }) {
|
|
503
|
+
const canvas = within(canvasElement);
|
|
504
|
+
await userEvent.click(await canvas.findByRole('button', { name: 'order-sync:1.2' }));
|
|
505
|
+
// the pick stays selected in the pane and surfaces as a chip on the composer
|
|
506
|
+
await waitFor(() =>
|
|
507
|
+
expect(option(canvas, 'order-sync:1.2')).toHaveClass('reqore-reference-picker-picked')
|
|
508
|
+
);
|
|
509
|
+
await expect(canvas.getAllByText('order-sync:1.2').length).toBeGreaterThan(0);
|
|
510
|
+
|
|
511
|
+
const toggle = canvasElement.querySelector('.references-toggle') as HTMLElement;
|
|
512
|
+
await userEvent.click(toggle);
|
|
513
|
+
// the picker closes; the chip stays, because the reference is still attached
|
|
514
|
+
await waitFor(() =>
|
|
515
|
+
expect(missingOption(canvas, 'invoice-export:2.0')).not.toBeInTheDocument()
|
|
516
|
+
);
|
|
517
|
+
await expect(canvas.getAllByText('order-sync:1.2').length).toBeGreaterThan(0);
|
|
518
|
+
},
|
|
519
|
+
};
|