@tetrascience-npm/tetrascience-react-ui 0.5.0 → 0.6.0-beta.79.1
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/README.md +84 -37
- package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.cjs +2 -0
- package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.cjs.map +1 -0
- package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.js +140 -0
- package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.js.map +1 -0
- package/dist/components/composed/PlateMapEditor/PlateMapActionsMenu.cjs +2 -0
- package/dist/components/composed/PlateMapEditor/PlateMapActionsMenu.cjs.map +1 -0
- package/dist/components/composed/PlateMapEditor/PlateMapActionsMenu.js +126 -0
- package/dist/components/composed/PlateMapEditor/PlateMapActionsMenu.js.map +1 -0
- package/dist/components/composed/PlateMapEditor/PlateMapEditor.cjs +2 -0
- package/dist/components/composed/PlateMapEditor/PlateMapEditor.cjs.map +1 -0
- package/dist/components/composed/PlateMapEditor/PlateMapEditor.js +341 -0
- package/dist/components/composed/PlateMapEditor/PlateMapEditor.js.map +1 -0
- package/dist/components/composed/PlateMapEditor/PlateMapForm.cjs +2 -0
- package/dist/components/composed/PlateMapEditor/PlateMapForm.cjs.map +1 -0
- package/dist/components/composed/PlateMapEditor/PlateMapForm.js +43 -0
- package/dist/components/composed/PlateMapEditor/PlateMapForm.js.map +1 -0
- package/dist/components/composed/PlateMapEditor/PlateMapGrid.cjs +2 -0
- package/dist/components/composed/PlateMapEditor/PlateMapGrid.cjs.map +1 -0
- package/dist/components/composed/PlateMapEditor/PlateMapGrid.js +154 -0
- package/dist/components/composed/PlateMapEditor/PlateMapGrid.js.map +1 -0
- package/dist/components/composed/PlateMapEditor/PlateMapManifest.cjs +2 -0
- package/dist/components/composed/PlateMapEditor/PlateMapManifest.cjs.map +1 -0
- package/dist/components/composed/PlateMapEditor/PlateMapManifest.js +44 -0
- package/dist/components/composed/PlateMapEditor/PlateMapManifest.js.map +1 -0
- package/dist/components/composed/PlateMapEditor/PlateMapPlateSelector.cjs +2 -0
- package/dist/components/composed/PlateMapEditor/PlateMapPlateSelector.cjs.map +1 -0
- package/dist/components/composed/PlateMapEditor/PlateMapPlateSelector.js +136 -0
- package/dist/components/composed/PlateMapEditor/PlateMapPlateSelector.js.map +1 -0
- package/dist/components/composed/PlateMapEditor/PlatePaintGrid.cjs +2 -0
- package/dist/components/composed/PlateMapEditor/PlatePaintGrid.cjs.map +1 -0
- package/dist/components/composed/PlateMapEditor/PlatePaintGrid.js +389 -0
- package/dist/components/composed/PlateMapEditor/PlatePaintGrid.js.map +1 -0
- package/dist/components/composed/PlateMapEditor/PlateZoomControl.cjs +2 -0
- package/dist/components/composed/PlateMapEditor/PlateZoomControl.cjs.map +1 -0
- package/dist/components/composed/PlateMapEditor/PlateZoomControl.js +54 -0
- package/dist/components/composed/PlateMapEditor/PlateZoomControl.js.map +1 -0
- package/dist/components/composed/PlateMapEditor/TemplateIOPanel.cjs +2 -0
- package/dist/components/composed/PlateMapEditor/TemplateIOPanel.cjs.map +1 -0
- package/dist/components/composed/PlateMapEditor/TemplateIOPanel.js +96 -0
- package/dist/components/composed/PlateMapEditor/TemplateIOPanel.js.map +1 -0
- package/dist/components/composed/PlateMapEditor/WellLegend.cjs +2 -0
- package/dist/components/composed/PlateMapEditor/WellLegend.cjs.map +1 -0
- package/dist/components/composed/PlateMapEditor/WellLegend.js +58 -0
- package/dist/components/composed/PlateMapEditor/WellLegend.js.map +1 -0
- package/dist/components/composed/PlateMapEditor/WellManifestTable.cjs +2 -0
- package/dist/components/composed/PlateMapEditor/WellManifestTable.cjs.map +1 -0
- package/dist/components/composed/PlateMapEditor/WellManifestTable.js +421 -0
- package/dist/components/composed/PlateMapEditor/WellManifestTable.js.map +1 -0
- package/dist/components/composed/PlateMapEditor/WellMetadataForm.cjs +2 -0
- package/dist/components/composed/PlateMapEditor/WellMetadataForm.cjs.map +1 -0
- package/dist/components/composed/PlateMapEditor/WellMetadataForm.js +177 -0
- package/dist/components/composed/PlateMapEditor/WellMetadataForm.js.map +1 -0
- package/dist/components/composed/PlateMapEditor/autoFill.cjs +2 -0
- package/dist/components/composed/PlateMapEditor/autoFill.cjs.map +1 -0
- package/dist/components/composed/PlateMapEditor/autoFill.js +41 -0
- package/dist/components/composed/PlateMapEditor/autoFill.js.map +1 -0
- package/dist/components/composed/PlateMapEditor/csvPlateTriage.cjs +4 -0
- package/dist/components/composed/PlateMapEditor/csvPlateTriage.cjs.map +1 -0
- package/dist/components/composed/PlateMapEditor/csvPlateTriage.js +103 -0
- package/dist/components/composed/PlateMapEditor/csvPlateTriage.js.map +1 -0
- package/dist/components/composed/PlateMapEditor/helpers.cjs +2 -0
- package/dist/components/composed/PlateMapEditor/helpers.cjs.map +1 -0
- package/dist/components/composed/PlateMapEditor/helpers.js +11 -0
- package/dist/components/composed/PlateMapEditor/helpers.js.map +1 -0
- package/dist/components/composed/PlateMapEditor/wellGrid.cjs +2 -0
- package/dist/components/composed/PlateMapEditor/wellGrid.cjs.map +1 -0
- package/dist/components/composed/PlateMapEditor/wellGrid.js +56 -0
- package/dist/components/composed/PlateMapEditor/wellGrid.js.map +1 -0
- package/dist/components/composed/ProcessFlow/ProcessFlow.cjs +2 -0
- package/dist/components/composed/ProcessFlow/ProcessFlow.cjs.map +1 -0
- package/dist/components/composed/ProcessFlow/ProcessFlow.js +543 -0
- package/dist/components/composed/ProcessFlow/ProcessFlow.js.map +1 -0
- package/dist/components/composed/ProcessFlow/ProcessFlow.utils.cjs +2 -0
- package/dist/components/composed/ProcessFlow/ProcessFlow.utils.cjs.map +1 -0
- package/dist/components/composed/ProcessFlow/ProcessFlow.utils.js +84 -0
- package/dist/components/composed/ProcessFlow/ProcessFlow.utils.js.map +1 -0
- package/dist/components/ui/accordion.cjs +1 -1
- package/dist/components/ui/accordion.cjs.map +1 -1
- package/dist/components/ui/accordion.js +1 -1
- package/dist/components/ui/accordion.js.map +1 -1
- package/dist/components/ui/badge.cjs +1 -1
- package/dist/components/ui/badge.cjs.map +1 -1
- package/dist/components/ui/badge.js +18 -18
- package/dist/components/ui/badge.js.map +1 -1
- package/dist/components/ui/button.cjs +1 -1
- package/dist/components/ui/button.cjs.map +1 -1
- package/dist/components/ui/button.js +16 -16
- package/dist/components/ui/button.js.map +1 -1
- package/dist/components/ui/calendar.cjs +1 -1
- package/dist/components/ui/calendar.cjs.map +1 -1
- package/dist/components/ui/calendar.js +5 -5
- package/dist/components/ui/calendar.js.map +1 -1
- package/dist/components/ui/card.cjs +1 -1
- package/dist/components/ui/card.cjs.map +1 -1
- package/dist/components/ui/card.js +1 -1
- package/dist/components/ui/card.js.map +1 -1
- package/dist/components/ui/checkbox.cjs +1 -1
- package/dist/components/ui/checkbox.cjs.map +1 -1
- package/dist/components/ui/checkbox.js +9 -9
- package/dist/components/ui/checkbox.js.map +1 -1
- package/dist/components/ui/combobox.cjs +1 -1
- package/dist/components/ui/combobox.cjs.map +1 -1
- package/dist/components/ui/combobox.js +5 -5
- package/dist/components/ui/combobox.js.map +1 -1
- package/dist/components/ui/data-table/data-table-group.cjs +2 -0
- package/dist/components/ui/data-table/data-table-group.cjs.map +1 -0
- package/dist/components/ui/data-table/data-table-group.js +118 -0
- package/dist/components/ui/data-table/data-table-group.js.map +1 -0
- package/dist/components/ui/data-table/data-table-pagination.cjs +1 -1
- package/dist/components/ui/data-table/data-table-pagination.cjs.map +1 -1
- package/dist/components/ui/data-table/data-table-pagination.js +22 -22
- package/dist/components/ui/data-table/data-table-pagination.js.map +1 -1
- package/dist/components/ui/data-table/data-table.cjs +1 -1
- package/dist/components/ui/data-table/data-table.cjs.map +1 -1
- package/dist/components/ui/data-table/data-table.js +567 -316
- package/dist/components/ui/data-table/data-table.js.map +1 -1
- package/dist/components/ui/dialog.cjs +1 -1
- package/dist/components/ui/dialog.cjs.map +1 -1
- package/dist/components/ui/dialog.js +13 -13
- package/dist/components/ui/dialog.js.map +1 -1
- package/dist/components/ui/input-group.cjs +1 -1
- package/dist/components/ui/input-group.cjs.map +1 -1
- package/dist/components/ui/input-group.js +29 -29
- package/dist/components/ui/input-group.js.map +1 -1
- package/dist/components/ui/input-otp.cjs +1 -1
- package/dist/components/ui/input-otp.cjs.map +1 -1
- package/dist/components/ui/input-otp.js +10 -10
- package/dist/components/ui/input-otp.js.map +1 -1
- package/dist/components/ui/input.cjs +1 -1
- package/dist/components/ui/input.cjs.map +1 -1
- package/dist/components/ui/input.js +7 -7
- package/dist/components/ui/input.js.map +1 -1
- package/dist/components/ui/item.cjs +1 -1
- package/dist/components/ui/item.cjs.map +1 -1
- package/dist/components/ui/item.js +17 -17
- package/dist/components/ui/item.js.map +1 -1
- package/dist/components/ui/navigation-menu.cjs +1 -1
- package/dist/components/ui/navigation-menu.cjs.map +1 -1
- package/dist/components/ui/navigation-menu.js +24 -24
- package/dist/components/ui/navigation-menu.js.map +1 -1
- package/dist/components/ui/popover.cjs +2 -0
- package/dist/components/ui/popover.cjs.map +1 -0
- package/dist/components/ui/popover.js +45 -0
- package/dist/components/ui/popover.js.map +1 -0
- package/dist/components/ui/radio-group.cjs +1 -1
- package/dist/components/ui/radio-group.cjs.map +1 -1
- package/dist/components/ui/radio-group.js +16 -16
- package/dist/components/ui/radio-group.js.map +1 -1
- package/dist/components/ui/scroll-area.cjs +1 -1
- package/dist/components/ui/scroll-area.cjs.map +1 -1
- package/dist/components/ui/scroll-area.js +6 -6
- package/dist/components/ui/scroll-area.js.map +1 -1
- package/dist/components/ui/select.cjs +1 -1
- package/dist/components/ui/select.cjs.map +1 -1
- package/dist/components/ui/select.js +48 -48
- package/dist/components/ui/select.js.map +1 -1
- package/dist/components/ui/slider.cjs +1 -1
- package/dist/components/ui/slider.cjs.map +1 -1
- package/dist/components/ui/slider.js +22 -22
- package/dist/components/ui/slider.js.map +1 -1
- package/dist/components/ui/switch.cjs +1 -1
- package/dist/components/ui/switch.cjs.map +1 -1
- package/dist/components/ui/switch.js +14 -14
- package/dist/components/ui/switch.js.map +1 -1
- package/dist/components/ui/table.cjs +1 -1
- package/dist/components/ui/table.cjs.map +1 -1
- package/dist/components/ui/table.js +2 -2
- package/dist/components/ui/table.js.map +1 -1
- package/dist/components/ui/tabs.cjs +1 -1
- package/dist/components/ui/tabs.cjs.map +1 -1
- package/dist/components/ui/tabs.js +9 -9
- package/dist/components/ui/tabs.js.map +1 -1
- package/dist/components/ui/textarea.cjs +1 -1
- package/dist/components/ui/textarea.cjs.map +1 -1
- package/dist/components/ui/textarea.js +6 -6
- package/dist/components/ui/textarea.js.map +1 -1
- package/dist/components/ui/toggle.cjs +1 -1
- package/dist/components/ui/toggle.cjs.map +1 -1
- package/dist/components/ui/toggle.js +13 -13
- package/dist/components/ui/toggle.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +830 -3
- package/dist/index.js +649 -593
- package/dist/index.js.map +1 -1
- package/dist/index.tailwind.css +1 -1
- package/dist/utils/colors.cjs +1 -1
- package/dist/utils/colors.cjs.map +1 -1
- package/dist/utils/colors.js +43 -21
- package/dist/utils/colors.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,9 +25,9 @@ This library provides:
|
|
|
25
25
|
## Compatibility
|
|
26
26
|
|
|
27
27
|
| Library version | React | Node.js | TDP (server utilities) |
|
|
28
|
-
|
|
|
29
|
-
| v0.5.x
|
|
30
|
-
| v0.4.x
|
|
28
|
+
| --------------- | ----- | ------- | ---------------------- |
|
|
29
|
+
| v0.5.x | 19+ | 18+ | v4.x+ |
|
|
30
|
+
| v0.4.x | 19+ | 18+ | v4.x+ |
|
|
31
31
|
|
|
32
32
|
> **Note:** The client-side components have no TDP version dependency.
|
|
33
33
|
> The `/server` utilities (JWT auth, provider helpers) require a running TDP instance of v4.x or later.
|
|
@@ -43,10 +43,10 @@ yarn add @tetrascience-npm/tetrascience-react-ui
|
|
|
43
43
|
|
|
44
44
|
```tsx
|
|
45
45
|
// 1. Import the CSS once at your app root (required)
|
|
46
|
-
import
|
|
46
|
+
import "@tetrascience-npm/tetrascience-react-ui/index.css";
|
|
47
47
|
|
|
48
48
|
// 2. Import components
|
|
49
|
-
import { Button, Card, CardHeader, CardContent } from
|
|
49
|
+
import { Button, Card, CardHeader, CardContent } from "@tetrascience-npm/tetrascience-react-ui";
|
|
50
50
|
|
|
51
51
|
function App() {
|
|
52
52
|
return (
|
|
@@ -67,9 +67,9 @@ This library uses **Tailwind CSS 4** with design tokens defined as CSS custom pr
|
|
|
67
67
|
|
|
68
68
|
### CSS Import Options
|
|
69
69
|
|
|
70
|
-
| Import path
|
|
71
|
-
|
|
|
72
|
-
| `@tetrascience-npm/tetrascience-react-ui/index.css`
|
|
70
|
+
| Import path | Use case |
|
|
71
|
+
| ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- |
|
|
72
|
+
| `@tetrascience-npm/tetrascience-react-ui/index.css` | **Pre-built CSS** — use this for most apps. Import once at your app root. |
|
|
73
73
|
| `@tetrascience-npm/tetrascience-react-ui/index.tailwind.css` | **Tailwind source** — for apps that run their own Tailwind build and want to extend/override tokens. |
|
|
74
74
|
|
|
75
75
|
Most consumers only need `index.css`:
|
|
@@ -100,7 +100,58 @@ Accordion, Alert, AlertDialog, AspectRatio, Avatar, Badge, Breadcrumb, Button, B
|
|
|
100
100
|
|
|
101
101
|
TetraScience-specific compositions built from UI primitives:
|
|
102
102
|
|
|
103
|
-
AppHeader, AppLayout, AssistantModal, CodeScriptEditorButton, LaunchContent, Main, Navbar, ProtocolConfiguration, ProtocolYamlCard, PythonEditorModal, Sidebar, TdpLink, TdpSearch, TdpUrl
|
|
103
|
+
AppHeader, AppLayout, AssistantModal, CodeScriptEditorButton, LaunchContent, Main, Navbar, ProcessFlow, ProtocolConfiguration, ProtocolYamlCard, PythonEditorModal, Sidebar, TdpLink, TdpSearch, TdpUrl
|
|
104
|
+
|
|
105
|
+
#### ProcessFlow
|
|
106
|
+
|
|
107
|
+
Use `ProcessFlow` to render parent-owned multi-step workflow state such as uploads, validation pipelines, review flows, processing stages, and setup sequences. Import it from the package and keep all workflow transitions and side effects in the consuming app.
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
import {
|
|
111
|
+
PROCESS_FLOW_STEP_STATUSES,
|
|
112
|
+
ProcessFlow,
|
|
113
|
+
type ProcessFlowStep,
|
|
114
|
+
type ProcessFlowStepStatus,
|
|
115
|
+
} from "@tetrascience-npm/tetrascience-react-ui";
|
|
116
|
+
|
|
117
|
+
const steps: ProcessFlowStep[] = [
|
|
118
|
+
{ id: "upload", label: "Upload", description: "Choose source files", status: "completed" },
|
|
119
|
+
{ id: "validate", label: "Validate", description: "Check schema and lineage", status: "active" },
|
|
120
|
+
{ id: "publish", label: "Publish", description: "Send downstream", status: "pending" },
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
function WorkflowProgress() {
|
|
124
|
+
return (
|
|
125
|
+
<ProcessFlow
|
|
126
|
+
steps={steps}
|
|
127
|
+
selectedStepId="validate"
|
|
128
|
+
onStepSelect={(step, details) => {
|
|
129
|
+
console.log(step.id, details.status);
|
|
130
|
+
}}
|
|
131
|
+
/>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const allStatuses: readonly ProcessFlowStepStatus[] = PROCESS_FLOW_STEP_STATUSES;
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Expected contract:
|
|
139
|
+
|
|
140
|
+
- `status` is independently controlled per step: `pending`, `active`, `completed`, `error`, or `disabled`.
|
|
141
|
+
- `selectedStepId` means the step the user is viewing or has clicked; it is separate from the `active` workflow state.
|
|
142
|
+
- `onStepSelect` emits user selection only. It does not mean a workflow step completed.
|
|
143
|
+
- Parent workflow code owns completion, error handling, retries, analytics, and other side effects.
|
|
144
|
+
- `description` is shown by default. Pass `showDescriptions={false}` to hide all descriptions.
|
|
145
|
+
- Descriptions auto-hide at narrow container widths (≤40rem) for mobile layouts.
|
|
146
|
+
- The component fills 100% of its container width — size it by controlling the container.
|
|
147
|
+
- Selected completed steps render with a green label; selected active steps render with a blue label.
|
|
148
|
+
- Use `connections` and per-step `position` only for simple branching/configurable flows.
|
|
149
|
+
|
|
150
|
+
For AI-assisted consuming apps, add a short instruction like this to the app's `AGENTS.md` or `CLAUDE.md`:
|
|
151
|
+
|
|
152
|
+
```md
|
|
153
|
+
Use `ProcessFlow` from `@tetrascience-npm/tetrascience-react-ui` for multi-step workflow visualization. Do not build a custom stepper for upload, validation, review, approval, processing, or setup flows. Parent components own the workflow state and pass `steps: ProcessFlowStep[]`; each step status must be one of `PROCESS_FLOW_STEP_STATUSES`. Use `selectedStepId` only for the viewed/selected step. Keep completion/error side effects in the parent workflow code, not inside `ProcessFlow`.
|
|
154
|
+
```
|
|
104
155
|
|
|
105
156
|
### Charts (`charts/`)
|
|
106
157
|
|
|
@@ -117,7 +168,7 @@ Beyond UI components, this library includes server-side helper functions for bui
|
|
|
117
168
|
**JWT Token Manager** - Manages JWT token retrieval for data apps:
|
|
118
169
|
|
|
119
170
|
```typescript
|
|
120
|
-
import { jwtManager } from
|
|
171
|
+
import { jwtManager } from "@tetrascience-npm/tetrascience-react-ui/server";
|
|
121
172
|
|
|
122
173
|
// In Express middleware
|
|
123
174
|
app.use(async (req, res, next) => {
|
|
@@ -146,12 +197,8 @@ TypeScript equivalents of the Python helpers from `ts-lib-ui-kit-streamlit` for
|
|
|
146
197
|
**Getting Provider Configurations:**
|
|
147
198
|
|
|
148
199
|
```typescript
|
|
149
|
-
import { TDPClient } from
|
|
150
|
-
import {
|
|
151
|
-
getProviderConfigurations,
|
|
152
|
-
buildProvider,
|
|
153
|
-
jwtManager,
|
|
154
|
-
} from '@tetrascience-npm/tetrascience-react-ui/server';
|
|
200
|
+
import { TDPClient } from "@tetrascience-npm/ts-connectors-sdk";
|
|
201
|
+
import { getProviderConfigurations, buildProvider, jwtManager } from "@tetrascience-npm/tetrascience-react-ui/server";
|
|
155
202
|
|
|
156
203
|
// Get user's auth token from request (e.g., in Express middleware)
|
|
157
204
|
const userToken = await jwtManager.getTokenFromExpressRequest(req);
|
|
@@ -160,7 +207,7 @@ const userToken = await jwtManager.getTokenFromExpressRequest(req);
|
|
|
160
207
|
// Other fields (tdpEndpoint, connectorId, orgSlug) are read from environment variables
|
|
161
208
|
const client = new TDPClient({
|
|
162
209
|
authToken: userToken,
|
|
163
|
-
artifactType:
|
|
210
|
+
artifactType: "data-app",
|
|
164
211
|
});
|
|
165
212
|
await client.init();
|
|
166
213
|
|
|
@@ -172,7 +219,7 @@ for (const config of providers) {
|
|
|
172
219
|
|
|
173
220
|
// Build a database connection from the config
|
|
174
221
|
const provider = await buildProvider(config);
|
|
175
|
-
const results = await provider.query(
|
|
222
|
+
const results = await provider.query("SELECT * FROM my_table LIMIT 10");
|
|
176
223
|
await provider.close();
|
|
177
224
|
}
|
|
178
225
|
```
|
|
@@ -185,21 +232,21 @@ import {
|
|
|
185
232
|
buildDatabricksProvider,
|
|
186
233
|
getTdpAthenaProvider,
|
|
187
234
|
type ProviderConfiguration,
|
|
188
|
-
} from
|
|
235
|
+
} from "@tetrascience-npm/tetrascience-react-ui/server";
|
|
189
236
|
|
|
190
237
|
// Snowflake
|
|
191
238
|
const snowflakeProvider = await buildSnowflakeProvider(config);
|
|
192
|
-
const data = await snowflakeProvider.query(
|
|
239
|
+
const data = await snowflakeProvider.query("SELECT * FROM users");
|
|
193
240
|
await snowflakeProvider.close();
|
|
194
241
|
|
|
195
242
|
// Databricks
|
|
196
243
|
const databricksProvider = await buildDatabricksProvider(config);
|
|
197
|
-
const data = await databricksProvider.query(
|
|
244
|
+
const data = await databricksProvider.query("SELECT * FROM events");
|
|
198
245
|
await databricksProvider.close();
|
|
199
246
|
|
|
200
247
|
// TDP Athena (uses environment configuration)
|
|
201
248
|
const athenaProvider = await getTdpAthenaProvider();
|
|
202
|
-
const data = await athenaProvider.query(
|
|
249
|
+
const data = await athenaProvider.query("SELECT * FROM files");
|
|
203
250
|
await athenaProvider.close();
|
|
204
251
|
```
|
|
205
252
|
|
|
@@ -211,15 +258,15 @@ import {
|
|
|
211
258
|
MissingTableError,
|
|
212
259
|
ProviderConnectionError,
|
|
213
260
|
InvalidProviderConfigurationError,
|
|
214
|
-
} from
|
|
261
|
+
} from "@tetrascience-npm/tetrascience-react-ui/server";
|
|
215
262
|
|
|
216
263
|
try {
|
|
217
|
-
const results = await provider.query(
|
|
264
|
+
const results = await provider.query("SELECT * FROM missing_table");
|
|
218
265
|
} catch (error) {
|
|
219
266
|
if (error instanceof MissingTableError) {
|
|
220
|
-
console.error(
|
|
267
|
+
console.error("Table not found:", error.message);
|
|
221
268
|
} else if (error instanceof QueryError) {
|
|
222
|
-
console.error(
|
|
269
|
+
console.error("Query failed:", error.message);
|
|
223
270
|
}
|
|
224
271
|
}
|
|
225
272
|
```
|
|
@@ -242,20 +289,20 @@ The TDP connector key/value store lets data apps persist small pieces of state (
|
|
|
242
289
|
**Reading and writing values with the user's JWT token:**
|
|
243
290
|
|
|
244
291
|
```typescript
|
|
245
|
-
import { TDPClient } from
|
|
246
|
-
import { jwtManager } from
|
|
292
|
+
import { TDPClient } from "@tetrascience-npm/ts-connectors-sdk";
|
|
293
|
+
import { jwtManager } from "@tetrascience-npm/tetrascience-react-ui/server";
|
|
247
294
|
|
|
248
295
|
// In an Express route handler:
|
|
249
|
-
app.get(
|
|
296
|
+
app.get("/api/kv/:key", async (req, res) => {
|
|
250
297
|
// 1. Get the user's JWT from request cookies
|
|
251
298
|
const userToken = await jwtManager.getTokenFromExpressRequest(req);
|
|
252
|
-
if (!userToken) return res.status(401).json({ error:
|
|
299
|
+
if (!userToken) return res.status(401).json({ error: "Not authenticated" });
|
|
253
300
|
|
|
254
301
|
// 2. Create a TDPClient authenticated as the user
|
|
255
302
|
// (CONNECTOR_ID, TDP_ENDPOINT, ORG_SLUG are read from env vars)
|
|
256
303
|
const client = new TDPClient({
|
|
257
304
|
authToken: userToken,
|
|
258
|
-
artifactType:
|
|
305
|
+
artifactType: "data-app",
|
|
259
306
|
});
|
|
260
307
|
await client.init();
|
|
261
308
|
|
|
@@ -264,13 +311,13 @@ app.get('/api/kv/:key', async (req, res) => {
|
|
|
264
311
|
res.json({ key: req.params.key, value });
|
|
265
312
|
});
|
|
266
313
|
|
|
267
|
-
app.put(
|
|
314
|
+
app.put("/api/kv/:key", async (req, res) => {
|
|
268
315
|
const userToken = await jwtManager.getTokenFromExpressRequest(req);
|
|
269
|
-
if (!userToken) return res.status(401).json({ error:
|
|
316
|
+
if (!userToken) return res.status(401).json({ error: "Not authenticated" });
|
|
270
317
|
|
|
271
318
|
const client = new TDPClient({
|
|
272
319
|
authToken: userToken,
|
|
273
|
-
artifactType:
|
|
320
|
+
artifactType: "data-app",
|
|
274
321
|
});
|
|
275
322
|
await client.init();
|
|
276
323
|
|
|
@@ -283,7 +330,7 @@ app.put('/api/kv/:key', async (req, res) => {
|
|
|
283
330
|
**Reading multiple values at once:**
|
|
284
331
|
|
|
285
332
|
```typescript
|
|
286
|
-
const values = await client.getValues([
|
|
333
|
+
const values = await client.getValues(["theme", "locale", "last-run"]);
|
|
287
334
|
// values[0] → theme, values[1] → locale, values[2] → last-run
|
|
288
335
|
```
|
|
289
336
|
|
|
@@ -315,8 +362,8 @@ Frontend: use `<TdpSearch columns={...} />` with default `apiEndpoint="/api/sear
|
|
|
315
362
|
Full TypeScript support with exported types:
|
|
316
363
|
|
|
317
364
|
```tsx
|
|
318
|
-
import { Button } from
|
|
319
|
-
import type { ButtonProps, BarGraphProps, BarDataSeries } from
|
|
365
|
+
import { Button } from "@tetrascience-npm/tetrascience-react-ui";
|
|
366
|
+
import type { ButtonProps, BarGraphProps, BarDataSeries } from "@tetrascience-npm/tetrascience-react-ui";
|
|
320
367
|
```
|
|
321
368
|
|
|
322
369
|
## Examples
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),x=require("lucide-react"),u=require("../../ui/button.cjs"),w=require("../../ui/input.cjs"),h=require("../../ui/popover.cjs"),n=require("../../ui/select.cjs"),z=require("../../../lib/utils.cjs"),P={contains:"contains",equals:"equals",not_equals:"not equals",starts_with:"starts with",ends_with:"ends with",is_empty:"is empty",is_not_empty:"is not empty"},R=["is_empty","is_not_empty"],f=["contains","equals","not_equals","starts_with","ends_with","is_empty","is_not_empty"];function O(r,d){const l=d?.[0]??"contains";return{id:crypto.randomUUID(),columnId:r,operator:l,value:""}}function A({columns:r,columnLabel:d,filters:l,onFiltersChange:o,triggerLabel:m="Filter",className:g}){const _=t=>d?.(t)??t,v=r[0],y=v?.columnId??"",C=()=>o([...l,O(y,v?.operators)]),I=t=>o(l.filter(c=>c.id!==t)),p=(t,c)=>o(l.map(a=>a.id===t?{...a,...c}:a)),N=()=>o([]),i=l.length;return e.jsxs(h.Popover,{children:[e.jsx(h.PopoverTrigger,{asChild:!0,children:e.jsxs(u.Button,{type:"button",variant:"outline",size:"sm","data-slot":"manifest-filter",className:z.cn(g),"aria-label":i>0?`${m} (${i} active)`:m,children:[e.jsx(x.ListFilterIcon,{className:"size-3.5"}),m,i>0?e.jsx("span",{className:"flex size-4 items-center justify-center rounded-full bg-primary text-[10px] font-medium text-primary-foreground",children:i}):null]})}),e.jsx(h.PopoverContent,{align:"end",className:"min-w-80",children:e.jsxs("div",{className:"flex flex-col gap-2",children:[l.map(t=>{const a=r.find(s=>s.columnId===t.columnId)?.operators??f,S=R.includes(t.operator);return e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs(n.Select,{value:t.columnId,onValueChange:s=>{const j=r.find(b=>b.columnId===s)?.operators??f,q=j.includes(t.operator)?t.operator:j[0]??"contains";p(t.id,{columnId:s,operator:q,value:""})},children:[e.jsx(n.SelectTrigger,{size:"sm",className:"w-36",children:e.jsx(n.SelectValue,{})}),e.jsx(n.SelectContent,{children:r.map(s=>e.jsx(n.SelectItem,{value:s.columnId,children:s.label??_(s.columnId)},s.columnId))})]}),e.jsxs(n.Select,{value:t.operator,onValueChange:s=>p(t.id,{operator:s,value:""}),children:[e.jsx(n.SelectTrigger,{size:"sm",className:"w-32",children:e.jsx(n.SelectValue,{})}),e.jsx(n.SelectContent,{children:a.map(s=>e.jsx(n.SelectItem,{value:s,children:P[s]},s))})]}),S?e.jsx("div",{className:"h-8 w-40","aria-hidden":!0}):e.jsx(w.Input,{className:"w-40",placeholder:"Value…",value:t.value,onChange:s=>p(t.id,{value:s.target.value})}),e.jsx(u.Button,{type:"button",variant:"ghost",size:"icon",className:"size-8 shrink-0 text-muted-foreground hover:text-foreground",onClick:()=>I(t.id),"aria-label":"Remove filter",children:e.jsx(x.XIcon,{className:"size-3.5"})})]},t.id)}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs(u.Button,{type:"button",variant:"outline",size:"sm",onClick:C,disabled:r.length===0,children:[e.jsx(x.PlusIcon,{className:"size-3.5"}),"Add filter"]}),l.length>0?e.jsx(u.Button,{type:"button",variant:"ghost",size:"sm",className:"text-muted-foreground",onClick:N,children:"Clear all"}):null]})]})})]})}exports.ManifestFilterPopover=A;
|
|
2
|
+
//# sourceMappingURL=ManifestFilterPopover.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ManifestFilterPopover.cjs","sources":["../../../../src/components/composed/PlateMapEditor/ManifestFilterPopover.tsx"],"sourcesContent":["import { ListFilterIcon, PlusIcon, XIcon } from \"lucide-react\";\n\nimport type { FilterColumnConfig, FilterCondition, FilterOperator } from \"@/components/ui/data-table/data-table\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@/components/ui/popover\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"@/components/ui/select\";\nimport { cn } from \"@/lib/utils\";\n\nconst OPERATOR_LABELS: Record<FilterOperator, string> = {\n contains: \"contains\",\n equals: \"equals\",\n not_equals: \"not equals\",\n starts_with: \"starts with\",\n ends_with: \"ends with\",\n is_empty: \"is empty\",\n is_not_empty: \"is not empty\",\n};\n\nconst VALUE_FREE_OPERATORS: FilterOperator[] = [\"is_empty\", \"is_not_empty\"];\n\nconst DEFAULT_OPERATORS: FilterOperator[] = [\n \"contains\",\n \"equals\",\n \"not_equals\",\n \"starts_with\",\n \"ends_with\",\n \"is_empty\",\n \"is_not_empty\",\n];\n\nfunction makeCondition(columnId: string, allowedOperators?: FilterOperator[]): FilterCondition {\n const operator = allowedOperators?.[0] ?? \"contains\";\n return { id: crypto.randomUUID(), columnId, operator, value: \"\" };\n}\n\nexport interface ManifestFilterPopoverProps {\n /** Filterable columns. Operator subsets can be specified per column. */\n columns: FilterColumnConfig[];\n /** Column id → display label resolver. */\n columnLabel?: (columnId: string) => string;\n filters: FilterCondition[];\n onFiltersChange: (next: FilterCondition[]) => void;\n triggerLabel?: string;\n className?: string;\n}\n\nexport function ManifestFilterPopover({\n columns,\n columnLabel,\n filters,\n onFiltersChange,\n triggerLabel = \"Filter\",\n className,\n}: ManifestFilterPopoverProps) {\n const labelFor = (columnId: string): string => columnLabel?.(columnId) ?? columnId;\n const firstColumn = columns[0];\n const firstColumnId = firstColumn?.columnId ?? \"\";\n\n const addFilter = () => onFiltersChange([...filters, makeCondition(firstColumnId, firstColumn?.operators)]);\n const removeFilter = (id: string) => onFiltersChange(filters.filter((cond) => cond.id !== id));\n const updateFilter = (id: string, patch: Partial<FilterCondition>) =>\n onFiltersChange(filters.map((cond) => (cond.id === id ? { ...cond, ...patch } : cond)));\n const clearAll = () => onFiltersChange([]);\n\n const activeCount = filters.length;\n\n return (\n <Popover>\n <PopoverTrigger asChild>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n data-slot=\"manifest-filter\"\n className={cn(className)}\n aria-label={activeCount > 0 ? `${triggerLabel} (${activeCount} active)` : triggerLabel}\n >\n <ListFilterIcon className=\"size-3.5\" />\n {triggerLabel}\n {activeCount > 0 ? (\n <span className=\"flex size-4 items-center justify-center rounded-full bg-primary text-[10px] font-medium text-primary-foreground\">\n {activeCount}\n </span>\n ) : null}\n </Button>\n </PopoverTrigger>\n\n <PopoverContent align=\"end\" className=\"min-w-80\">\n <div className=\"flex flex-col gap-2\">\n {filters.map((condition) => {\n const colConfig = columns.find((c) => c.columnId === condition.columnId);\n const operators = colConfig?.operators ?? DEFAULT_OPERATORS;\n const isValueFree = VALUE_FREE_OPERATORS.includes(condition.operator);\n return (\n <div key={condition.id} className=\"flex items-center gap-2\">\n <Select\n value={condition.columnId}\n onValueChange={(value) => {\n const nextConfig = columns.find((c) => c.columnId === value);\n const nextOperators = nextConfig?.operators ?? DEFAULT_OPERATORS;\n const nextOperator = nextOperators.includes(condition.operator)\n ? condition.operator\n : (nextOperators[0] ?? \"contains\");\n updateFilter(condition.id, { columnId: value, operator: nextOperator, value: \"\" });\n }}\n >\n <SelectTrigger size=\"sm\" className=\"w-36\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {columns.map((c) => (\n <SelectItem key={c.columnId} value={c.columnId}>\n {c.label ?? labelFor(c.columnId)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n\n <Select\n value={condition.operator}\n onValueChange={(value) =>\n updateFilter(condition.id, { operator: value as FilterOperator, value: \"\" })\n }\n >\n <SelectTrigger size=\"sm\" className=\"w-32\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {operators.map((op) => (\n <SelectItem key={op} value={op}>\n {OPERATOR_LABELS[op]}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n\n {isValueFree ? (\n <div className=\"h-8 w-40\" aria-hidden />\n ) : (\n <Input\n className=\"w-40\"\n placeholder=\"Value…\"\n value={condition.value}\n onChange={(event) => updateFilter(condition.id, { value: event.target.value })}\n />\n )}\n\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-8 shrink-0 text-muted-foreground hover:text-foreground\"\n onClick={() => removeFilter(condition.id)}\n aria-label=\"Remove filter\"\n >\n <XIcon className=\"size-3.5\" />\n </Button>\n </div>\n );\n })}\n\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={addFilter}\n disabled={columns.length === 0}\n >\n <PlusIcon className=\"size-3.5\" />\n Add filter\n </Button>\n {filters.length > 0 ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"text-muted-foreground\"\n onClick={clearAll}\n >\n Clear all\n </Button>\n ) : null}\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n"],"names":["OPERATOR_LABELS","VALUE_FREE_OPERATORS","DEFAULT_OPERATORS","makeCondition","columnId","allowedOperators","operator","ManifestFilterPopover","columns","columnLabel","filters","onFiltersChange","triggerLabel","className","labelFor","firstColumn","firstColumnId","addFilter","removeFilter","id","cond","updateFilter","patch","clearAll","activeCount","Popover","jsx","PopoverTrigger","jsxs","Button","cn","ListFilterIcon","PopoverContent","condition","operators","c","isValueFree","Select","value","nextOperators","nextOperator","SelectTrigger","SelectValue","SelectContent","SelectItem","op","Input","event","XIcon","PlusIcon"],"mappings":"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"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { jsxs as l, jsx as t } from "react/jsx-runtime";
|
|
2
|
+
import { ListFilterIcon as R, XIcon as S, PlusIcon as F } from "lucide-react";
|
|
3
|
+
import { Button as m } from "../../ui/button.js";
|
|
4
|
+
import { Input as q } from "../../ui/input.js";
|
|
5
|
+
import { Popover as T, PopoverTrigger as V, PopoverContent as k } from "../../ui/popover.js";
|
|
6
|
+
import { Select as v, SelectTrigger as g, SelectValue as _, SelectContent as x, SelectItem as y } from "../../ui/select.js";
|
|
7
|
+
import { cn as U } from "../../../lib/utils.js";
|
|
8
|
+
const j = {
|
|
9
|
+
contains: "contains",
|
|
10
|
+
equals: "equals",
|
|
11
|
+
not_equals: "not equals",
|
|
12
|
+
starts_with: "starts with",
|
|
13
|
+
ends_with: "ends with",
|
|
14
|
+
is_empty: "is empty",
|
|
15
|
+
is_not_empty: "is not empty"
|
|
16
|
+
}, L = ["is_empty", "is_not_empty"], C = [
|
|
17
|
+
"contains",
|
|
18
|
+
"equals",
|
|
19
|
+
"not_equals",
|
|
20
|
+
"starts_with",
|
|
21
|
+
"ends_with",
|
|
22
|
+
"is_empty",
|
|
23
|
+
"is_not_empty"
|
|
24
|
+
];
|
|
25
|
+
function B(n, u) {
|
|
26
|
+
const r = u?.[0] ?? "contains";
|
|
27
|
+
return { id: crypto.randomUUID(), columnId: n, operator: r, value: "" };
|
|
28
|
+
}
|
|
29
|
+
function Q({
|
|
30
|
+
columns: n,
|
|
31
|
+
columnLabel: u,
|
|
32
|
+
filters: r,
|
|
33
|
+
onFiltersChange: o,
|
|
34
|
+
triggerLabel: d = "Filter",
|
|
35
|
+
className: I
|
|
36
|
+
}) {
|
|
37
|
+
const N = (e) => u?.(e) ?? e, h = n[0], w = h?.columnId ?? "", z = () => o([...r, B(w, h?.operators)]), b = (e) => o(r.filter((c) => c.id !== e)), p = (e, c) => o(r.map((s) => s.id === e ? { ...s, ...c } : s)), A = () => o([]), i = r.length;
|
|
38
|
+
return /* @__PURE__ */ l(T, { children: [
|
|
39
|
+
/* @__PURE__ */ t(V, { asChild: !0, children: /* @__PURE__ */ l(
|
|
40
|
+
m,
|
|
41
|
+
{
|
|
42
|
+
type: "button",
|
|
43
|
+
variant: "outline",
|
|
44
|
+
size: "sm",
|
|
45
|
+
"data-slot": "manifest-filter",
|
|
46
|
+
className: U(I),
|
|
47
|
+
"aria-label": i > 0 ? `${d} (${i} active)` : d,
|
|
48
|
+
children: [
|
|
49
|
+
/* @__PURE__ */ t(R, { className: "size-3.5" }),
|
|
50
|
+
d,
|
|
51
|
+
i > 0 ? /* @__PURE__ */ t("span", { className: "flex size-4 items-center justify-center rounded-full bg-primary text-[10px] font-medium text-primary-foreground", children: i }) : null
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
) }),
|
|
55
|
+
/* @__PURE__ */ t(k, { align: "end", className: "min-w-80", children: /* @__PURE__ */ l("div", { className: "flex flex-col gap-2", children: [
|
|
56
|
+
r.map((e) => {
|
|
57
|
+
const s = n.find((a) => a.columnId === e.columnId)?.operators ?? C, E = L.includes(e.operator);
|
|
58
|
+
return /* @__PURE__ */ l("div", { className: "flex items-center gap-2", children: [
|
|
59
|
+
/* @__PURE__ */ l(
|
|
60
|
+
v,
|
|
61
|
+
{
|
|
62
|
+
value: e.columnId,
|
|
63
|
+
onValueChange: (a) => {
|
|
64
|
+
const f = n.find((P) => P.columnId === a)?.operators ?? C, O = f.includes(e.operator) ? e.operator : f[0] ?? "contains";
|
|
65
|
+
p(e.id, { columnId: a, operator: O, value: "" });
|
|
66
|
+
},
|
|
67
|
+
children: [
|
|
68
|
+
/* @__PURE__ */ t(g, { size: "sm", className: "w-36", children: /* @__PURE__ */ t(_, {}) }),
|
|
69
|
+
/* @__PURE__ */ t(x, { children: n.map((a) => /* @__PURE__ */ t(y, { value: a.columnId, children: a.label ?? N(a.columnId) }, a.columnId)) })
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
),
|
|
73
|
+
/* @__PURE__ */ l(
|
|
74
|
+
v,
|
|
75
|
+
{
|
|
76
|
+
value: e.operator,
|
|
77
|
+
onValueChange: (a) => p(e.id, { operator: a, value: "" }),
|
|
78
|
+
children: [
|
|
79
|
+
/* @__PURE__ */ t(g, { size: "sm", className: "w-32", children: /* @__PURE__ */ t(_, {}) }),
|
|
80
|
+
/* @__PURE__ */ t(x, { children: s.map((a) => /* @__PURE__ */ t(y, { value: a, children: j[a] }, a)) })
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
),
|
|
84
|
+
E ? /* @__PURE__ */ t("div", { className: "h-8 w-40", "aria-hidden": !0 }) : /* @__PURE__ */ t(
|
|
85
|
+
q,
|
|
86
|
+
{
|
|
87
|
+
className: "w-40",
|
|
88
|
+
placeholder: "Value…",
|
|
89
|
+
value: e.value,
|
|
90
|
+
onChange: (a) => p(e.id, { value: a.target.value })
|
|
91
|
+
}
|
|
92
|
+
),
|
|
93
|
+
/* @__PURE__ */ t(
|
|
94
|
+
m,
|
|
95
|
+
{
|
|
96
|
+
type: "button",
|
|
97
|
+
variant: "ghost",
|
|
98
|
+
size: "icon",
|
|
99
|
+
className: "size-8 shrink-0 text-muted-foreground hover:text-foreground",
|
|
100
|
+
onClick: () => b(e.id),
|
|
101
|
+
"aria-label": "Remove filter",
|
|
102
|
+
children: /* @__PURE__ */ t(S, { className: "size-3.5" })
|
|
103
|
+
}
|
|
104
|
+
)
|
|
105
|
+
] }, e.id);
|
|
106
|
+
}),
|
|
107
|
+
/* @__PURE__ */ l("div", { className: "flex items-center gap-2", children: [
|
|
108
|
+
/* @__PURE__ */ l(
|
|
109
|
+
m,
|
|
110
|
+
{
|
|
111
|
+
type: "button",
|
|
112
|
+
variant: "outline",
|
|
113
|
+
size: "sm",
|
|
114
|
+
onClick: z,
|
|
115
|
+
disabled: n.length === 0,
|
|
116
|
+
children: [
|
|
117
|
+
/* @__PURE__ */ t(F, { className: "size-3.5" }),
|
|
118
|
+
"Add filter"
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
),
|
|
122
|
+
r.length > 0 ? /* @__PURE__ */ t(
|
|
123
|
+
m,
|
|
124
|
+
{
|
|
125
|
+
type: "button",
|
|
126
|
+
variant: "ghost",
|
|
127
|
+
size: "sm",
|
|
128
|
+
className: "text-muted-foreground",
|
|
129
|
+
onClick: A,
|
|
130
|
+
children: "Clear all"
|
|
131
|
+
}
|
|
132
|
+
) : null
|
|
133
|
+
] })
|
|
134
|
+
] }) })
|
|
135
|
+
] });
|
|
136
|
+
}
|
|
137
|
+
export {
|
|
138
|
+
Q as ManifestFilterPopover
|
|
139
|
+
};
|
|
140
|
+
//# sourceMappingURL=ManifestFilterPopover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ManifestFilterPopover.js","sources":["../../../../src/components/composed/PlateMapEditor/ManifestFilterPopover.tsx"],"sourcesContent":["import { ListFilterIcon, PlusIcon, XIcon } from \"lucide-react\";\n\nimport type { FilterColumnConfig, FilterCondition, FilterOperator } from \"@/components/ui/data-table/data-table\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@/components/ui/popover\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"@/components/ui/select\";\nimport { cn } from \"@/lib/utils\";\n\nconst OPERATOR_LABELS: Record<FilterOperator, string> = {\n contains: \"contains\",\n equals: \"equals\",\n not_equals: \"not equals\",\n starts_with: \"starts with\",\n ends_with: \"ends with\",\n is_empty: \"is empty\",\n is_not_empty: \"is not empty\",\n};\n\nconst VALUE_FREE_OPERATORS: FilterOperator[] = [\"is_empty\", \"is_not_empty\"];\n\nconst DEFAULT_OPERATORS: FilterOperator[] = [\n \"contains\",\n \"equals\",\n \"not_equals\",\n \"starts_with\",\n \"ends_with\",\n \"is_empty\",\n \"is_not_empty\",\n];\n\nfunction makeCondition(columnId: string, allowedOperators?: FilterOperator[]): FilterCondition {\n const operator = allowedOperators?.[0] ?? \"contains\";\n return { id: crypto.randomUUID(), columnId, operator, value: \"\" };\n}\n\nexport interface ManifestFilterPopoverProps {\n /** Filterable columns. Operator subsets can be specified per column. */\n columns: FilterColumnConfig[];\n /** Column id → display label resolver. */\n columnLabel?: (columnId: string) => string;\n filters: FilterCondition[];\n onFiltersChange: (next: FilterCondition[]) => void;\n triggerLabel?: string;\n className?: string;\n}\n\nexport function ManifestFilterPopover({\n columns,\n columnLabel,\n filters,\n onFiltersChange,\n triggerLabel = \"Filter\",\n className,\n}: ManifestFilterPopoverProps) {\n const labelFor = (columnId: string): string => columnLabel?.(columnId) ?? columnId;\n const firstColumn = columns[0];\n const firstColumnId = firstColumn?.columnId ?? \"\";\n\n const addFilter = () => onFiltersChange([...filters, makeCondition(firstColumnId, firstColumn?.operators)]);\n const removeFilter = (id: string) => onFiltersChange(filters.filter((cond) => cond.id !== id));\n const updateFilter = (id: string, patch: Partial<FilterCondition>) =>\n onFiltersChange(filters.map((cond) => (cond.id === id ? { ...cond, ...patch } : cond)));\n const clearAll = () => onFiltersChange([]);\n\n const activeCount = filters.length;\n\n return (\n <Popover>\n <PopoverTrigger asChild>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n data-slot=\"manifest-filter\"\n className={cn(className)}\n aria-label={activeCount > 0 ? `${triggerLabel} (${activeCount} active)` : triggerLabel}\n >\n <ListFilterIcon className=\"size-3.5\" />\n {triggerLabel}\n {activeCount > 0 ? (\n <span className=\"flex size-4 items-center justify-center rounded-full bg-primary text-[10px] font-medium text-primary-foreground\">\n {activeCount}\n </span>\n ) : null}\n </Button>\n </PopoverTrigger>\n\n <PopoverContent align=\"end\" className=\"min-w-80\">\n <div className=\"flex flex-col gap-2\">\n {filters.map((condition) => {\n const colConfig = columns.find((c) => c.columnId === condition.columnId);\n const operators = colConfig?.operators ?? DEFAULT_OPERATORS;\n const isValueFree = VALUE_FREE_OPERATORS.includes(condition.operator);\n return (\n <div key={condition.id} className=\"flex items-center gap-2\">\n <Select\n value={condition.columnId}\n onValueChange={(value) => {\n const nextConfig = columns.find((c) => c.columnId === value);\n const nextOperators = nextConfig?.operators ?? DEFAULT_OPERATORS;\n const nextOperator = nextOperators.includes(condition.operator)\n ? condition.operator\n : (nextOperators[0] ?? \"contains\");\n updateFilter(condition.id, { columnId: value, operator: nextOperator, value: \"\" });\n }}\n >\n <SelectTrigger size=\"sm\" className=\"w-36\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {columns.map((c) => (\n <SelectItem key={c.columnId} value={c.columnId}>\n {c.label ?? labelFor(c.columnId)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n\n <Select\n value={condition.operator}\n onValueChange={(value) =>\n updateFilter(condition.id, { operator: value as FilterOperator, value: \"\" })\n }\n >\n <SelectTrigger size=\"sm\" className=\"w-32\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {operators.map((op) => (\n <SelectItem key={op} value={op}>\n {OPERATOR_LABELS[op]}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n\n {isValueFree ? (\n <div className=\"h-8 w-40\" aria-hidden />\n ) : (\n <Input\n className=\"w-40\"\n placeholder=\"Value…\"\n value={condition.value}\n onChange={(event) => updateFilter(condition.id, { value: event.target.value })}\n />\n )}\n\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-8 shrink-0 text-muted-foreground hover:text-foreground\"\n onClick={() => removeFilter(condition.id)}\n aria-label=\"Remove filter\"\n >\n <XIcon className=\"size-3.5\" />\n </Button>\n </div>\n );\n })}\n\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={addFilter}\n disabled={columns.length === 0}\n >\n <PlusIcon className=\"size-3.5\" />\n Add filter\n </Button>\n {filters.length > 0 ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"text-muted-foreground\"\n onClick={clearAll}\n >\n Clear all\n </Button>\n ) : null}\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n"],"names":["OPERATOR_LABELS","VALUE_FREE_OPERATORS","DEFAULT_OPERATORS","makeCondition","columnId","allowedOperators","operator","ManifestFilterPopover","columns","columnLabel","filters","onFiltersChange","triggerLabel","className","labelFor","firstColumn","firstColumnId","addFilter","removeFilter","id","cond","updateFilter","patch","clearAll","activeCount","Popover","jsx","PopoverTrigger","jsxs","Button","cn","ListFilterIcon","PopoverContent","condition","operators","c","isValueFree","Select","value","nextOperators","nextOperator","SelectTrigger","SelectValue","SelectContent","SelectItem","op","Input","event","XIcon","PlusIcon"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),d=require("lucide-react"),C=require("react"),A=require("./csvPlateTriage.cjs"),F=require("./helpers.cjs"),I=require("../../ui/button.cjs"),n=require("../../ui/dropdown-menu.cjs"),z=require("../../../lib/utils.cjs");function _(t){const a=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t){for(const r in t)if(r!=="default"){const i=Object.getOwnPropertyDescriptor(t,r);Object.defineProperty(a,r,i.get?i:{enumerable:!0,get:()=>t[r]})}}return a.default=t,Object.freeze(a)}const x=_(C);function b({inputRef:t,accept:a,onPick:r,triageCsv:i}){return e.jsx("input",{ref:t,type:"file",accept:a,hidden:!0,onChange:o=>{const u=o.currentTarget,s=o.target.files?.[0];if(!s){u.value="";return}(async()=>{const c=i?await A.triagePlateMapCsvFile(s):void 0;await(c?r?.(s,c):r?.(s)),u.value=""})()}})}function G({templates:t,templateId:a,onTemplateChange:r,onClearTemplate:i,hasEntries:o,onImportCsv:u,onExportCsv:s,onImportTemplate:c,onExportTemplate:j,label:g="Actions",align:D="start",side:m="bottom",csvAccept:S=".csv,text/csv",templateAccept:k="application/json",importTemplateLabel:y="Import template (JSON)",exportTemplateLabel:R="Save template",importCsvLabel:v="Import plate map (CSV)",exportCsvLabel:q="Export plate map (CSV)",clearLabel:N="Clear template",className:O}){const f=x.useRef(null),M=x.useRef(null),h=x.useMemo(()=>F.groupTemplateOptions(t),[t]),w=o===!1;return h.length>0||!!c||!!j||!!u||!!s||!!i?e.jsxs(e.Fragment,{children:[e.jsxs(n.DropdownMenu,{children:[e.jsx(n.DropdownMenuTrigger,{asChild:!0,children:e.jsxs(I.Button,{type:"button",variant:"outline",size:"sm",className:z.cn("min-w-24 justify-between",O),children:[e.jsx("span",{children:g}),e.jsx(d.ChevronDown,{"aria-hidden":!0})]})}),e.jsxs(n.DropdownMenuContent,{align:D,side:m,className:"w-64",children:[h.map(([p,P])=>e.jsxs(n.DropdownMenuGroup,{children:[p?e.jsx(n.DropdownMenuLabel,{children:p}):null,P.map(l=>e.jsxs(n.DropdownMenuItem,{disabled:l.disabled,onClick:()=>r?.(l.id),children:[l.id===a?e.jsx(d.Check,{"aria-hidden":!0}):e.jsx("span",{className:"size-4","aria-hidden":!0}),e.jsxs("span",{className:"flex min-w-0 flex-col",children:[e.jsx("span",{className:"truncate",children:l.label}),l.description?e.jsx("span",{className:"truncate text-xs text-muted-foreground",children:l.description}):null]})]},l.id))]},p||"templates")),h.length>0&&(c||j||u||s||i)?e.jsx(n.DropdownMenuSeparator,{}):null,c?e.jsxs(n.DropdownMenuItem,{onClick:()=>f.current?.click(),children:[e.jsx(d.LayoutTemplate,{"aria-hidden":!0}),y]}):null,j?e.jsxs(n.DropdownMenuItem,{disabled:w,onClick:()=>j(),children:[e.jsx(d.SaveAll,{"aria-hidden":!0}),R]}):null,(c||j)&&(u||s)?e.jsx(n.DropdownMenuSeparator,{}):null,u?e.jsxs(n.DropdownMenuItem,{onClick:()=>M.current?.click(),children:[e.jsx(d.Upload,{"aria-hidden":!0}),v]}):null,s?e.jsxs(n.DropdownMenuItem,{disabled:w,onClick:()=>s(),children:[e.jsx(d.Download,{"aria-hidden":!0}),q]}):null,i?e.jsxs(e.Fragment,{children:[e.jsx(n.DropdownMenuSeparator,{}),e.jsxs(n.DropdownMenuItem,{variant:"destructive",disabled:!a&&!o,onClick:()=>i(),children:[e.jsx(d.Trash2,{"aria-hidden":!0}),N]})]}):null]})]}),e.jsx(b,{inputRef:f,accept:k,onPick:c}),e.jsx(b,{inputRef:M,accept:S,onPick:u,triageCsv:!0})]}):null}exports.PlateMapActionsMenu=G;
|
|
2
|
+
//# sourceMappingURL=PlateMapActionsMenu.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PlateMapActionsMenu.cjs","sources":["../../../../src/components/composed/PlateMapEditor/PlateMapActionsMenu.tsx"],"sourcesContent":["import { Check, ChevronDown, Download, LayoutTemplate, SaveAll, Trash2, Upload } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { triagePlateMapCsvFile } from \"./csvPlateTriage\";\nimport { groupTemplateOptions } from \"./helpers\";\n\nimport type { ImportExportHandlers, PlateMapCsvTriage, TemplateOption } from \"./types\";\n\nimport { Button } from \"@/components/ui/button\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface PlateMapActionsMenuProps extends ImportExportHandlers {\n templates?: TemplateOption[];\n templateId?: string;\n onTemplateChange?: (id: string) => void;\n onClearTemplate?: () => void;\n /** Disable export/save actions when there is nothing to export. */\n hasEntries?: boolean;\n label?: React.ReactNode;\n align?: \"start\" | \"center\" | \"end\";\n side?: \"top\" | \"right\" | \"bottom\" | \"left\";\n csvAccept?: string;\n templateAccept?: string;\n importTemplateLabel?: string;\n exportTemplateLabel?: string;\n importCsvLabel?: string;\n exportCsvLabel?: string;\n clearLabel?: string;\n className?: string;\n}\n\nfunction HiddenFileInput({\n inputRef,\n accept,\n onPick,\n triageCsv,\n}: {\n inputRef: React.RefObject<HTMLInputElement | null>;\n accept: string;\n onPick?: (file: File, triage?: PlateMapCsvTriage) => void | Promise<void>;\n triageCsv?: boolean;\n}) {\n return (\n <input\n ref={inputRef}\n type=\"file\"\n accept={accept}\n hidden\n onChange={(event) => {\n const input = event.currentTarget;\n const file = event.target.files?.[0];\n if (!file) {\n input.value = \"\";\n return;\n }\n\n void (async () => {\n const triage = triageCsv ? await triagePlateMapCsvFile(file) : undefined;\n await (triage ? onPick?.(file, triage) : onPick?.(file));\n input.value = \"\";\n })();\n }}\n />\n );\n}\n\nexport function PlateMapActionsMenu({\n templates,\n templateId,\n onTemplateChange,\n onClearTemplate,\n hasEntries,\n onImportCsv,\n onExportCsv,\n onImportTemplate,\n onExportTemplate,\n label = \"Actions\",\n align = \"start\",\n side = \"bottom\",\n csvAccept = \".csv,text/csv\",\n templateAccept = \"application/json\",\n importTemplateLabel = \"Import template (JSON)\",\n exportTemplateLabel = \"Save template\",\n importCsvLabel = \"Import plate map (CSV)\",\n exportCsvLabel = \"Export plate map (CSV)\",\n clearLabel = \"Clear template\",\n className,\n}: PlateMapActionsMenuProps) {\n const templateInputRef = React.useRef<HTMLInputElement>(null);\n const csvInputRef = React.useRef<HTMLInputElement>(null);\n const templateGroups = React.useMemo(() => groupTemplateOptions(templates), [templates]);\n const disableEntryExport = hasEntries === false;\n\n const hasMenuItems =\n templateGroups.length > 0 ||\n !!onImportTemplate ||\n !!onExportTemplate ||\n !!onImportCsv ||\n !!onExportCsv ||\n !!onClearTemplate;\n\n if (!hasMenuItems) return null;\n\n return (\n <>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" className={cn(\"min-w-24 justify-between\", className)}>\n <span>{label}</span>\n <ChevronDown aria-hidden />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align={align} side={side} className=\"w-64\">\n {templateGroups.map(([group, options]) => (\n <DropdownMenuGroup key={group || \"templates\"}>\n {group ? <DropdownMenuLabel>{group}</DropdownMenuLabel> : null}\n {options.map((template) => (\n <DropdownMenuItem\n key={template.id}\n disabled={template.disabled}\n onClick={() => onTemplateChange?.(template.id)}\n >\n {template.id === templateId ? <Check aria-hidden /> : <span className=\"size-4\" aria-hidden />}\n <span className=\"flex min-w-0 flex-col\">\n <span className=\"truncate\">{template.label}</span>\n {template.description ? (\n <span className=\"truncate text-xs text-muted-foreground\">{template.description}</span>\n ) : null}\n </span>\n </DropdownMenuItem>\n ))}\n </DropdownMenuGroup>\n ))}\n\n {templateGroups.length > 0 &&\n (onImportTemplate || onExportTemplate || onImportCsv || onExportCsv || onClearTemplate) ? (\n <DropdownMenuSeparator />\n ) : null}\n\n {onImportTemplate ? (\n <DropdownMenuItem onClick={() => templateInputRef.current?.click()}>\n <LayoutTemplate aria-hidden />\n {importTemplateLabel}\n </DropdownMenuItem>\n ) : null}\n {onExportTemplate ? (\n <DropdownMenuItem disabled={disableEntryExport} onClick={() => onExportTemplate()}>\n <SaveAll aria-hidden />\n {exportTemplateLabel}\n </DropdownMenuItem>\n ) : null}\n\n {(onImportTemplate || onExportTemplate) && (onImportCsv || onExportCsv) ? <DropdownMenuSeparator /> : null}\n\n {onImportCsv ? (\n <DropdownMenuItem onClick={() => csvInputRef.current?.click()}>\n <Upload aria-hidden />\n {importCsvLabel}\n </DropdownMenuItem>\n ) : null}\n {onExportCsv ? (\n <DropdownMenuItem disabled={disableEntryExport} onClick={() => onExportCsv()}>\n <Download aria-hidden />\n {exportCsvLabel}\n </DropdownMenuItem>\n ) : null}\n\n {onClearTemplate ? (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuItem\n variant=\"destructive\"\n disabled={!templateId && !hasEntries}\n onClick={() => onClearTemplate()}\n >\n <Trash2 aria-hidden />\n {clearLabel}\n </DropdownMenuItem>\n </>\n ) : null}\n </DropdownMenuContent>\n </DropdownMenu>\n <HiddenFileInput inputRef={templateInputRef} accept={templateAccept} onPick={onImportTemplate} />\n <HiddenFileInput inputRef={csvInputRef} accept={csvAccept} onPick={onImportCsv} triageCsv />\n </>\n );\n}\n"],"names":["HiddenFileInput","inputRef","accept","onPick","triageCsv","jsx","event","input","file","triage","triagePlateMapCsvFile","PlateMapActionsMenu","templates","templateId","onTemplateChange","onClearTemplate","hasEntries","onImportCsv","onExportCsv","onImportTemplate","onExportTemplate","label","align","side","csvAccept","templateAccept","importTemplateLabel","exportTemplateLabel","importCsvLabel","exportCsvLabel","clearLabel","className","templateInputRef","React","csvInputRef","templateGroups","groupTemplateOptions","disableEntryExport","jsxs","Fragment","DropdownMenu","DropdownMenuTrigger","Button","cn","ChevronDown","DropdownMenuContent","group","options","DropdownMenuGroup","DropdownMenuLabel","template","DropdownMenuItem","Check","DropdownMenuSeparator","LayoutTemplate","SaveAll","Upload","Download","Trash2"],"mappings":"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"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { jsxs as n, Fragment as k, jsx as e } from "react/jsx-runtime";
|
|
2
|
+
import { ChevronDown as G, Check as L, LayoutTemplate as O, SaveAll as V, Upload as B, Download as H, Trash2 as J } from "lucide-react";
|
|
3
|
+
import * as m from "react";
|
|
4
|
+
import { triagePlateMapCsvFile as U } from "./csvPlateTriage.js";
|
|
5
|
+
import { groupTemplateOptions as q } from "./helpers.js";
|
|
6
|
+
import { Button as K } from "../../ui/button.js";
|
|
7
|
+
import { DropdownMenu as Q, DropdownMenuTrigger as W, DropdownMenuContent as X, DropdownMenuGroup as Y, DropdownMenuLabel as Z, DropdownMenuItem as c, DropdownMenuSeparator as w } from "../../ui/dropdown-menu.js";
|
|
8
|
+
import { cn as _ } from "../../../lib/utils.js";
|
|
9
|
+
function D({
|
|
10
|
+
inputRef: s,
|
|
11
|
+
accept: o,
|
|
12
|
+
onPick: h,
|
|
13
|
+
triageCsv: l
|
|
14
|
+
}) {
|
|
15
|
+
return /* @__PURE__ */ e(
|
|
16
|
+
"input",
|
|
17
|
+
{
|
|
18
|
+
ref: s,
|
|
19
|
+
type: "file",
|
|
20
|
+
accept: o,
|
|
21
|
+
hidden: !0,
|
|
22
|
+
onChange: (d) => {
|
|
23
|
+
const r = d.currentTarget, i = d.target.files?.[0];
|
|
24
|
+
if (!i) {
|
|
25
|
+
r.value = "";
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
(async () => {
|
|
29
|
+
const t = l ? await U(i) : void 0;
|
|
30
|
+
await (t ? h?.(i, t) : h?.(i)), r.value = "";
|
|
31
|
+
})();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
function te({
|
|
37
|
+
templates: s,
|
|
38
|
+
templateId: o,
|
|
39
|
+
onTemplateChange: h,
|
|
40
|
+
onClearTemplate: l,
|
|
41
|
+
hasEntries: d,
|
|
42
|
+
onImportCsv: r,
|
|
43
|
+
onExportCsv: i,
|
|
44
|
+
onImportTemplate: t,
|
|
45
|
+
onExportTemplate: u,
|
|
46
|
+
label: N = "Actions",
|
|
47
|
+
align: R = "start",
|
|
48
|
+
side: v = "bottom",
|
|
49
|
+
csvAccept: y = ".csv,text/csv",
|
|
50
|
+
templateAccept: S = "application/json",
|
|
51
|
+
importTemplateLabel: C = "Import template (JSON)",
|
|
52
|
+
exportTemplateLabel: j = "Save template",
|
|
53
|
+
importCsvLabel: x = "Import plate map (CSV)",
|
|
54
|
+
exportCsvLabel: A = "Export plate map (CSV)",
|
|
55
|
+
clearLabel: F = "Clear template",
|
|
56
|
+
className: P
|
|
57
|
+
}) {
|
|
58
|
+
const M = m.useRef(null), b = m.useRef(null), f = m.useMemo(() => q(s), [s]), g = d === !1;
|
|
59
|
+
return f.length > 0 || !!t || !!u || !!r || !!i || !!l ? /* @__PURE__ */ n(k, { children: [
|
|
60
|
+
/* @__PURE__ */ n(Q, { children: [
|
|
61
|
+
/* @__PURE__ */ e(W, { asChild: !0, children: /* @__PURE__ */ n(K, { type: "button", variant: "outline", size: "sm", className: _("min-w-24 justify-between", P), children: [
|
|
62
|
+
/* @__PURE__ */ e("span", { children: N }),
|
|
63
|
+
/* @__PURE__ */ e(G, { "aria-hidden": !0 })
|
|
64
|
+
] }) }),
|
|
65
|
+
/* @__PURE__ */ n(X, { align: R, side: v, className: "w-64", children: [
|
|
66
|
+
f.map(([p, z]) => /* @__PURE__ */ n(Y, { children: [
|
|
67
|
+
p ? /* @__PURE__ */ e(Z, { children: p }) : null,
|
|
68
|
+
z.map((a) => /* @__PURE__ */ n(
|
|
69
|
+
c,
|
|
70
|
+
{
|
|
71
|
+
disabled: a.disabled,
|
|
72
|
+
onClick: () => h?.(a.id),
|
|
73
|
+
children: [
|
|
74
|
+
a.id === o ? /* @__PURE__ */ e(L, { "aria-hidden": !0 }) : /* @__PURE__ */ e("span", { className: "size-4", "aria-hidden": !0 }),
|
|
75
|
+
/* @__PURE__ */ n("span", { className: "flex min-w-0 flex-col", children: [
|
|
76
|
+
/* @__PURE__ */ e("span", { className: "truncate", children: a.label }),
|
|
77
|
+
a.description ? /* @__PURE__ */ e("span", { className: "truncate text-xs text-muted-foreground", children: a.description }) : null
|
|
78
|
+
] })
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
a.id
|
|
82
|
+
))
|
|
83
|
+
] }, p || "templates")),
|
|
84
|
+
f.length > 0 && (t || u || r || i || l) ? /* @__PURE__ */ e(w, {}) : null,
|
|
85
|
+
t ? /* @__PURE__ */ n(c, { onClick: () => M.current?.click(), children: [
|
|
86
|
+
/* @__PURE__ */ e(O, { "aria-hidden": !0 }),
|
|
87
|
+
C
|
|
88
|
+
] }) : null,
|
|
89
|
+
u ? /* @__PURE__ */ n(c, { disabled: g, onClick: () => u(), children: [
|
|
90
|
+
/* @__PURE__ */ e(V, { "aria-hidden": !0 }),
|
|
91
|
+
j
|
|
92
|
+
] }) : null,
|
|
93
|
+
(t || u) && (r || i) ? /* @__PURE__ */ e(w, {}) : null,
|
|
94
|
+
r ? /* @__PURE__ */ n(c, { onClick: () => b.current?.click(), children: [
|
|
95
|
+
/* @__PURE__ */ e(B, { "aria-hidden": !0 }),
|
|
96
|
+
x
|
|
97
|
+
] }) : null,
|
|
98
|
+
i ? /* @__PURE__ */ n(c, { disabled: g, onClick: () => i(), children: [
|
|
99
|
+
/* @__PURE__ */ e(H, { "aria-hidden": !0 }),
|
|
100
|
+
A
|
|
101
|
+
] }) : null,
|
|
102
|
+
l ? /* @__PURE__ */ n(k, { children: [
|
|
103
|
+
/* @__PURE__ */ e(w, {}),
|
|
104
|
+
/* @__PURE__ */ n(
|
|
105
|
+
c,
|
|
106
|
+
{
|
|
107
|
+
variant: "destructive",
|
|
108
|
+
disabled: !o && !d,
|
|
109
|
+
onClick: () => l(),
|
|
110
|
+
children: [
|
|
111
|
+
/* @__PURE__ */ e(J, { "aria-hidden": !0 }),
|
|
112
|
+
F
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
] }) : null
|
|
117
|
+
] })
|
|
118
|
+
] }),
|
|
119
|
+
/* @__PURE__ */ e(D, { inputRef: M, accept: S, onPick: t }),
|
|
120
|
+
/* @__PURE__ */ e(D, { inputRef: b, accept: y, onPick: r, triageCsv: !0 })
|
|
121
|
+
] }) : null;
|
|
122
|
+
}
|
|
123
|
+
export {
|
|
124
|
+
te as PlateMapActionsMenu
|
|
125
|
+
};
|
|
126
|
+
//# sourceMappingURL=PlateMapActionsMenu.js.map
|