@flanksource/clicky-ui 0.2.14 → 0.2.16
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/chat.cjs +20 -0
- package/dist/chat.cjs.map +1 -0
- package/dist/chat.d.ts +2 -0
- package/dist/chat.d.ts.map +1 -0
- package/dist/chat.js +20 -0
- package/dist/chat.js.map +1 -0
- package/dist/components/Combobox.cjs +19 -9
- package/dist/components/Combobox.cjs.map +1 -1
- package/dist/components/Combobox.d.ts +10 -0
- package/dist/components/Combobox.d.ts.map +1 -1
- package/dist/components/Combobox.js +19 -9
- package/dist/components/Combobox.js.map +1 -1
- package/dist/components/DateTimePicker.cjs +6 -1
- package/dist/components/DateTimePicker.cjs.map +1 -1
- package/dist/components/DateTimePicker.d.ts +11 -3
- package/dist/components/DateTimePicker.d.ts.map +1 -1
- package/dist/components/DateTimePicker.js +6 -1
- package/dist/components/DateTimePicker.js.map +1 -1
- package/dist/components/Field.cjs +33 -0
- package/dist/components/Field.cjs.map +1 -0
- package/dist/components/Field.d.ts +27 -0
- package/dist/components/Field.d.ts.map +1 -0
- package/dist/components/Field.js +33 -0
- package/dist/components/Field.js.map +1 -0
- package/dist/components/FilterBar.cjs +49 -55
- package/dist/components/FilterBar.cjs.map +1 -1
- package/dist/components/FilterBar.d.ts +2 -2
- package/dist/components/FilterBar.d.ts.map +1 -1
- package/dist/components/FilterBar.js +44 -50
- package/dist/components/FilterBar.js.map +1 -1
- package/dist/components/FormatOptionsDropdown.cjs +2 -18
- package/dist/components/FormatOptionsDropdown.cjs.map +1 -1
- package/dist/components/FormatOptionsDropdown.d.ts +1 -17
- package/dist/components/FormatOptionsDropdown.d.ts.map +1 -1
- package/dist/components/FormatOptionsDropdown.js +1 -17
- package/dist/components/FormatOptionsDropdown.js.map +1 -1
- package/dist/components/JsonSchemaForm.cjs +128 -12
- package/dist/components/JsonSchemaForm.cjs.map +1 -1
- package/dist/components/JsonSchemaForm.d.ts +1 -1
- package/dist/components/JsonSchemaForm.d.ts.map +1 -1
- package/dist/components/JsonSchemaForm.js +131 -15
- package/dist/components/JsonSchemaForm.js.map +1 -1
- package/dist/components/MultiSelect.cjs +2 -1
- package/dist/components/MultiSelect.cjs.map +1 -1
- package/dist/components/MultiSelect.d.ts +5 -1
- package/dist/components/MultiSelect.d.ts.map +1 -1
- package/dist/components/MultiSelect.js +2 -1
- package/dist/components/MultiSelect.js.map +1 -1
- package/dist/components/SecretKeySelector.cjs +0 -1
- package/dist/components/SecretKeySelector.cjs.map +1 -1
- package/dist/components/SecretKeySelector.d.ts +0 -2
- package/dist/components/SecretKeySelector.d.ts.map +1 -1
- package/dist/components/SecretKeySelector.js +1 -2
- package/dist/components/SecretKeySelector.js.map +1 -1
- package/dist/components/TreePickerField.cjs +137 -0
- package/dist/components/TreePickerField.cjs.map +1 -0
- package/dist/components/TreePickerField.d.ts +30 -0
- package/dist/components/TreePickerField.d.ts.map +1 -0
- package/dist/components/TreePickerField.js +137 -0
- package/dist/components/TreePickerField.js.map +1 -0
- package/dist/components/WorkloadPicker.cjs +6 -81
- package/dist/components/WorkloadPicker.cjs.map +1 -1
- package/dist/components/WorkloadPicker.d.ts +1 -20
- package/dist/components/WorkloadPicker.d.ts.map +1 -1
- package/dist/components/WorkloadPicker.js +3 -78
- package/dist/components/WorkloadPicker.js.map +1 -1
- package/dist/components/button-variants.cjs +30 -0
- package/dist/components/button-variants.cjs.map +1 -0
- package/dist/components/button-variants.d.ts +5 -0
- package/dist/components/button-variants.d.ts.map +1 -0
- package/dist/components/button-variants.js +30 -0
- package/dist/components/button-variants.js.map +1 -0
- package/dist/components/button.cjs +11 -82
- package/dist/components/button.cjs.map +1 -1
- package/dist/components/button.d.ts +1 -5
- package/dist/components/button.d.ts.map +1 -1
- package/dist/components/button.js +5 -76
- package/dist/components/button.js.map +1 -1
- package/dist/components/filter-bar-utils.cjs +37 -0
- package/dist/components/filter-bar-utils.cjs.map +1 -0
- package/dist/components/filter-bar-utils.d.ts +4 -0
- package/dist/components/filter-bar-utils.d.ts.map +1 -0
- package/dist/components/filter-bar-utils.js +37 -0
- package/dist/components/filter-bar-utils.js.map +1 -0
- package/dist/components/format-options.cjs +20 -0
- package/dist/components/format-options.cjs.map +1 -0
- package/dist/components/format-options.d.ts +18 -0
- package/dist/components/format-options.d.ts.map +1 -0
- package/dist/components/format-options.js +20 -0
- package/dist/components/format-options.js.map +1 -0
- package/dist/components/json-schema-form-array.cjs +13 -17
- package/dist/components/json-schema-form-array.cjs.map +1 -1
- package/dist/components/json-schema-form-array.d.ts +1 -2
- package/dist/components/json-schema-form-array.d.ts.map +1 -1
- package/dist/components/json-schema-form-array.js +3 -7
- package/dist/components/json-schema-form-array.js.map +1 -1
- package/dist/components/json-schema-form-fields.cjs +97 -232
- package/dist/components/json-schema-form-fields.cjs.map +1 -1
- package/dist/components/json-schema-form-fields.d.ts +51 -6
- package/dist/components/json-schema-form-fields.d.ts.map +1 -1
- package/dist/components/json-schema-form-fields.js +89 -224
- package/dist/components/json-schema-form-fields.js.map +1 -1
- package/dist/components/json-schema-form-object.cjs +149 -0
- package/dist/components/json-schema-form-object.cjs.map +1 -0
- package/dist/components/json-schema-form-object.d.ts +10 -0
- package/dist/components/json-schema-form-object.d.ts.map +1 -0
- package/dist/components/json-schema-form-object.js +149 -0
- package/dist/components/json-schema-form-object.js.map +1 -0
- package/dist/components/json-schema-form-preferences.cjs +41 -0
- package/dist/components/json-schema-form-preferences.cjs.map +1 -0
- package/dist/components/json-schema-form-preferences.d.ts +10 -0
- package/dist/components/json-schema-form-preferences.d.ts.map +1 -0
- package/dist/components/json-schema-form-preferences.js +41 -0
- package/dist/components/json-schema-form-preferences.js.map +1 -0
- package/dist/components/json-schema-form-render.cjs +43 -72
- package/dist/components/json-schema-form-render.cjs.map +1 -1
- package/dist/components/json-schema-form-render.d.ts +5 -33
- package/dist/components/json-schema-form-render.d.ts.map +1 -1
- package/dist/components/json-schema-form-render.js +41 -70
- package/dist/components/json-schema-form-render.js.map +1 -1
- package/dist/components/json-schema-form-resolve.cjs +9 -1
- package/dist/components/json-schema-form-resolve.cjs.map +1 -1
- package/dist/components/json-schema-form-resolve.d.ts.map +1 -1
- package/dist/components/json-schema-form-resolve.js +9 -1
- package/dist/components/json-schema-form-resolve.js.map +1 -1
- package/dist/components/json-schema-form-types.d.ts +59 -1
- package/dist/components/json-schema-form-types.d.ts.map +1 -1
- package/dist/components/json-schema-form-utils.cjs +96 -0
- package/dist/components/json-schema-form-utils.cjs.map +1 -0
- package/dist/components/json-schema-form-utils.d.ts +17 -0
- package/dist/components/json-schema-form-utils.d.ts.map +1 -0
- package/dist/components/json-schema-form-utils.js +96 -0
- package/dist/components/json-schema-form-utils.js.map +1 -0
- package/dist/components/loading.cjs +109 -0
- package/dist/components/loading.cjs.map +1 -0
- package/dist/components/loading.d.ts +29 -0
- package/dist/components/loading.d.ts.map +1 -0
- package/dist/components/loading.js +109 -0
- package/dist/components/loading.js.map +1 -0
- package/dist/components/use-form.cjs +27 -0
- package/dist/components/use-form.cjs.map +1 -0
- package/dist/components/use-form.d.ts +30 -0
- package/dist/components/use-form.d.ts.map +1 -0
- package/dist/components/use-form.js +27 -0
- package/dist/components/use-form.js.map +1 -0
- package/dist/components/workload-picker-utils.cjs +88 -0
- package/dist/components/workload-picker-utils.cjs.map +1 -0
- package/dist/components/workload-picker-utils.d.ts +34 -0
- package/dist/components/workload-picker-utils.d.ts.map +1 -0
- package/dist/components/workload-picker-utils.js +88 -0
- package/dist/components/workload-picker-utils.js.map +1 -0
- package/dist/components.cjs +25 -6
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.ts +14 -4
- package/dist/components.d.ts.map +1 -1
- package/dist/components.js +24 -5
- package/dist/components.js.map +1 -1
- package/dist/data/Badge.cjs +11 -91
- package/dist/data/Badge.cjs.map +1 -1
- package/dist/data/Badge.d.ts +1 -5
- package/dist/data/Badge.d.ts.map +1 -1
- package/dist/data/Badge.js +11 -91
- package/dist/data/Badge.js.map +1 -1
- package/dist/data/Clicky.cjs +4 -3
- package/dist/data/Clicky.cjs.map +1 -1
- package/dist/data/Clicky.d.ts.map +1 -1
- package/dist/data/Clicky.js +4 -3
- package/dist/data/Clicky.js.map +1 -1
- package/dist/data/DataTable.cjs +161 -156
- package/dist/data/DataTable.cjs.map +1 -1
- package/dist/data/DataTable.d.ts +25 -4
- package/dist/data/DataTable.d.ts.map +1 -1
- package/dist/data/DataTable.js +140 -135
- package/dist/data/DataTable.js.map +1 -1
- package/dist/data/FilterPill.cjs +3 -0
- package/dist/data/FilterPill.cjs.map +1 -1
- package/dist/data/FilterPill.d.ts.map +1 -1
- package/dist/data/FilterPill.js +3 -0
- package/dist/data/FilterPill.js.map +1 -1
- package/dist/data/Icon.cjs +7 -7
- package/dist/data/Icon.cjs.map +1 -1
- package/dist/data/Icon.js +7 -7
- package/dist/data/Icon.js.map +1 -1
- package/dist/data/LogDetails.cjs +5 -14
- package/dist/data/LogDetails.cjs.map +1 -1
- package/dist/data/LogDetails.d.ts +8 -4
- package/dist/data/LogDetails.d.ts.map +1 -1
- package/dist/data/LogDetails.js +4 -13
- package/dist/data/LogDetails.js.map +1 -1
- package/dist/data/LogsTable.cjs +6 -165
- package/dist/data/LogsTable.cjs.map +1 -1
- package/dist/data/LogsTable.d.ts +2 -15
- package/dist/data/LogsTable.d.ts.map +1 -1
- package/dist/data/LogsTable.js +6 -165
- package/dist/data/LogsTable.js.map +1 -1
- package/dist/data/TimeseriesPanel.axes.cjs.map +1 -1
- package/dist/data/TimeseriesPanel.axes.js.map +1 -1
- package/dist/data/TreeNode.cjs +13 -7
- package/dist/data/TreeNode.cjs.map +1 -1
- package/dist/data/TreeNode.d.ts.map +1 -1
- package/dist/data/TreeNode.js +13 -7
- package/dist/data/TreeNode.js.map +1 -1
- package/dist/data/badge-variants.cjs +85 -0
- package/dist/data/badge-variants.cjs.map +1 -0
- package/dist/data/badge-variants.d.ts +6 -0
- package/dist/data/badge-variants.d.ts.map +1 -0
- package/dist/data/badge-variants.js +85 -0
- package/dist/data/badge-variants.js.map +1 -0
- package/dist/data/cache-browser/CacheBrowser.cjs +59 -0
- package/dist/data/cache-browser/CacheBrowser.cjs.map +1 -0
- package/dist/data/cache-browser/CacheBrowser.d.ts +26 -0
- package/dist/data/cache-browser/CacheBrowser.d.ts.map +1 -0
- package/dist/data/cache-browser/CacheBrowser.js +59 -0
- package/dist/data/cache-browser/CacheBrowser.js.map +1 -0
- package/dist/data/cache-browser/CacheDetailPanel.cjs +193 -0
- package/dist/data/cache-browser/CacheDetailPanel.cjs.map +1 -0
- package/dist/data/cache-browser/CacheDetailPanel.d.ts +20 -0
- package/dist/data/cache-browser/CacheDetailPanel.d.ts.map +1 -0
- package/dist/data/cache-browser/CacheDetailPanel.js +193 -0
- package/dist/data/cache-browser/CacheDetailPanel.js.map +1 -0
- package/dist/data/cache-browser/CacheStatsOverview.cjs +126 -0
- package/dist/data/cache-browser/CacheStatsOverview.cjs.map +1 -0
- package/dist/data/cache-browser/CacheStatsOverview.d.ts +17 -0
- package/dist/data/cache-browser/CacheStatsOverview.d.ts.map +1 -0
- package/dist/data/cache-browser/CacheStatsOverview.js +126 -0
- package/dist/data/cache-browser/CacheStatsOverview.js.map +1 -0
- package/dist/data/cache-browser/CacheTree.cjs +189 -0
- package/dist/data/cache-browser/CacheTree.cjs.map +1 -0
- package/dist/data/cache-browser/CacheTree.d.ts +27 -0
- package/dist/data/cache-browser/CacheTree.d.ts.map +1 -0
- package/dist/data/cache-browser/CacheTree.js +189 -0
- package/dist/data/cache-browser/CacheTree.js.map +1 -0
- package/dist/data/cache-browser/CacheValue.cjs +86 -0
- package/dist/data/cache-browser/CacheValue.cjs.map +1 -0
- package/dist/data/cache-browser/CacheValue.d.ts +11 -0
- package/dist/data/cache-browser/CacheValue.d.ts.map +1 -0
- package/dist/data/cache-browser/CacheValue.js +86 -0
- package/dist/data/cache-browser/CacheValue.js.map +1 -0
- package/dist/data/cache-browser/adapter.cjs +52 -0
- package/dist/data/cache-browser/adapter.cjs.map +1 -0
- package/dist/data/cache-browser/adapter.d.ts +48 -0
- package/dist/data/cache-browser/adapter.d.ts.map +1 -0
- package/dist/data/cache-browser/adapter.js +52 -0
- package/dist/data/cache-browser/adapter.js.map +1 -0
- package/dist/data/cache-browser/api.cjs +42 -0
- package/dist/data/cache-browser/api.cjs.map +1 -0
- package/dist/data/cache-browser/api.d.ts +33 -0
- package/dist/data/cache-browser/api.d.ts.map +1 -0
- package/dist/data/cache-browser/api.js +42 -0
- package/dist/data/cache-browser/api.js.map +1 -0
- package/dist/data/cache-browser/index.d.ts +9 -0
- package/dist/data/cache-browser/index.d.ts.map +1 -0
- package/dist/data/cache-browser/types.cjs +7 -0
- package/dist/data/cache-browser/types.cjs.map +1 -0
- package/dist/data/cache-browser/types.d.ts +78 -0
- package/dist/data/cache-browser/types.d.ts.map +1 -0
- package/dist/data/cache-browser/types.js +7 -0
- package/dist/data/cache-browser/types.js.map +1 -0
- package/dist/data/cells/TagList.cjs +4 -101
- package/dist/data/cells/TagList.cjs.map +1 -1
- package/dist/data/cells/TagList.d.ts +1 -49
- package/dist/data/cells/TagList.d.ts.map +1 -1
- package/dist/data/cells/TagList.js +3 -100
- package/dist/data/cells/TagList.js.map +1 -1
- package/dist/data/cells/Timestamp.cjs +3 -192
- package/dist/data/cells/Timestamp.cjs.map +1 -1
- package/dist/data/cells/Timestamp.d.ts +1 -50
- package/dist/data/cells/Timestamp.d.ts.map +1 -1
- package/dist/data/cells/Timestamp.js +2 -191
- package/dist/data/cells/Timestamp.js.map +1 -1
- package/dist/data/cells/tag-utils.cjs +103 -0
- package/dist/data/cells/tag-utils.cjs.map +1 -0
- package/dist/data/cells/tag-utils.d.ts +51 -0
- package/dist/data/cells/tag-utils.d.ts.map +1 -0
- package/dist/data/cells/tag-utils.js +103 -0
- package/dist/data/cells/tag-utils.js.map +1 -0
- package/dist/data/cells/timestamp-format.cjs +193 -0
- package/dist/data/cells/timestamp-format.cjs.map +1 -0
- package/dist/data/cells/timestamp-format.d.ts +51 -0
- package/dist/data/cells/timestamp-format.d.ts.map +1 -0
- package/dist/data/cells/timestamp-format.js +193 -0
- package/dist/data/cells/timestamp-format.js.map +1 -0
- package/dist/data/chat/Chat.cjs +48 -0
- package/dist/data/chat/Chat.cjs.map +1 -0
- package/dist/data/chat/Chat.d.ts +26 -0
- package/dist/data/chat/Chat.d.ts.map +1 -0
- package/dist/data/chat/Chat.fixtures.d.ts +6 -0
- package/dist/data/chat/Chat.fixtures.d.ts.map +1 -0
- package/dist/data/chat/Chat.js +48 -0
- package/dist/data/chat/Chat.js.map +1 -0
- package/dist/data/chat/Conversation.cjs +34 -0
- package/dist/data/chat/Conversation.cjs.map +1 -0
- package/dist/data/chat/Conversation.d.ts +11 -0
- package/dist/data/chat/Conversation.d.ts.map +1 -0
- package/dist/data/chat/Conversation.js +34 -0
- package/dist/data/chat/Conversation.js.map +1 -0
- package/dist/data/chat/Message.cjs +44 -0
- package/dist/data/chat/Message.cjs.map +1 -0
- package/dist/data/chat/Message.d.ts +10 -0
- package/dist/data/chat/Message.d.ts.map +1 -0
- package/dist/data/chat/Message.js +44 -0
- package/dist/data/chat/Message.js.map +1 -0
- package/dist/data/chat/PromptInput.cjs +61 -0
- package/dist/data/chat/PromptInput.cjs.map +1 -0
- package/dist/data/chat/PromptInput.d.ts +16 -0
- package/dist/data/chat/PromptInput.d.ts.map +1 -0
- package/dist/data/chat/PromptInput.js +61 -0
- package/dist/data/chat/PromptInput.js.map +1 -0
- package/dist/data/chat/ToolCall.cjs +92 -0
- package/dist/data/chat/ToolCall.cjs.map +1 -0
- package/dist/data/chat/ToolCall.d.ts +14 -0
- package/dist/data/chat/ToolCall.d.ts.map +1 -0
- package/dist/data/chat/ToolCall.js +92 -0
- package/dist/data/chat/ToolCall.js.map +1 -0
- package/dist/data/chat/clickyOperationsToTools.cjs +73 -0
- package/dist/data/chat/clickyOperationsToTools.cjs.map +1 -0
- package/dist/data/chat/clickyOperationsToTools.d.ts +10 -0
- package/dist/data/chat/clickyOperationsToTools.d.ts.map +1 -0
- package/dist/data/chat/clickyOperationsToTools.js +73 -0
- package/dist/data/chat/clickyOperationsToTools.js.map +1 -0
- package/dist/data/chat/index.d.ts +8 -0
- package/dist/data/chat/index.d.ts.map +1 -0
- package/dist/data/chat/types.cjs +18 -0
- package/dist/data/chat/types.cjs.map +1 -0
- package/dist/data/chat/types.d.ts +41 -0
- package/dist/data/chat/types.d.ts.map +1 -0
- package/dist/data/chat/types.js +18 -0
- package/dist/data/chat/types.js.map +1 -0
- package/dist/data/data-table-utils.cjs +55 -0
- package/dist/data/data-table-utils.cjs.map +1 -0
- package/dist/data/data-table-utils.d.ts +24 -0
- package/dist/data/data-table-utils.d.ts.map +1 -0
- package/dist/data/data-table-utils.js +55 -0
- package/dist/data/data-table-utils.js.map +1 -0
- package/dist/data/diagnostics/DiagnosticsDetailPanel.cjs +2 -1
- package/dist/data/diagnostics/DiagnosticsDetailPanel.cjs.map +1 -1
- package/dist/data/diagnostics/DiagnosticsDetailPanel.d.ts.map +1 -1
- package/dist/data/diagnostics/DiagnosticsDetailPanel.js +3 -2
- package/dist/data/diagnostics/DiagnosticsDetailPanel.js.map +1 -1
- package/dist/data/diagnostics/GoroutineCard.cjs +3 -22
- package/dist/data/diagnostics/GoroutineCard.cjs.map +1 -1
- package/dist/data/diagnostics/GoroutineCard.d.ts +0 -2
- package/dist/data/diagnostics/GoroutineCard.d.ts.map +1 -1
- package/dist/data/diagnostics/GoroutineCard.js +2 -21
- package/dist/data/diagnostics/GoroutineCard.js.map +1 -1
- package/dist/data/diagnostics/ThreadCard.cjs +3 -38
- package/dist/data/diagnostics/ThreadCard.cjs.map +1 -1
- package/dist/data/diagnostics/ThreadCard.d.ts +0 -2
- package/dist/data/diagnostics/ThreadCard.d.ts.map +1 -1
- package/dist/data/diagnostics/ThreadCard.js +2 -37
- package/dist/data/diagnostics/ThreadCard.js.map +1 -1
- package/dist/data/diagnostics/state-styles.cjs +59 -0
- package/dist/data/diagnostics/state-styles.cjs.map +1 -0
- package/dist/data/diagnostics/state-styles.d.ts +5 -0
- package/dist/data/diagnostics/state-styles.d.ts.map +1 -0
- package/dist/data/diagnostics/state-styles.js +59 -0
- package/dist/data/diagnostics/state-styles.js.map +1 -0
- package/dist/data/logs-normalize.cjs +166 -0
- package/dist/data/logs-normalize.cjs.map +1 -0
- package/dist/data/logs-normalize.d.ts +16 -0
- package/dist/data/logs-normalize.d.ts.map +1 -0
- package/dist/data/logs-normalize.js +166 -0
- package/dist/data/logs-normalize.js.map +1 -0
- package/dist/data/task-status.cjs +19 -19
- package/dist/data/task-status.cjs.map +1 -1
- package/dist/data/task-status.js +19 -19
- package/dist/data/task-status.js.map +1 -1
- package/dist/data/version-info.cjs +3 -3
- package/dist/data/version-info.js +3 -3
- package/dist/data.cjs +43 -18
- package/dist/data.cjs.map +1 -1
- package/dist/data.d.ts +11 -5
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +30 -5
- package/dist/data.js.map +1 -1
- package/dist/hooks/density-provider.cjs +38 -0
- package/dist/hooks/density-provider.cjs.map +1 -0
- package/dist/hooks/density-provider.d.ts +20 -0
- package/dist/hooks/density-provider.d.ts.map +1 -0
- package/dist/hooks/density-provider.js +38 -0
- package/dist/hooks/density-provider.js.map +1 -0
- package/dist/hooks/theme-provider.cjs +43 -0
- package/dist/hooks/theme-provider.cjs.map +1 -0
- package/dist/hooks/theme-provider.d.ts +9 -0
- package/dist/hooks/theme-provider.d.ts.map +1 -0
- package/dist/hooks/theme-provider.js +43 -0
- package/dist/hooks/theme-provider.js.map +1 -0
- package/dist/hooks/use-density.cjs +8 -37
- package/dist/hooks/use-density.cjs.map +1 -1
- package/dist/hooks/use-density.d.ts +5 -20
- package/dist/hooks/use-density.d.ts.map +1 -1
- package/dist/hooks/use-density.js +9 -38
- package/dist/hooks/use-density.js.map +1 -1
- package/dist/hooks/use-theme.cjs +10 -43
- package/dist/hooks/use-theme.cjs.map +1 -1
- package/dist/hooks/use-theme.d.ts +6 -9
- package/dist/hooks/use-theme.d.ts.map +1 -1
- package/dist/hooks/use-theme.js +11 -44
- package/dist/hooks/use-theme.js.map +1 -1
- package/dist/hooks.cjs +5 -2
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.ts +4 -2
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +5 -2
- package/dist/hooks.js.map +1 -1
- package/dist/icons/changeIconAliases.cjs +13 -13
- package/dist/icons/changeIconAliases.cjs.map +1 -1
- package/dist/icons/changeIconAliases.d.ts.map +1 -1
- package/dist/icons/changeIconAliases.js +13 -13
- package/dist/icons/changeIconAliases.js.map +1 -1
- package/dist/index.cjs +78 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +61 -13
- package/dist/index.js.map +1 -1
- package/dist/overlay/DropdownMenu.cjs +2 -0
- package/dist/overlay/DropdownMenu.cjs.map +1 -1
- package/dist/overlay/DropdownMenu.d.ts +3 -1
- package/dist/overlay/DropdownMenu.d.ts.map +1 -1
- package/dist/overlay/DropdownMenu.js +2 -0
- package/dist/overlay/DropdownMenu.js.map +1 -1
- package/dist/overlay/Modal.cjs +38 -27
- package/dist/overlay/Modal.cjs.map +1 -1
- package/dist/overlay/Modal.d.ts +8 -2
- package/dist/overlay/Modal.d.ts.map +1 -1
- package/dist/overlay/Modal.js +38 -27
- package/dist/overlay/Modal.js.map +1 -1
- package/dist/overlay/modalStack.cjs +35 -0
- package/dist/overlay/modalStack.cjs.map +1 -0
- package/dist/overlay/modalStack.d.ts +13 -0
- package/dist/overlay/modalStack.d.ts.map +1 -0
- package/dist/overlay/modalStack.js +35 -0
- package/dist/overlay/modalStack.js.map +1 -0
- package/dist/rpc/AcceptPicker.cjs +2 -18
- package/dist/rpc/AcceptPicker.cjs.map +1 -1
- package/dist/rpc/AcceptPicker.d.ts +1 -41
- package/dist/rpc/AcceptPicker.d.ts.map +1 -1
- package/dist/rpc/AcceptPicker.js +2 -18
- package/dist/rpc/AcceptPicker.js.map +1 -1
- package/dist/rpc/CommandOutput.cjs +1 -1
- package/dist/rpc/CommandOutput.cjs.map +1 -1
- package/dist/rpc/CommandOutput.js +1 -1
- package/dist/rpc/CommandOutput.js.map +1 -1
- package/dist/rpc/EndpointList.cjs +1 -1
- package/dist/rpc/EndpointList.cjs.map +1 -1
- package/dist/rpc/EndpointList.js +1 -1
- package/dist/rpc/EndpointList.js.map +1 -1
- package/dist/rpc/FilterForm.cjs +4 -4
- package/dist/rpc/FilterForm.cjs.map +1 -1
- package/dist/rpc/FilterForm.js +4 -4
- package/dist/rpc/FilterForm.js.map +1 -1
- package/dist/rpc/OperationCatalog.cjs +38 -60
- package/dist/rpc/OperationCatalog.cjs.map +1 -1
- package/dist/rpc/OperationCatalog.d.ts +3 -3
- package/dist/rpc/OperationCatalog.d.ts.map +1 -1
- package/dist/rpc/OperationCatalog.js +40 -62
- package/dist/rpc/OperationCatalog.js.map +1 -1
- package/dist/rpc/OperationCommandPage.cjs.map +1 -1
- package/dist/rpc/OperationCommandPage.d.ts.map +1 -1
- package/dist/rpc/OperationCommandPage.js.map +1 -1
- package/dist/rpc/accept-options.cjs +20 -0
- package/dist/rpc/accept-options.cjs.map +1 -0
- package/dist/rpc/accept-options.d.ts +42 -0
- package/dist/rpc/accept-options.d.ts.map +1 -0
- package/dist/rpc/accept-options.js +20 -0
- package/dist/rpc/accept-options.js.map +1 -0
- package/dist/rpc/classify.cjs +15 -4
- package/dist/rpc/classify.cjs.map +1 -1
- package/dist/rpc/classify.d.ts.map +1 -1
- package/dist/rpc/classify.js +15 -4
- package/dist/rpc/classify.js.map +1 -1
- package/dist/rpc/clickyMetadata.cjs +13 -3
- package/dist/rpc/clickyMetadata.cjs.map +1 -1
- package/dist/rpc/clickyMetadata.d.ts +2 -0
- package/dist/rpc/clickyMetadata.d.ts.map +1 -1
- package/dist/rpc/clickyMetadata.js +14 -4
- package/dist/rpc/clickyMetadata.js.map +1 -1
- package/dist/rpc/formMetadata.cjs +5 -3
- package/dist/rpc/formMetadata.cjs.map +1 -1
- package/dist/rpc/formMetadata.d.ts.map +1 -1
- package/dist/rpc/formMetadata.js +5 -3
- package/dist/rpc/formMetadata.js.map +1 -1
- package/dist/rpc.cjs +3 -2
- package/dist/rpc.cjs.map +1 -1
- package/dist/rpc.d.ts +2 -1
- package/dist/rpc.d.ts.map +1 -1
- package/dist/rpc.js +2 -1
- package/dist/rpc.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +16 -1
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useRef, useLayoutEffect, useEffect } from "react";
|
|
3
|
+
import { createPortal } from "react-dom";
|
|
4
|
+
import { cn } from "../lib/utils.js";
|
|
5
|
+
import { Icon } from "../data/Icon.js";
|
|
6
|
+
import { Tree } from "../data/Tree.js";
|
|
7
|
+
import { inputSizeClass } from "./json-schema-form-size.js";
|
|
8
|
+
import { UiChevronDown } from "../icons/components/UiChevronDown.js";
|
|
9
|
+
const PANEL_MAX_WIDTH_PX = 480;
|
|
10
|
+
function TreePickerField({
|
|
11
|
+
roots,
|
|
12
|
+
getKey,
|
|
13
|
+
getChildren,
|
|
14
|
+
renderRow,
|
|
15
|
+
getSearchText,
|
|
16
|
+
defaultOpen,
|
|
17
|
+
isSelectable,
|
|
18
|
+
onSelect,
|
|
19
|
+
label,
|
|
20
|
+
placeholder = "Select…",
|
|
21
|
+
disabled,
|
|
22
|
+
size,
|
|
23
|
+
className,
|
|
24
|
+
triggerClassName,
|
|
25
|
+
panelClassName
|
|
26
|
+
}) {
|
|
27
|
+
const [open, setOpen] = useState(false);
|
|
28
|
+
const [pos, setPos] = useState(
|
|
29
|
+
null
|
|
30
|
+
);
|
|
31
|
+
const rootRef = useRef(null);
|
|
32
|
+
const anchorRef = useRef(null);
|
|
33
|
+
const panelRef = useRef(null);
|
|
34
|
+
useLayoutEffect(() => {
|
|
35
|
+
if (!open) {
|
|
36
|
+
setPos(null);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const update = () => {
|
|
40
|
+
const anchor = anchorRef.current;
|
|
41
|
+
if (!anchor) return;
|
|
42
|
+
const rect = anchor.getBoundingClientRect();
|
|
43
|
+
const viewportCap = window.innerWidth - rect.left - 8;
|
|
44
|
+
const maxWidth = Math.max(rect.width, Math.min(PANEL_MAX_WIDTH_PX, viewportCap));
|
|
45
|
+
setPos({ top: rect.bottom + 4, left: rect.left, width: rect.width, maxWidth });
|
|
46
|
+
};
|
|
47
|
+
update();
|
|
48
|
+
window.addEventListener("scroll", update, true);
|
|
49
|
+
window.addEventListener("resize", update);
|
|
50
|
+
return () => {
|
|
51
|
+
window.removeEventListener("scroll", update, true);
|
|
52
|
+
window.removeEventListener("resize", update);
|
|
53
|
+
};
|
|
54
|
+
}, [open]);
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (!open) return;
|
|
57
|
+
const onPointerDown = (e) => {
|
|
58
|
+
var _a, _b;
|
|
59
|
+
const target = e.target;
|
|
60
|
+
if (!((_a = rootRef.current) == null ? void 0 : _a.contains(target)) && !((_b = panelRef.current) == null ? void 0 : _b.contains(target))) {
|
|
61
|
+
setOpen(false);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
document.addEventListener("mousedown", onPointerDown);
|
|
65
|
+
return () => document.removeEventListener("mousedown", onPointerDown);
|
|
66
|
+
}, [open]);
|
|
67
|
+
return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: cn("relative", className), children: [
|
|
68
|
+
/* @__PURE__ */ jsxs(
|
|
69
|
+
"button",
|
|
70
|
+
{
|
|
71
|
+
ref: anchorRef,
|
|
72
|
+
type: "button",
|
|
73
|
+
disabled,
|
|
74
|
+
"aria-haspopup": "tree",
|
|
75
|
+
"aria-expanded": open,
|
|
76
|
+
onClick: () => setOpen((o) => !o),
|
|
77
|
+
className: cn(
|
|
78
|
+
"relative flex w-full items-center rounded-md border border-input bg-background text-left text-foreground",
|
|
79
|
+
size ? inputSizeClass[size] : "h-control-h px-control-px text-sm",
|
|
80
|
+
"pr-8",
|
|
81
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
|
|
82
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
83
|
+
triggerClassName
|
|
84
|
+
),
|
|
85
|
+
children: [
|
|
86
|
+
/* @__PURE__ */ jsx("span", { className: cn("min-w-0 flex-1 truncate", label == null && "text-muted-foreground"), children: label ?? placeholder }),
|
|
87
|
+
/* @__PURE__ */ jsx("span", { className: "pointer-events-none absolute right-0 flex h-full items-center px-2 text-muted-foreground", children: /* @__PURE__ */ jsx(Icon, { icon: UiChevronDown, className: "text-xs" }) })
|
|
88
|
+
]
|
|
89
|
+
}
|
|
90
|
+
),
|
|
91
|
+
open && pos && createPortal(
|
|
92
|
+
/* @__PURE__ */ jsx(
|
|
93
|
+
"div",
|
|
94
|
+
{
|
|
95
|
+
ref: panelRef,
|
|
96
|
+
"data-slot": "tree-picker-popup",
|
|
97
|
+
style: {
|
|
98
|
+
position: "fixed",
|
|
99
|
+
top: pos.top,
|
|
100
|
+
left: pos.left,
|
|
101
|
+
width: pos.width,
|
|
102
|
+
maxWidth: pos.maxWidth
|
|
103
|
+
},
|
|
104
|
+
className: cn(
|
|
105
|
+
"z-50 flex max-h-[60vh] flex-col overflow-hidden rounded-md border border-border bg-popover shadow-md",
|
|
106
|
+
panelClassName
|
|
107
|
+
),
|
|
108
|
+
onKeyDown: (e) => {
|
|
109
|
+
if (e.key === "Escape") setOpen(false);
|
|
110
|
+
},
|
|
111
|
+
children: /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-auto", children: /* @__PURE__ */ jsx(
|
|
112
|
+
Tree,
|
|
113
|
+
{
|
|
114
|
+
roots,
|
|
115
|
+
getKey,
|
|
116
|
+
getChildren,
|
|
117
|
+
renderRow,
|
|
118
|
+
...getSearchText ? { getSearchText } : {},
|
|
119
|
+
...defaultOpen ? { defaultOpen } : {},
|
|
120
|
+
onSelect: (node) => {
|
|
121
|
+
if (!isSelectable || isSelectable(node)) {
|
|
122
|
+
onSelect(node);
|
|
123
|
+
setOpen(false);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
) })
|
|
128
|
+
}
|
|
129
|
+
),
|
|
130
|
+
document.body
|
|
131
|
+
)
|
|
132
|
+
] });
|
|
133
|
+
}
|
|
134
|
+
export {
|
|
135
|
+
TreePickerField
|
|
136
|
+
};
|
|
137
|
+
//# sourceMappingURL=TreePickerField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TreePickerField.js","sources":["../../src/components/TreePickerField.tsx"],"sourcesContent":["import { useEffect, useLayoutEffect, useRef, useState, type ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"../data/Icon\";\nimport { UiChevronDown } from \"../icons\";\nimport { Tree, type TreeProps } from \"../data/Tree\";\nimport { inputSizeClass, type FormSize } from \"./json-schema-form-size\";\n\n// Upper bound the open panel grows to so wide trees show full labels before\n// truncating; the panel is never narrower than the trigger.\nconst PANEL_MAX_WIDTH_PX = 480;\n\nexport interface TreePickerFieldProps<T> {\n /** Root nodes of the tree to browse. */\n roots: T[];\n getKey: (node: T) => string | number;\n getChildren: (node: T) => T[] | undefined;\n renderRow: TreeProps<T>[\"renderRow\"];\n getSearchText?: (node: T) => string;\n defaultOpen?: (node: T, depth: number) => boolean;\n /**\n * Decides which nodes commit a selection when clicked. A click on a\n * non-selectable node still toggles its expansion (it never closes the\n * picker). Defaults to every node selectable.\n */\n isSelectable?: (node: T) => boolean;\n /** Fires for a selectable node, then closes the dropdown. */\n onSelect: (node: T) => void;\n /** Current-selection display in the trigger; falls back to `placeholder`. */\n label?: ReactNode;\n placeholder?: string;\n disabled?: boolean;\n size?: FormSize;\n className?: string;\n triggerClassName?: string;\n panelClassName?: string;\n}\n\n// TreePickerField is a form-field-styled trigger (matching Combobox's closed\n// input) that opens a portal-anchored dropdown holding a Tree. The dropdown is\n// positioned with fixed coordinates measured from the trigger so it escapes any\n// overflow-hidden / scroll ancestor (e.g. a modal body). A click on a selectable\n// node commits and closes; a non-selectable node only toggles expansion.\nexport function TreePickerField<T>({\n roots,\n getKey,\n getChildren,\n renderRow,\n getSearchText,\n defaultOpen,\n isSelectable,\n onSelect,\n label,\n placeholder = \"Select…\",\n disabled,\n size,\n className,\n triggerClassName,\n panelClassName,\n}: TreePickerFieldProps<T>) {\n const [open, setOpen] = useState(false);\n const [pos, setPos] = useState<{ top: number; left: number; width: number; maxWidth: number } | null>(\n null,\n );\n const rootRef = useRef<HTMLDivElement>(null);\n const anchorRef = useRef<HTMLButtonElement>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n\n // Position the portaled panel from the trigger rect, repositioning while open.\n useLayoutEffect(() => {\n if (!open) {\n setPos(null);\n return;\n }\n const update = () => {\n const anchor = anchorRef.current;\n if (!anchor) return;\n const rect = anchor.getBoundingClientRect();\n const viewportCap = window.innerWidth - rect.left - 8;\n const maxWidth = Math.max(rect.width, Math.min(PANEL_MAX_WIDTH_PX, viewportCap));\n setPos({ top: rect.bottom + 4, left: rect.left, width: rect.width, maxWidth });\n };\n update();\n window.addEventListener(\"scroll\", update, true);\n window.addEventListener(\"resize\", update);\n return () => {\n window.removeEventListener(\"scroll\", update, true);\n window.removeEventListener(\"resize\", update);\n };\n }, [open]);\n\n // Dismiss on an outside pointer-down (the trigger and panel are exempt).\n useEffect(() => {\n if (!open) return;\n const onPointerDown = (e: MouseEvent) => {\n const target = e.target as Node;\n if (!rootRef.current?.contains(target) && !panelRef.current?.contains(target)) {\n setOpen(false);\n }\n };\n document.addEventListener(\"mousedown\", onPointerDown);\n return () => document.removeEventListener(\"mousedown\", onPointerDown);\n }, [open]);\n\n return (\n <div ref={rootRef} className={cn(\"relative\", className)}>\n <button\n ref={anchorRef}\n type=\"button\"\n disabled={disabled}\n aria-haspopup=\"tree\"\n aria-expanded={open}\n onClick={() => setOpen((o) => !o)}\n className={cn(\n \"relative flex w-full items-center rounded-md border border-input bg-background text-left text-foreground\",\n size ? inputSizeClass[size] : \"h-control-h px-control-px text-sm\",\n \"pr-8\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\",\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n triggerClassName,\n )}\n >\n <span className={cn(\"min-w-0 flex-1 truncate\", label == null && \"text-muted-foreground\")}>\n {label ?? placeholder}\n </span>\n <span className=\"pointer-events-none absolute right-0 flex h-full items-center px-2 text-muted-foreground\">\n <Icon icon={UiChevronDown} className=\"text-xs\" />\n </span>\n </button>\n\n {open &&\n pos &&\n createPortal(\n <div\n ref={panelRef}\n data-slot=\"tree-picker-popup\"\n style={{\n position: \"fixed\",\n top: pos.top,\n left: pos.left,\n width: pos.width,\n maxWidth: pos.maxWidth,\n }}\n className={cn(\n \"z-50 flex max-h-[60vh] flex-col overflow-hidden rounded-md border border-border bg-popover shadow-md\",\n panelClassName,\n )}\n onKeyDown={(e) => {\n if (e.key === \"Escape\") setOpen(false);\n }}\n >\n <div className=\"min-h-0 flex-1 overflow-auto\">\n <Tree<T>\n roots={roots}\n getKey={getKey}\n getChildren={getChildren}\n renderRow={renderRow}\n {...(getSearchText ? { getSearchText } : {})}\n {...(defaultOpen ? { defaultOpen } : {})}\n onSelect={(node) => {\n if (!isSelectable || isSelectable(node)) {\n onSelect(node);\n setOpen(false);\n }\n }}\n />\n </div>\n </div>,\n document.body,\n )}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -2,22 +2,15 @@
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const jsxRuntime = require("react/jsx-runtime");
|
|
4
4
|
const react = require("react");
|
|
5
|
-
const mi = require("@flanksource/icons/mi");
|
|
6
5
|
const utils = require("../lib/utils.cjs");
|
|
7
6
|
const Combobox = require("./Combobox.cjs");
|
|
8
|
-
const
|
|
9
|
-
service: { label: "Service", Icon: mi.K8SService },
|
|
10
|
-
ingress: { label: "Ingress", Icon: mi.K8SIngress },
|
|
11
|
-
deployment: { label: "Deployment", Icon: mi.K8SDeployment },
|
|
12
|
-
statefulset: { label: "StatefulSet", Icon: mi.K8SStatefulset }
|
|
13
|
-
};
|
|
14
|
-
const ALL_KINDS = ["service", "ingress", "deployment", "statefulset"];
|
|
7
|
+
const workloadPickerUtils = require("./workload-picker-utils.cjs");
|
|
15
8
|
function WorkloadPicker({
|
|
16
9
|
value,
|
|
17
10
|
onChange,
|
|
18
11
|
loadWorkloads,
|
|
19
12
|
namespace,
|
|
20
|
-
kinds =
|
|
13
|
+
kinds = workloadPickerUtils.ALL_WORKLOAD_KINDS,
|
|
21
14
|
strict = false,
|
|
22
15
|
placeholder = "Select workload / service…",
|
|
23
16
|
className
|
|
@@ -38,16 +31,16 @@ function WorkloadPicker({
|
|
|
38
31
|
};
|
|
39
32
|
}, [loadWorkloads, kindsKey]);
|
|
40
33
|
const options = react.useMemo(
|
|
41
|
-
() => buildWorkloadOptions(namespace, byKind, kinds, value),
|
|
34
|
+
() => workloadPickerUtils.buildWorkloadOptions(namespace, byKind, kinds, value),
|
|
42
35
|
[namespace, byKind, kinds, value]
|
|
43
36
|
);
|
|
44
37
|
const invalid = react.useMemo(() => {
|
|
45
38
|
if (!strict || !value || loading) return false;
|
|
46
|
-
const { keys, names } = loadedWorkloads(namespace, byKind, kinds);
|
|
39
|
+
const { keys, names } = workloadPickerUtils.loadedWorkloads(namespace, byKind, kinds);
|
|
47
40
|
return !keys.has(value) && !names.has(value);
|
|
48
41
|
}, [strict, value, loading, namespace, byKind, kinds]);
|
|
49
|
-
const selectedKind = kindForValue(kinds, value);
|
|
50
|
-
const leadMeta = WORKLOAD_META[selectedKind];
|
|
42
|
+
const selectedKind = workloadPickerUtils.kindForValue(kinds, value);
|
|
43
|
+
const leadMeta = workloadPickerUtils.WORKLOAD_META[selectedKind];
|
|
51
44
|
const LeadIcon = leadMeta.Icon;
|
|
52
45
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils.cn("flex items-center gap-2", className), children: [
|
|
53
46
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -72,73 +65,5 @@ function WorkloadPicker({
|
|
|
72
65
|
) })
|
|
73
66
|
] });
|
|
74
67
|
}
|
|
75
|
-
function ingressHost(kind, r) {
|
|
76
|
-
var _a;
|
|
77
|
-
return kind === "ingress" ? (_a = r.hosts) == null ? void 0 : _a[0] : void 0;
|
|
78
|
-
}
|
|
79
|
-
function workloadName(kind, r) {
|
|
80
|
-
return ingressHost(kind, r) ?? r.name;
|
|
81
|
-
}
|
|
82
|
-
const KNOWN_KINDS = /* @__PURE__ */ new Set(["service", "ingress", "deployment", "statefulset"]);
|
|
83
|
-
function workloadKey(namespace, kind, r) {
|
|
84
|
-
const name = workloadName(kind, r);
|
|
85
|
-
return namespace ? `${namespace}/${kind}/${name}` : `${kind}/${name}`;
|
|
86
|
-
}
|
|
87
|
-
function parseWorkloadKey(value) {
|
|
88
|
-
const parts = value.split("/");
|
|
89
|
-
const name = parts.at(-1);
|
|
90
|
-
const maybeKind = parts.at(-2);
|
|
91
|
-
if (name != null && maybeKind != null && KNOWN_KINDS.has(maybeKind)) {
|
|
92
|
-
const namespace = parts.slice(0, -2).join("/");
|
|
93
|
-
const parsed = { kind: maybeKind, name };
|
|
94
|
-
if (namespace) parsed.namespace = namespace;
|
|
95
|
-
return parsed;
|
|
96
|
-
}
|
|
97
|
-
return { name: value };
|
|
98
|
-
}
|
|
99
|
-
function loadedWorkloads(namespace, byKind, kinds) {
|
|
100
|
-
const keys = /* @__PURE__ */ new Set();
|
|
101
|
-
const names = /* @__PURE__ */ new Set();
|
|
102
|
-
for (const kind of kinds) {
|
|
103
|
-
for (const r of byKind[kind] ?? []) {
|
|
104
|
-
keys.add(workloadKey(namespace, kind, r));
|
|
105
|
-
names.add(workloadName(kind, r));
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return { keys, names };
|
|
109
|
-
}
|
|
110
|
-
function kindForValue(kinds, value) {
|
|
111
|
-
const kind = value ? parseWorkloadKey(value).kind : void 0;
|
|
112
|
-
return kind ?? kinds[0] ?? "service";
|
|
113
|
-
}
|
|
114
|
-
function buildWorkloadOptions(namespace, byKind, kinds, value) {
|
|
115
|
-
const opts = [];
|
|
116
|
-
for (const kind of kinds) {
|
|
117
|
-
const meta = WORKLOAD_META[kind];
|
|
118
|
-
const Icon = meta.Icon;
|
|
119
|
-
for (const r of byKind[kind] ?? []) {
|
|
120
|
-
const host = ingressHost(kind, r);
|
|
121
|
-
opts.push({
|
|
122
|
-
value: workloadKey(namespace, kind, r),
|
|
123
|
-
// The label is the human name; an ingress pairs its host with the
|
|
124
|
-
// ingress name for context.
|
|
125
|
-
label: host ? `${host} (${r.name})` : r.name,
|
|
126
|
-
group: meta.label,
|
|
127
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-4 w-4" })
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
if (value && !opts.some((o) => o.value === value)) {
|
|
132
|
-
const parsed = parseWorkloadKey(value);
|
|
133
|
-
const Icon = WORKLOAD_META[parsed.kind ?? kinds[0] ?? "service"].Icon;
|
|
134
|
-
return [{ value, label: parsed.name, icon: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-4 w-4" }) }, ...opts];
|
|
135
|
-
}
|
|
136
|
-
return opts;
|
|
137
|
-
}
|
|
138
68
|
exports.WorkloadPicker = WorkloadPicker;
|
|
139
|
-
exports.buildWorkloadOptions = buildWorkloadOptions;
|
|
140
|
-
exports.kindForValue = kindForValue;
|
|
141
|
-
exports.loadedWorkloads = loadedWorkloads;
|
|
142
|
-
exports.parseWorkloadKey = parseWorkloadKey;
|
|
143
|
-
exports.workloadKey = workloadKey;
|
|
144
69
|
//# sourceMappingURL=WorkloadPicker.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkloadPicker.cjs","sources":["../../src/components/WorkloadPicker.tsx"],"sourcesContent":["import { useEffect, useMemo, useState, type ComponentType } from \"react\";\nimport {\n K8SService,\n K8SIngress,\n K8SDeployment,\n K8SStatefulset,\n} from \"@flanksource/icons/mi\";\nimport { cn } from \"../lib/utils\";\nimport { Combobox, type ComboboxOption } from \"./Combobox\";\n\n// WorkloadPicker selects a backing Kubernetes workload (Service / Ingress /\n// Deployment / StatefulSet) for an endpoint. Options from every kind are merged\n// into one Combobox, grouped by kind via the Combobox group-header support and\n// labelled with the kind's icon.\n//\n// The emitted value is a `[namespace/]kind/name` key (see workloadKey /\n// parseWorkloadKey) so two workloads of different kinds that share a name don't\n// collide. An ingress's name-part is its first host (the routable address),\n// labelled with the ingress name for context; every other kind uses its name.\n//\n// The component is presentational: it owns the kind→group/icon mapping and the\n// key encoding but fetches nothing — the consumer supplies an async\n// `loadWorkloads` getter.\n\nexport type WorkloadKind = \"service\" | \"ingress\" | \"deployment\" | \"statefulset\";\n\n/** One workload returned by the loader. Ingresses may carry rule hostnames. */\nexport type WorkloadResource = { name: string; hosts?: string[] };\n\ntype KindIconProps = { className?: string; title?: string; \"aria-label\"?: string };\ntype KindMeta = { label: string; Icon: ComponentType<KindIconProps> };\n\n// WORKLOAD_META maps each kind to its group header label and icon, in display\n// order. The order of the keys drives the order options/groups appear in.\nconst WORKLOAD_META: Record<WorkloadKind, KindMeta> = {\n service: { label: \"Service\", Icon: K8SService },\n ingress: { label: \"Ingress\", Icon: K8SIngress },\n deployment: { label: \"Deployment\", Icon: K8SDeployment },\n statefulset: { label: \"StatefulSet\", Icon: K8SStatefulset },\n};\n\nconst ALL_KINDS: WorkloadKind[] = [\"service\", \"ingress\", \"deployment\", \"statefulset\"];\n\nexport type WorkloadPickerProps = {\n /**\n * Controlled selected value — a `[namespace/]kind/name` key (see\n * {@link workloadKey} / {@link parseWorkloadKey}).\n */\n value: string;\n /** Called with the chosen `[namespace/]kind/name` key (or \"\" when cleared). */\n onChange: (value: string) => void;\n /**\n * Async getter the component calls to load the requested kinds' workloads.\n * Returns a map keyed by kind. The consumer owns fetching/caching.\n */\n loadWorkloads: (kinds: WorkloadKind[]) => Promise<Record<WorkloadKind, WorkloadResource[]>>;\n /**\n * Namespace the workloads live in. When set it prefixes the emitted key\n * (`namespace/kind/name`), so values stay distinct across namespaces.\n */\n namespace?: string;\n /** Kinds to offer, in display order. Defaults to all four. */\n kinds?: WorkloadKind[];\n /**\n * When true, a non-empty value that does not match any loaded workload (once\n * loading settles) is flagged invalid — the picked workload doesn't exist in\n * the namespace. The value is still shown (pinned) so the user can see and\n * fix it; freeform entry is not rejected, only marked.\n */\n strict?: boolean;\n placeholder?: string;\n className?: string;\n};\n\nexport function WorkloadPicker({\n value,\n onChange,\n loadWorkloads,\n namespace,\n kinds = ALL_KINDS,\n strict = false,\n placeholder = \"Select workload / service…\",\n className,\n}: WorkloadPickerProps) {\n const [byKind, setByKind] = useState<Partial<Record<WorkloadKind, WorkloadResource[]>>>({});\n const [loading, setLoading] = useState(false);\n\n const kindsKey = kinds.join(\",\");\n useEffect(() => {\n let cancelled = false;\n setLoading(true);\n loadWorkloads(kinds)\n .then((res) => {\n if (!cancelled) setByKind(res);\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n return () => {\n cancelled = true;\n };\n // loadWorkloads is expected to be stable (memoized by the consumer); kindsKey\n // is the joined `kinds` so a changed selection reloads without depending on\n // the array's identity.\n }, [loadWorkloads, kindsKey]);\n\n const options = useMemo(\n () => buildWorkloadOptions(namespace, byKind, kinds, value),\n [namespace, byKind, kinds, value],\n );\n\n // In strict mode a non-empty value is invalid once loading settles unless it\n // matches a loaded workload — either by its full `[namespace/]kind/name` key\n // (what the picker emits) or by its bare name-part (what consumers that\n // persist only the resolved name, e.g. a Service name or ingress host, feed\n // back in). buildWorkloadOptions pins an unmatched value first, so test\n // membership against the loaded set, not `options`.\n const invalid = useMemo(() => {\n if (!strict || !value || loading) return false;\n const { keys, names } = loadedWorkloads(namespace, byKind, kinds);\n return !keys.has(value) && !names.has(value);\n }, [strict, value, loading, namespace, byKind, kinds]);\n\n // The lead icon reflects the selected workload's kind (read from the value's\n // key), falling back to the first offered kind when nothing is selected or the\n // value carries no recognised kind (e.g. freeform input).\n const selectedKind = kindForValue(kinds, value);\n const leadMeta = WORKLOAD_META[selectedKind];\n const LeadIcon = leadMeta.Icon;\n return (\n <div className={cn(\"flex items-center gap-2\", className)}>\n <LeadIcon\n className=\"h-4 w-4 shrink-0 text-muted-foreground\"\n title={leadMeta.label}\n aria-label={leadMeta.label}\n />\n <div className=\"min-w-0 flex-1\">\n <Combobox\n options={options}\n value={value}\n onChange={onChange}\n allowCustomValue\n loading={loading}\n invalid={invalid}\n placeholder={placeholder}\n />\n </div>\n </div>\n );\n}\n\n// ingressHost is the first host an ingress routes, or undefined for non-ingress\n// kinds and host-less ingresses. An ingress's name-part is its host.\nfunction ingressHost(kind: WorkloadKind, r: WorkloadResource): string | undefined {\n return kind === \"ingress\" ? r.hosts?.[0] : undefined;\n}\n\n// workloadName is the name-part of a resource's key: an ingress's first host\n// (the routable address callers want), else the resource's own name.\nfunction workloadName(kind: WorkloadKind, r: WorkloadResource): string {\n return ingressHost(kind, r) ?? r.name;\n}\n\n// ParsedWorkloadKey is the structured form of a `[namespace/]kind/name` value.\nexport type ParsedWorkloadKey = { namespace?: string; kind?: WorkloadKind; name: string };\n\nconst KNOWN_KINDS = new Set<string>([\"service\", \"ingress\", \"deployment\", \"statefulset\"]);\n\n// workloadKey is the value a resource contributes (what onChange emits): a\n// `[namespace/]kind/name` composite so two workloads of different kinds sharing\n// a name don't collide. namespace is omitted when not supplied.\nexport function workloadKey(\n namespace: string | undefined,\n kind: WorkloadKind,\n r: WorkloadResource,\n): string {\n const name = workloadName(kind, r);\n return namespace ? `${namespace}/${kind}/${name}` : `${kind}/${name}`;\n}\n\n// parseWorkloadKey splits a `[namespace/]kind/name` value back into its parts.\n// The trailing segment is always the name (a host may itself contain no slash);\n// the segment before it is the kind when it is a known workload kind, and any\n// remaining leading segment is the namespace. A bare value (no recognised\n// kind/name shape) is returned as just its name so freeform input survives.\nexport function parseWorkloadKey(value: string): ParsedWorkloadKey {\n const parts = value.split(\"/\");\n const name = parts.at(-1);\n const maybeKind = parts.at(-2);\n if (name != null && maybeKind != null && KNOWN_KINDS.has(maybeKind)) {\n const namespace = parts.slice(0, -2).join(\"/\");\n const parsed: ParsedWorkloadKey = { kind: maybeKind as WorkloadKind, name };\n if (namespace) parsed.namespace = namespace;\n return parsed;\n }\n return { name: value };\n}\n\n// loadedWorkloads collapses the loaded resources into the two membership sets a\n// strict picker validates a value against: `keys` are the full\n// `[namespace/]kind/name` keys the picker emits, `names` are the bare name-parts\n// (service name / ingress host) a consumer may persist instead. A value in\n// neither set names a workload that doesn't exist in the namespace.\nexport function loadedWorkloads(\n namespace: string | undefined,\n byKind: Partial<Record<WorkloadKind, WorkloadResource[]>>,\n kinds: WorkloadKind[],\n): { keys: Set<string>; names: Set<string> } {\n const keys = new Set<string>();\n const names = new Set<string>();\n for (const kind of kinds) {\n for (const r of byKind[kind] ?? []) {\n keys.add(workloadKey(namespace, kind, r));\n names.add(workloadName(kind, r));\n }\n }\n return { keys, names };\n}\n\n// kindForValue returns the kind encoded in the selected value, so the lead icon\n// can mirror it without consulting the loaded resources. Falls back to the first\n// offered kind when nothing is selected or the value carries no recognised kind.\nexport function kindForValue(kinds: WorkloadKind[], value: string): WorkloadKind {\n const kind = value ? parseWorkloadKey(value).kind : undefined;\n return kind ?? kinds[0] ?? \"service\";\n}\n\n// buildWorkloadOptions flattens the per-kind resources into grouped Combobox\n// options in kind order. Each option's value is its `[namespace/]kind/name` key\n// and its label the human name; a current value not present in any kind is\n// pinned first (labelled with just its name-part) so the selection stays visible.\nexport function buildWorkloadOptions(\n namespace: string | undefined,\n byKind: Partial<Record<WorkloadKind, WorkloadResource[]>>,\n kinds: WorkloadKind[],\n value: string,\n): ComboboxOption[] {\n const opts: ComboboxOption[] = [];\n for (const kind of kinds) {\n const meta = WORKLOAD_META[kind];\n const Icon = meta.Icon;\n for (const r of byKind[kind] ?? []) {\n const host = ingressHost(kind, r);\n opts.push({\n value: workloadKey(namespace, kind, r),\n // The label is the human name; an ingress pairs its host with the\n // ingress name for context.\n label: host ? `${host} (${r.name})` : r.name,\n group: meta.label,\n icon: <Icon className=\"h-4 w-4\" />,\n });\n }\n }\n if (value && !opts.some((o) => o.value === value)) {\n const parsed = parseWorkloadKey(value);\n const Icon = WORKLOAD_META[parsed.kind ?? kinds[0] ?? \"service\"].Icon;\n return [{ value, label: parsed.name, icon: <Icon className=\"h-4 w-4\" /> }, ...opts];\n }\n return opts;\n}\n"],"names":["K8SService","K8SIngress","K8SDeployment","K8SStatefulset","useState","useEffect","useMemo","cn","jsx","Combobox"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WorkloadPicker.cjs","sources":["../../src/components/WorkloadPicker.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Combobox } from \"./Combobox\";\nimport {\n ALL_WORKLOAD_KINDS,\n WORKLOAD_META,\n buildWorkloadOptions,\n kindForValue,\n loadedWorkloads,\n type WorkloadKind,\n type WorkloadResource,\n} from \"./workload-picker-utils\";\n\n// WorkloadPicker selects a backing Kubernetes workload (Service / Ingress /\n// Deployment / StatefulSet) for an endpoint. Options from every kind are merged\n// into one Combobox, grouped by kind via the Combobox group-header support and\n// labelled with the kind's icon.\n//\n// The emitted value is a `[namespace/]kind/name` key (see workloadKey /\n// parseWorkloadKey in workload-picker-utils) so two workloads of different\n// kinds that share a name don't collide. An ingress's name-part is its first\n// host (the routable address), labelled with the ingress name for context;\n// every other kind uses its name.\n//\n// The component is presentational: the kind→group/icon mapping and the key\n// encoding live in workload-picker-utils; it fetches nothing — the consumer\n// supplies an async `loadWorkloads` getter.\n\nexport type WorkloadPickerProps = {\n /**\n * Controlled selected value — a `[namespace/]kind/name` key (see\n * {@link workloadKey} / {@link parseWorkloadKey}).\n */\n value: string;\n /** Called with the chosen `[namespace/]kind/name` key (or \"\" when cleared). */\n onChange: (value: string) => void;\n /**\n * Async getter the component calls to load the requested kinds' workloads.\n * Returns a map keyed by kind. The consumer owns fetching/caching.\n */\n loadWorkloads: (kinds: WorkloadKind[]) => Promise<Record<WorkloadKind, WorkloadResource[]>>;\n /**\n * Namespace the workloads live in. When set it prefixes the emitted key\n * (`namespace/kind/name`), so values stay distinct across namespaces.\n */\n namespace?: string;\n /** Kinds to offer, in display order. Defaults to all four. */\n kinds?: WorkloadKind[];\n /**\n * When true, a non-empty value that does not match any loaded workload (once\n * loading settles) is flagged invalid — the picked workload doesn't exist in\n * the namespace. The value is still shown (pinned) so the user can see and\n * fix it; freeform entry is not rejected, only marked.\n */\n strict?: boolean;\n placeholder?: string;\n className?: string;\n};\n\nexport function WorkloadPicker({\n value,\n onChange,\n loadWorkloads,\n namespace,\n kinds = ALL_WORKLOAD_KINDS,\n strict = false,\n placeholder = \"Select workload / service…\",\n className,\n}: WorkloadPickerProps) {\n const [byKind, setByKind] = useState<Partial<Record<WorkloadKind, WorkloadResource[]>>>({});\n const [loading, setLoading] = useState(false);\n\n const kindsKey = kinds.join(\",\");\n useEffect(() => {\n let cancelled = false;\n setLoading(true);\n loadWorkloads(kinds)\n .then((res) => {\n if (!cancelled) setByKind(res);\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n return () => {\n cancelled = true;\n };\n // loadWorkloads is expected to be stable (memoized by the consumer); kindsKey\n // is the joined `kinds` so a changed selection reloads without depending on\n // the array's identity.\n }, [loadWorkloads, kindsKey]);\n\n const options = useMemo(\n () => buildWorkloadOptions(namespace, byKind, kinds, value),\n [namespace, byKind, kinds, value],\n );\n\n // In strict mode a non-empty value is invalid once loading settles unless it\n // matches a loaded workload — either by its full `[namespace/]kind/name` key\n // (what the picker emits) or by its bare name-part (what consumers that\n // persist only the resolved name, e.g. a Service name or ingress host, feed\n // back in). buildWorkloadOptions pins an unmatched value first, so test\n // membership against the loaded set, not `options`.\n const invalid = useMemo(() => {\n if (!strict || !value || loading) return false;\n const { keys, names } = loadedWorkloads(namespace, byKind, kinds);\n return !keys.has(value) && !names.has(value);\n }, [strict, value, loading, namespace, byKind, kinds]);\n\n // The lead icon reflects the selected workload's kind (read from the value's\n // key), falling back to the first offered kind when nothing is selected or the\n // value carries no recognised kind (e.g. freeform input).\n const selectedKind = kindForValue(kinds, value);\n const leadMeta = WORKLOAD_META[selectedKind];\n const LeadIcon = leadMeta.Icon;\n return (\n <div className={cn(\"flex items-center gap-2\", className)}>\n <LeadIcon\n className=\"h-4 w-4 shrink-0 text-muted-foreground\"\n title={leadMeta.label}\n aria-label={leadMeta.label}\n />\n <div className=\"min-w-0 flex-1\">\n <Combobox\n options={options}\n value={value}\n onChange={onChange}\n allowCustomValue\n loading={loading}\n invalid={invalid}\n placeholder={placeholder}\n />\n </div>\n </div>\n );\n}\n\n"],"names":["ALL_WORKLOAD_KINDS","useState","useEffect","useMemo","buildWorkloadOptions","loadedWorkloads","kindForValue","WORKLOAD_META","cn","jsx","Combobox"],"mappings":";;;;;;;AA2DO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQA,oBAAAA;AAAAA,EACR,SAAS;AAAA,EACT,cAAc;AAAA,EACd;AACF,GAAwB;AACtB,QAAM,CAAC,QAAQ,SAAS,IAAIC,MAAAA,SAA4D,CAAA,CAAE;AAC1F,QAAM,CAAC,SAAS,UAAU,IAAIA,MAAAA,SAAS,KAAK;AAE5C,QAAM,WAAW,MAAM,KAAK,GAAG;AAC/BC,QAAAA,UAAU,MAAM;AACd,QAAI,YAAY;AAChB,eAAW,IAAI;AACf,kBAAc,KAAK,EAChB,KAAK,CAAC,QAAQ;AACb,UAAI,CAAC,UAAW,WAAU,GAAG;AAAA,IAC/B,CAAC,EACA,QAAQ,MAAM;AACb,UAAI,CAAC,UAAW,YAAW,KAAK;AAAA,IAClC,CAAC;AACH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EAIF,GAAG,CAAC,eAAe,QAAQ,CAAC;AAE5B,QAAM,UAAUC,MAAAA;AAAAA,IACd,MAAMC,oBAAAA,qBAAqB,WAAW,QAAQ,OAAO,KAAK;AAAA,IAC1D,CAAC,WAAW,QAAQ,OAAO,KAAK;AAAA,EAAA;AASlC,QAAM,UAAUD,MAAAA,QAAQ,MAAM;AAC5B,QAAI,CAAC,UAAU,CAAC,SAAS,QAAS,QAAO;AACzC,UAAM,EAAE,MAAM,MAAA,IAAUE,oBAAAA,gBAAgB,WAAW,QAAQ,KAAK;AAChE,WAAO,CAAC,KAAK,IAAI,KAAK,KAAK,CAAC,MAAM,IAAI,KAAK;AAAA,EAC7C,GAAG,CAAC,QAAQ,OAAO,SAAS,WAAW,QAAQ,KAAK,CAAC;AAKrD,QAAM,eAAeC,oBAAAA,aAAa,OAAO,KAAK;AAC9C,QAAM,WAAWC,oBAAAA,cAAc,YAAY;AAC3C,QAAM,WAAW,SAAS;AAC1B,yCACG,OAAA,EAAI,WAAWC,MAAAA,GAAG,2BAA2B,SAAS,GACrD,UAAA;AAAA,IAAAC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO,SAAS;AAAA,QAChB,cAAY,SAAS;AAAA,MAAA;AAAA,IAAA;AAAA,IAEvBA,2BAAAA,IAAC,OAAA,EAAI,WAAU,kBACb,UAAAA,2BAAAA;AAAAA,MAACC,SAAAA;AAAAA,MAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA,kBAAgB;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,IAAA,EACF,CACF;AAAA,EAAA,GACF;AAEJ;;"}
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export type WorkloadKind = "service" | "ingress" | "deployment" | "statefulset";
|
|
3
|
-
/** One workload returned by the loader. Ingresses may carry rule hostnames. */
|
|
4
|
-
export type WorkloadResource = {
|
|
5
|
-
name: string;
|
|
6
|
-
hosts?: string[];
|
|
7
|
-
};
|
|
1
|
+
import { WorkloadKind, WorkloadResource } from './workload-picker-utils';
|
|
8
2
|
export type WorkloadPickerProps = {
|
|
9
3
|
/**
|
|
10
4
|
* Controlled selected value — a `[namespace/]kind/name` key (see
|
|
@@ -36,17 +30,4 @@ export type WorkloadPickerProps = {
|
|
|
36
30
|
className?: string;
|
|
37
31
|
};
|
|
38
32
|
export declare function WorkloadPicker({ value, onChange, loadWorkloads, namespace, kinds, strict, placeholder, className, }: WorkloadPickerProps): import("react/jsx-runtime").JSX.Element;
|
|
39
|
-
export type ParsedWorkloadKey = {
|
|
40
|
-
namespace?: string;
|
|
41
|
-
kind?: WorkloadKind;
|
|
42
|
-
name: string;
|
|
43
|
-
};
|
|
44
|
-
export declare function workloadKey(namespace: string | undefined, kind: WorkloadKind, r: WorkloadResource): string;
|
|
45
|
-
export declare function parseWorkloadKey(value: string): ParsedWorkloadKey;
|
|
46
|
-
export declare function loadedWorkloads(namespace: string | undefined, byKind: Partial<Record<WorkloadKind, WorkloadResource[]>>, kinds: WorkloadKind[]): {
|
|
47
|
-
keys: Set<string>;
|
|
48
|
-
names: Set<string>;
|
|
49
|
-
};
|
|
50
|
-
export declare function kindForValue(kinds: WorkloadKind[], value: string): WorkloadKind;
|
|
51
|
-
export declare function buildWorkloadOptions(namespace: string | undefined, byKind: Partial<Record<WorkloadKind, WorkloadResource[]>>, kinds: WorkloadKind[], value: string): ComboboxOption[];
|
|
52
33
|
//# sourceMappingURL=WorkloadPicker.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkloadPicker.d.ts","sourceRoot":"","sources":["../../src/components/WorkloadPicker.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"WorkloadPicker.d.ts","sourceRoot":"","sources":["../../src/components/WorkloadPicker.tsx"],"names":[],"mappings":"AAGA,OAAO,EAML,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACtB,MAAM,yBAAyB,CAAC;AAiBjC,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC;;;OAGG;IACH,aAAa,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC;IAC5F;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;IACvB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,QAAQ,EACR,aAAa,EACb,SAAS,EACT,KAA0B,EAC1B,MAAc,EACd,WAA0C,EAC1C,SAAS,GACV,EAAE,mBAAmB,2CAkErB"}
|
|
@@ -1,21 +1,14 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useEffect, useMemo } from "react";
|
|
3
|
-
import { K8SStatefulset, K8SDeployment, K8SIngress, K8SService } from "@flanksource/icons/mi";
|
|
4
3
|
import { cn } from "../lib/utils.js";
|
|
5
4
|
import { Combobox } from "./Combobox.js";
|
|
6
|
-
|
|
7
|
-
service: { label: "Service", Icon: K8SService },
|
|
8
|
-
ingress: { label: "Ingress", Icon: K8SIngress },
|
|
9
|
-
deployment: { label: "Deployment", Icon: K8SDeployment },
|
|
10
|
-
statefulset: { label: "StatefulSet", Icon: K8SStatefulset }
|
|
11
|
-
};
|
|
12
|
-
const ALL_KINDS = ["service", "ingress", "deployment", "statefulset"];
|
|
5
|
+
import { ALL_WORKLOAD_KINDS, buildWorkloadOptions, loadedWorkloads, kindForValue, WORKLOAD_META } from "./workload-picker-utils.js";
|
|
13
6
|
function WorkloadPicker({
|
|
14
7
|
value,
|
|
15
8
|
onChange,
|
|
16
9
|
loadWorkloads,
|
|
17
10
|
namespace,
|
|
18
|
-
kinds =
|
|
11
|
+
kinds = ALL_WORKLOAD_KINDS,
|
|
19
12
|
strict = false,
|
|
20
13
|
placeholder = "Select workload / service…",
|
|
21
14
|
className
|
|
@@ -70,75 +63,7 @@ function WorkloadPicker({
|
|
|
70
63
|
) })
|
|
71
64
|
] });
|
|
72
65
|
}
|
|
73
|
-
function ingressHost(kind, r) {
|
|
74
|
-
var _a;
|
|
75
|
-
return kind === "ingress" ? (_a = r.hosts) == null ? void 0 : _a[0] : void 0;
|
|
76
|
-
}
|
|
77
|
-
function workloadName(kind, r) {
|
|
78
|
-
return ingressHost(kind, r) ?? r.name;
|
|
79
|
-
}
|
|
80
|
-
const KNOWN_KINDS = /* @__PURE__ */ new Set(["service", "ingress", "deployment", "statefulset"]);
|
|
81
|
-
function workloadKey(namespace, kind, r) {
|
|
82
|
-
const name = workloadName(kind, r);
|
|
83
|
-
return namespace ? `${namespace}/${kind}/${name}` : `${kind}/${name}`;
|
|
84
|
-
}
|
|
85
|
-
function parseWorkloadKey(value) {
|
|
86
|
-
const parts = value.split("/");
|
|
87
|
-
const name = parts.at(-1);
|
|
88
|
-
const maybeKind = parts.at(-2);
|
|
89
|
-
if (name != null && maybeKind != null && KNOWN_KINDS.has(maybeKind)) {
|
|
90
|
-
const namespace = parts.slice(0, -2).join("/");
|
|
91
|
-
const parsed = { kind: maybeKind, name };
|
|
92
|
-
if (namespace) parsed.namespace = namespace;
|
|
93
|
-
return parsed;
|
|
94
|
-
}
|
|
95
|
-
return { name: value };
|
|
96
|
-
}
|
|
97
|
-
function loadedWorkloads(namespace, byKind, kinds) {
|
|
98
|
-
const keys = /* @__PURE__ */ new Set();
|
|
99
|
-
const names = /* @__PURE__ */ new Set();
|
|
100
|
-
for (const kind of kinds) {
|
|
101
|
-
for (const r of byKind[kind] ?? []) {
|
|
102
|
-
keys.add(workloadKey(namespace, kind, r));
|
|
103
|
-
names.add(workloadName(kind, r));
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return { keys, names };
|
|
107
|
-
}
|
|
108
|
-
function kindForValue(kinds, value) {
|
|
109
|
-
const kind = value ? parseWorkloadKey(value).kind : void 0;
|
|
110
|
-
return kind ?? kinds[0] ?? "service";
|
|
111
|
-
}
|
|
112
|
-
function buildWorkloadOptions(namespace, byKind, kinds, value) {
|
|
113
|
-
const opts = [];
|
|
114
|
-
for (const kind of kinds) {
|
|
115
|
-
const meta = WORKLOAD_META[kind];
|
|
116
|
-
const Icon = meta.Icon;
|
|
117
|
-
for (const r of byKind[kind] ?? []) {
|
|
118
|
-
const host = ingressHost(kind, r);
|
|
119
|
-
opts.push({
|
|
120
|
-
value: workloadKey(namespace, kind, r),
|
|
121
|
-
// The label is the human name; an ingress pairs its host with the
|
|
122
|
-
// ingress name for context.
|
|
123
|
-
label: host ? `${host} (${r.name})` : r.name,
|
|
124
|
-
group: meta.label,
|
|
125
|
-
icon: /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" })
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
if (value && !opts.some((o) => o.value === value)) {
|
|
130
|
-
const parsed = parseWorkloadKey(value);
|
|
131
|
-
const Icon = WORKLOAD_META[parsed.kind ?? kinds[0] ?? "service"].Icon;
|
|
132
|
-
return [{ value, label: parsed.name, icon: /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" }) }, ...opts];
|
|
133
|
-
}
|
|
134
|
-
return opts;
|
|
135
|
-
}
|
|
136
66
|
export {
|
|
137
|
-
WorkloadPicker
|
|
138
|
-
buildWorkloadOptions,
|
|
139
|
-
kindForValue,
|
|
140
|
-
loadedWorkloads,
|
|
141
|
-
parseWorkloadKey,
|
|
142
|
-
workloadKey
|
|
67
|
+
WorkloadPicker
|
|
143
68
|
};
|
|
144
69
|
//# sourceMappingURL=WorkloadPicker.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkloadPicker.js","sources":["../../src/components/WorkloadPicker.tsx"],"sourcesContent":["import { useEffect, useMemo, useState, type ComponentType } from \"react\";\nimport {\n K8SService,\n K8SIngress,\n K8SDeployment,\n K8SStatefulset,\n} from \"@flanksource/icons/mi\";\nimport { cn } from \"../lib/utils\";\nimport { Combobox, type ComboboxOption } from \"./Combobox\";\n\n// WorkloadPicker selects a backing Kubernetes workload (Service / Ingress /\n// Deployment / StatefulSet) for an endpoint. Options from every kind are merged\n// into one Combobox, grouped by kind via the Combobox group-header support and\n// labelled with the kind's icon.\n//\n// The emitted value is a `[namespace/]kind/name` key (see workloadKey /\n// parseWorkloadKey) so two workloads of different kinds that share a name don't\n// collide. An ingress's name-part is its first host (the routable address),\n// labelled with the ingress name for context; every other kind uses its name.\n//\n// The component is presentational: it owns the kind→group/icon mapping and the\n// key encoding but fetches nothing — the consumer supplies an async\n// `loadWorkloads` getter.\n\nexport type WorkloadKind = \"service\" | \"ingress\" | \"deployment\" | \"statefulset\";\n\n/** One workload returned by the loader. Ingresses may carry rule hostnames. */\nexport type WorkloadResource = { name: string; hosts?: string[] };\n\ntype KindIconProps = { className?: string; title?: string; \"aria-label\"?: string };\ntype KindMeta = { label: string; Icon: ComponentType<KindIconProps> };\n\n// WORKLOAD_META maps each kind to its group header label and icon, in display\n// order. The order of the keys drives the order options/groups appear in.\nconst WORKLOAD_META: Record<WorkloadKind, KindMeta> = {\n service: { label: \"Service\", Icon: K8SService },\n ingress: { label: \"Ingress\", Icon: K8SIngress },\n deployment: { label: \"Deployment\", Icon: K8SDeployment },\n statefulset: { label: \"StatefulSet\", Icon: K8SStatefulset },\n};\n\nconst ALL_KINDS: WorkloadKind[] = [\"service\", \"ingress\", \"deployment\", \"statefulset\"];\n\nexport type WorkloadPickerProps = {\n /**\n * Controlled selected value — a `[namespace/]kind/name` key (see\n * {@link workloadKey} / {@link parseWorkloadKey}).\n */\n value: string;\n /** Called with the chosen `[namespace/]kind/name` key (or \"\" when cleared). */\n onChange: (value: string) => void;\n /**\n * Async getter the component calls to load the requested kinds' workloads.\n * Returns a map keyed by kind. The consumer owns fetching/caching.\n */\n loadWorkloads: (kinds: WorkloadKind[]) => Promise<Record<WorkloadKind, WorkloadResource[]>>;\n /**\n * Namespace the workloads live in. When set it prefixes the emitted key\n * (`namespace/kind/name`), so values stay distinct across namespaces.\n */\n namespace?: string;\n /** Kinds to offer, in display order. Defaults to all four. */\n kinds?: WorkloadKind[];\n /**\n * When true, a non-empty value that does not match any loaded workload (once\n * loading settles) is flagged invalid — the picked workload doesn't exist in\n * the namespace. The value is still shown (pinned) so the user can see and\n * fix it; freeform entry is not rejected, only marked.\n */\n strict?: boolean;\n placeholder?: string;\n className?: string;\n};\n\nexport function WorkloadPicker({\n value,\n onChange,\n loadWorkloads,\n namespace,\n kinds = ALL_KINDS,\n strict = false,\n placeholder = \"Select workload / service…\",\n className,\n}: WorkloadPickerProps) {\n const [byKind, setByKind] = useState<Partial<Record<WorkloadKind, WorkloadResource[]>>>({});\n const [loading, setLoading] = useState(false);\n\n const kindsKey = kinds.join(\",\");\n useEffect(() => {\n let cancelled = false;\n setLoading(true);\n loadWorkloads(kinds)\n .then((res) => {\n if (!cancelled) setByKind(res);\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n return () => {\n cancelled = true;\n };\n // loadWorkloads is expected to be stable (memoized by the consumer); kindsKey\n // is the joined `kinds` so a changed selection reloads without depending on\n // the array's identity.\n }, [loadWorkloads, kindsKey]);\n\n const options = useMemo(\n () => buildWorkloadOptions(namespace, byKind, kinds, value),\n [namespace, byKind, kinds, value],\n );\n\n // In strict mode a non-empty value is invalid once loading settles unless it\n // matches a loaded workload — either by its full `[namespace/]kind/name` key\n // (what the picker emits) or by its bare name-part (what consumers that\n // persist only the resolved name, e.g. a Service name or ingress host, feed\n // back in). buildWorkloadOptions pins an unmatched value first, so test\n // membership against the loaded set, not `options`.\n const invalid = useMemo(() => {\n if (!strict || !value || loading) return false;\n const { keys, names } = loadedWorkloads(namespace, byKind, kinds);\n return !keys.has(value) && !names.has(value);\n }, [strict, value, loading, namespace, byKind, kinds]);\n\n // The lead icon reflects the selected workload's kind (read from the value's\n // key), falling back to the first offered kind when nothing is selected or the\n // value carries no recognised kind (e.g. freeform input).\n const selectedKind = kindForValue(kinds, value);\n const leadMeta = WORKLOAD_META[selectedKind];\n const LeadIcon = leadMeta.Icon;\n return (\n <div className={cn(\"flex items-center gap-2\", className)}>\n <LeadIcon\n className=\"h-4 w-4 shrink-0 text-muted-foreground\"\n title={leadMeta.label}\n aria-label={leadMeta.label}\n />\n <div className=\"min-w-0 flex-1\">\n <Combobox\n options={options}\n value={value}\n onChange={onChange}\n allowCustomValue\n loading={loading}\n invalid={invalid}\n placeholder={placeholder}\n />\n </div>\n </div>\n );\n}\n\n// ingressHost is the first host an ingress routes, or undefined for non-ingress\n// kinds and host-less ingresses. An ingress's name-part is its host.\nfunction ingressHost(kind: WorkloadKind, r: WorkloadResource): string | undefined {\n return kind === \"ingress\" ? r.hosts?.[0] : undefined;\n}\n\n// workloadName is the name-part of a resource's key: an ingress's first host\n// (the routable address callers want), else the resource's own name.\nfunction workloadName(kind: WorkloadKind, r: WorkloadResource): string {\n return ingressHost(kind, r) ?? r.name;\n}\n\n// ParsedWorkloadKey is the structured form of a `[namespace/]kind/name` value.\nexport type ParsedWorkloadKey = { namespace?: string; kind?: WorkloadKind; name: string };\n\nconst KNOWN_KINDS = new Set<string>([\"service\", \"ingress\", \"deployment\", \"statefulset\"]);\n\n// workloadKey is the value a resource contributes (what onChange emits): a\n// `[namespace/]kind/name` composite so two workloads of different kinds sharing\n// a name don't collide. namespace is omitted when not supplied.\nexport function workloadKey(\n namespace: string | undefined,\n kind: WorkloadKind,\n r: WorkloadResource,\n): string {\n const name = workloadName(kind, r);\n return namespace ? `${namespace}/${kind}/${name}` : `${kind}/${name}`;\n}\n\n// parseWorkloadKey splits a `[namespace/]kind/name` value back into its parts.\n// The trailing segment is always the name (a host may itself contain no slash);\n// the segment before it is the kind when it is a known workload kind, and any\n// remaining leading segment is the namespace. A bare value (no recognised\n// kind/name shape) is returned as just its name so freeform input survives.\nexport function parseWorkloadKey(value: string): ParsedWorkloadKey {\n const parts = value.split(\"/\");\n const name = parts.at(-1);\n const maybeKind = parts.at(-2);\n if (name != null && maybeKind != null && KNOWN_KINDS.has(maybeKind)) {\n const namespace = parts.slice(0, -2).join(\"/\");\n const parsed: ParsedWorkloadKey = { kind: maybeKind as WorkloadKind, name };\n if (namespace) parsed.namespace = namespace;\n return parsed;\n }\n return { name: value };\n}\n\n// loadedWorkloads collapses the loaded resources into the two membership sets a\n// strict picker validates a value against: `keys` are the full\n// `[namespace/]kind/name` keys the picker emits, `names` are the bare name-parts\n// (service name / ingress host) a consumer may persist instead. A value in\n// neither set names a workload that doesn't exist in the namespace.\nexport function loadedWorkloads(\n namespace: string | undefined,\n byKind: Partial<Record<WorkloadKind, WorkloadResource[]>>,\n kinds: WorkloadKind[],\n): { keys: Set<string>; names: Set<string> } {\n const keys = new Set<string>();\n const names = new Set<string>();\n for (const kind of kinds) {\n for (const r of byKind[kind] ?? []) {\n keys.add(workloadKey(namespace, kind, r));\n names.add(workloadName(kind, r));\n }\n }\n return { keys, names };\n}\n\n// kindForValue returns the kind encoded in the selected value, so the lead icon\n// can mirror it without consulting the loaded resources. Falls back to the first\n// offered kind when nothing is selected or the value carries no recognised kind.\nexport function kindForValue(kinds: WorkloadKind[], value: string): WorkloadKind {\n const kind = value ? parseWorkloadKey(value).kind : undefined;\n return kind ?? kinds[0] ?? \"service\";\n}\n\n// buildWorkloadOptions flattens the per-kind resources into grouped Combobox\n// options in kind order. Each option's value is its `[namespace/]kind/name` key\n// and its label the human name; a current value not present in any kind is\n// pinned first (labelled with just its name-part) so the selection stays visible.\nexport function buildWorkloadOptions(\n namespace: string | undefined,\n byKind: Partial<Record<WorkloadKind, WorkloadResource[]>>,\n kinds: WorkloadKind[],\n value: string,\n): ComboboxOption[] {\n const opts: ComboboxOption[] = [];\n for (const kind of kinds) {\n const meta = WORKLOAD_META[kind];\n const Icon = meta.Icon;\n for (const r of byKind[kind] ?? []) {\n const host = ingressHost(kind, r);\n opts.push({\n value: workloadKey(namespace, kind, r),\n // The label is the human name; an ingress pairs its host with the\n // ingress name for context.\n label: host ? `${host} (${r.name})` : r.name,\n group: meta.label,\n icon: <Icon className=\"h-4 w-4\" />,\n });\n }\n }\n if (value && !opts.some((o) => o.value === value)) {\n const parsed = parseWorkloadKey(value);\n const Icon = WORKLOAD_META[parsed.kind ?? kinds[0] ?? \"service\"].Icon;\n return [{ value, label: parsed.name, icon: <Icon className=\"h-4 w-4\" /> }, ...opts];\n }\n return opts;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WorkloadPicker.js","sources":["../../src/components/WorkloadPicker.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Combobox } from \"./Combobox\";\nimport {\n ALL_WORKLOAD_KINDS,\n WORKLOAD_META,\n buildWorkloadOptions,\n kindForValue,\n loadedWorkloads,\n type WorkloadKind,\n type WorkloadResource,\n} from \"./workload-picker-utils\";\n\n// WorkloadPicker selects a backing Kubernetes workload (Service / Ingress /\n// Deployment / StatefulSet) for an endpoint. Options from every kind are merged\n// into one Combobox, grouped by kind via the Combobox group-header support and\n// labelled with the kind's icon.\n//\n// The emitted value is a `[namespace/]kind/name` key (see workloadKey /\n// parseWorkloadKey in workload-picker-utils) so two workloads of different\n// kinds that share a name don't collide. An ingress's name-part is its first\n// host (the routable address), labelled with the ingress name for context;\n// every other kind uses its name.\n//\n// The component is presentational: the kind→group/icon mapping and the key\n// encoding live in workload-picker-utils; it fetches nothing — the consumer\n// supplies an async `loadWorkloads` getter.\n\nexport type WorkloadPickerProps = {\n /**\n * Controlled selected value — a `[namespace/]kind/name` key (see\n * {@link workloadKey} / {@link parseWorkloadKey}).\n */\n value: string;\n /** Called with the chosen `[namespace/]kind/name` key (or \"\" when cleared). */\n onChange: (value: string) => void;\n /**\n * Async getter the component calls to load the requested kinds' workloads.\n * Returns a map keyed by kind. The consumer owns fetching/caching.\n */\n loadWorkloads: (kinds: WorkloadKind[]) => Promise<Record<WorkloadKind, WorkloadResource[]>>;\n /**\n * Namespace the workloads live in. When set it prefixes the emitted key\n * (`namespace/kind/name`), so values stay distinct across namespaces.\n */\n namespace?: string;\n /** Kinds to offer, in display order. Defaults to all four. */\n kinds?: WorkloadKind[];\n /**\n * When true, a non-empty value that does not match any loaded workload (once\n * loading settles) is flagged invalid — the picked workload doesn't exist in\n * the namespace. The value is still shown (pinned) so the user can see and\n * fix it; freeform entry is not rejected, only marked.\n */\n strict?: boolean;\n placeholder?: string;\n className?: string;\n};\n\nexport function WorkloadPicker({\n value,\n onChange,\n loadWorkloads,\n namespace,\n kinds = ALL_WORKLOAD_KINDS,\n strict = false,\n placeholder = \"Select workload / service…\",\n className,\n}: WorkloadPickerProps) {\n const [byKind, setByKind] = useState<Partial<Record<WorkloadKind, WorkloadResource[]>>>({});\n const [loading, setLoading] = useState(false);\n\n const kindsKey = kinds.join(\",\");\n useEffect(() => {\n let cancelled = false;\n setLoading(true);\n loadWorkloads(kinds)\n .then((res) => {\n if (!cancelled) setByKind(res);\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n return () => {\n cancelled = true;\n };\n // loadWorkloads is expected to be stable (memoized by the consumer); kindsKey\n // is the joined `kinds` so a changed selection reloads without depending on\n // the array's identity.\n }, [loadWorkloads, kindsKey]);\n\n const options = useMemo(\n () => buildWorkloadOptions(namespace, byKind, kinds, value),\n [namespace, byKind, kinds, value],\n );\n\n // In strict mode a non-empty value is invalid once loading settles unless it\n // matches a loaded workload — either by its full `[namespace/]kind/name` key\n // (what the picker emits) or by its bare name-part (what consumers that\n // persist only the resolved name, e.g. a Service name or ingress host, feed\n // back in). buildWorkloadOptions pins an unmatched value first, so test\n // membership against the loaded set, not `options`.\n const invalid = useMemo(() => {\n if (!strict || !value || loading) return false;\n const { keys, names } = loadedWorkloads(namespace, byKind, kinds);\n return !keys.has(value) && !names.has(value);\n }, [strict, value, loading, namespace, byKind, kinds]);\n\n // The lead icon reflects the selected workload's kind (read from the value's\n // key), falling back to the first offered kind when nothing is selected or the\n // value carries no recognised kind (e.g. freeform input).\n const selectedKind = kindForValue(kinds, value);\n const leadMeta = WORKLOAD_META[selectedKind];\n const LeadIcon = leadMeta.Icon;\n return (\n <div className={cn(\"flex items-center gap-2\", className)}>\n <LeadIcon\n className=\"h-4 w-4 shrink-0 text-muted-foreground\"\n title={leadMeta.label}\n aria-label={leadMeta.label}\n />\n <div className=\"min-w-0 flex-1\">\n <Combobox\n options={options}\n value={value}\n onChange={onChange}\n allowCustomValue\n loading={loading}\n invalid={invalid}\n placeholder={placeholder}\n />\n </div>\n </div>\n );\n}\n\n"],"names":[],"mappings":";;;;;AA2DO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,cAAc;AAAA,EACd;AACF,GAAwB;AACtB,QAAM,CAAC,QAAQ,SAAS,IAAI,SAA4D,CAAA,CAAE;AAC1F,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAE5C,QAAM,WAAW,MAAM,KAAK,GAAG;AAC/B,YAAU,MAAM;AACd,QAAI,YAAY;AAChB,eAAW,IAAI;AACf,kBAAc,KAAK,EAChB,KAAK,CAAC,QAAQ;AACb,UAAI,CAAC,UAAW,WAAU,GAAG;AAAA,IAC/B,CAAC,EACA,QAAQ,MAAM;AACb,UAAI,CAAC,UAAW,YAAW,KAAK;AAAA,IAClC,CAAC;AACH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EAIF,GAAG,CAAC,eAAe,QAAQ,CAAC;AAE5B,QAAM,UAAU;AAAA,IACd,MAAM,qBAAqB,WAAW,QAAQ,OAAO,KAAK;AAAA,IAC1D,CAAC,WAAW,QAAQ,OAAO,KAAK;AAAA,EAAA;AASlC,QAAM,UAAU,QAAQ,MAAM;AAC5B,QAAI,CAAC,UAAU,CAAC,SAAS,QAAS,QAAO;AACzC,UAAM,EAAE,MAAM,MAAA,IAAU,gBAAgB,WAAW,QAAQ,KAAK;AAChE,WAAO,CAAC,KAAK,IAAI,KAAK,KAAK,CAAC,MAAM,IAAI,KAAK;AAAA,EAC7C,GAAG,CAAC,QAAQ,OAAO,SAAS,WAAW,QAAQ,KAAK,CAAC;AAKrD,QAAM,eAAe,aAAa,OAAO,KAAK;AAC9C,QAAM,WAAW,cAAc,YAAY;AAC3C,QAAM,WAAW,SAAS;AAC1B,8BACG,OAAA,EAAI,WAAW,GAAG,2BAA2B,SAAS,GACrD,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO,SAAS;AAAA,QAChB,cAAY,SAAS;AAAA,MAAA;AAAA,IAAA;AAAA,IAEvB,oBAAC,OAAA,EAAI,WAAU,kBACb,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA,kBAAgB;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,IAAA,EACF,CACF;AAAA,EAAA,GACF;AAEJ;"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const classVarianceAuthority = require("class-variance-authority");
|
|
4
|
+
const buttonVariants = classVarianceAuthority.cva(
|
|
5
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
6
|
+
{
|
|
7
|
+
variants: {
|
|
8
|
+
variant: {
|
|
9
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
10
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
11
|
+
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
12
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
13
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
14
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
15
|
+
},
|
|
16
|
+
size: {
|
|
17
|
+
default: "h-control-h px-control-px py-2",
|
|
18
|
+
sm: "h-8 rounded-md px-3 text-xs",
|
|
19
|
+
lg: "h-10 rounded-md px-8",
|
|
20
|
+
icon: "h-control-h w-control-h"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
defaultVariants: {
|
|
24
|
+
variant: "default",
|
|
25
|
+
size: "default"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
exports.buttonVariants = buttonVariants;
|
|
30
|
+
//# sourceMappingURL=button-variants.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button-variants.cjs","sources":["../../src/components/button-variants.ts"],"sourcesContent":["import { cva } from \"class-variance-authority\";\n\nexport const buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive: \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\n outline: \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n secondary: \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-control-h px-control-px py-2\",\n sm: \"h-8 rounded-md px-3 text-xs\",\n lg: \"h-10 rounded-md px-8\",\n icon: \"h-control-h w-control-h\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n"],"names":["cva"],"mappings":";;;AAEO,MAAM,iBAAiBA,uBAAAA;AAAAA,EAC5B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,aAAa;AAAA,QACb,SAAS;AAAA,QACT,WAAW;AAAA,QACX,OAAO;AAAA,QACP,MAAM;AAAA,MAAA;AAAA,MAER,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,MAAM;AAAA,MAAA;AAAA,IACR;AAAA,IAEF,iBAAiB;AAAA,MACf,SAAS;AAAA,MACT,MAAM;AAAA,IAAA;AAAA,EACR;AAEJ;;"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const buttonVariants: (props?: ({
|
|
2
|
+
variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
|
|
3
|
+
size?: "sm" | "lg" | "default" | "icon" | null | undefined;
|
|
4
|
+
} & import('class-variance-authority/types').ClassProp) | undefined) => string;
|
|
5
|
+
//# sourceMappingURL=button-variants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button-variants.d.ts","sourceRoot":"","sources":["../../src/components/button-variants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,cAAc;;;8EAwB1B,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { cva } from "class-variance-authority";
|
|
2
|
+
const buttonVariants = cva(
|
|
3
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
4
|
+
{
|
|
5
|
+
variants: {
|
|
6
|
+
variant: {
|
|
7
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
8
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
9
|
+
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
10
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
11
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
12
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
13
|
+
},
|
|
14
|
+
size: {
|
|
15
|
+
default: "h-control-h px-control-px py-2",
|
|
16
|
+
sm: "h-8 rounded-md px-3 text-xs",
|
|
17
|
+
lg: "h-10 rounded-md px-8",
|
|
18
|
+
icon: "h-control-h w-control-h"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
defaultVariants: {
|
|
22
|
+
variant: "default",
|
|
23
|
+
size: "default"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
export {
|
|
28
|
+
buttonVariants
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=button-variants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button-variants.js","sources":["../../src/components/button-variants.ts"],"sourcesContent":["import { cva } from \"class-variance-authority\";\n\nexport const buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive: \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\n outline: \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n secondary: \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-control-h px-control-px py-2\",\n sm: \"h-8 rounded-md px-3 text-xs\",\n lg: \"h-10 rounded-md px-8\",\n icon: \"h-control-h w-control-h\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n"],"names":[],"mappings":";AAEO,MAAM,iBAAiB;AAAA,EAC5B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,aAAa;AAAA,QACb,SAAS;AAAA,QACT,WAAW;AAAA,QACX,OAAO;AAAA,QACP,MAAM;AAAA,MAAA;AAAA,MAER,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,MAAM;AAAA,MAAA;AAAA,IACR;AAAA,IAEF,iBAAiB;AAAA,MACf,SAAS;AAAA,MACT,MAAM;AAAA,IAAA;AAAA,EACR;AAEJ;"}
|