@things-factory/dataset 9.1.18 → 10.0.0-beta.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/EXPLORATION_INDEX.md +252 -0
- package/FRONTEND_ARCHITECTURE.md +732 -0
- package/QUICK_REFERENCE.md +365 -0
- package/dist-client/pages/data-archive/data-archive-list-page.d.ts +1 -7
- package/dist-client/pages/data-archive/data-archive-list-page.js +42 -77
- package/dist-client/pages/data-archive/data-archive-list-page.js.map +1 -1
- package/dist-client/pages/data-entry/data-entry-list-page.d.ts +1 -7
- package/dist-client/pages/data-entry/data-entry-list-page.js +77 -143
- package/dist-client/pages/data-entry/data-entry-list-page.js.map +1 -1
- package/dist-client/pages/data-key-set/data-key-set-list-page.d.ts +1 -7
- package/dist-client/pages/data-key-set/data-key-set-list-page.js +69 -131
- package/dist-client/pages/data-key-set/data-key-set-list-page.js.map +1 -1
- package/dist-client/pages/data-ooc/data-ooc-list-page.d.ts +0 -6
- package/dist-client/pages/data-ooc/data-ooc-list-page.js +87 -166
- package/dist-client/pages/data-ooc/data-ooc-list-page.js.map +1 -1
- package/dist-client/pages/data-report/data-report-list-page.d.ts +1 -7
- package/dist-client/pages/data-report/data-report-list-page.js +71 -132
- package/dist-client/pages/data-report/data-report-list-page.js.map +1 -1
- package/dist-client/pages/data-report/data-report-samples-page.d.ts +1 -7
- package/dist-client/pages/data-report/data-report-samples-page.js +17 -30
- package/dist-client/pages/data-report/data-report-samples-page.js.map +1 -1
- package/dist-client/pages/data-sample/data-sample-list-page.d.ts +0 -6
- package/dist-client/pages/data-sample/data-sample-list-page.js +68 -130
- package/dist-client/pages/data-sample/data-sample-list-page.js.map +1 -1
- package/dist-client/pages/data-sample/data-sample-search-page.d.ts +1 -7
- package/dist-client/pages/data-sample/data-sample-search-page.js +63 -116
- package/dist-client/pages/data-sample/data-sample-search-page.js.map +1 -1
- package/dist-client/pages/data-sensor/data-sensor-list-page.d.ts +0 -6
- package/dist-client/pages/data-sensor/data-sensor-list-page.js +89 -167
- package/dist-client/pages/data-sensor/data-sensor-list-page.js.map +1 -1
- package/dist-client/pages/data-set/data-item-list.js +15 -1
- package/dist-client/pages/data-set/data-item-list.js.map +1 -1
- package/dist-client/pages/data-set/data-set-list-page.d.ts +0 -6
- package/dist-client/pages/data-set/data-set-list-page.js +2 -4
- package/dist-client/pages/data-set/data-set-list-page.js.map +1 -1
- package/dist-client/pages/data-summary/data-summary-list-page.d.ts +1 -7
- package/dist-client/pages/data-summary/data-summary-list-page.js +56 -105
- package/dist-client/pages/data-summary/data-summary-list-page.js.map +1 -1
- package/dist-client/pages/data-summary/data-summary-period-page.d.ts +1 -7
- package/dist-client/pages/data-summary/data-summary-period-page.js +50 -90
- package/dist-client/pages/data-summary/data-summary-period-page.js.map +1 -1
- package/dist-client/pages/data-summary/data-summary-search-page.d.ts +1 -7
- package/dist-client/pages/data-summary/data-summary-search-page.js +61 -111
- package/dist-client/pages/data-summary/data-summary-search-page.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/activities/activity-data-review.js +5 -2
- package/dist-server/activities/activity-data-review.js.map +1 -1
- package/dist-server/activities/activity-ooc-review.js +4 -1
- package/dist-server/activities/activity-ooc-review.js.map +1 -1
- package/dist-server/controllers/create-data-ooc.js +2 -1
- package/dist-server/controllers/create-data-ooc.js.map +1 -1
- package/dist-server/controllers/create-data-sample.js +59 -7
- package/dist-server/controllers/create-data-sample.js.map +1 -1
- package/dist-server/controllers/issue-data-collection-task.js +9 -5
- package/dist-server/controllers/issue-data-collection-task.js.map +1 -1
- package/dist-server/controllers/issue-ooc-resolve.js +11 -6
- package/dist-server/controllers/issue-ooc-resolve.js.map +1 -1
- package/dist-server/controllers/issue-ooc-review.js +9 -6
- package/dist-server/controllers/issue-ooc-review.js.map +1 -1
- package/dist-server/service/data-set/data-item-type.d.ts +259 -0
- package/dist-server/service/data-set/data-item-type.js +259 -0
- package/dist-server/service/data-set/data-item-type.js.map +1 -1
- package/dist-server/service/index.d.ts +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/dist-server/utils/index.d.ts +1 -0
- package/dist-server/utils/index.js +1 -0
- package/dist-server/utils/index.js.map +1 -1
- package/dist-server/utils/media-validation.d.ts +51 -0
- package/dist-server/utils/media-validation.js +148 -0
- package/dist-server/utils/media-validation.js.map +1 -0
- package/package.json +26 -26
- package/spec/integration/debug.spec.ts +42 -0
- package/spec/integration/ooc-lifecycle.spec.ts +484 -0
- package/spec/integration/ooc-workflow.spec.ts +276 -0
- package/spec/integration/simple.spec.ts +62 -0
- package/spec/unit/controllers/activity-callbacks.spec.ts +609 -0
- package/spec/unit/controllers/create-data-ooc.spec.ts +310 -0
- package/spec/unit/controllers/issue-ooc-resolve.spec.ts +431 -0
- package/spec/unit/controllers/issue-ooc-review.spec.ts +288 -0
- package/spec/unit/data-use-case.spec.ts +150 -0
- package/spec/unit/ooc-state-transition.spec.ts +233 -0
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
# Quick Reference: Frontend Component Architecture
|
|
2
|
+
|
|
3
|
+
## File Locations - Quick Lookup
|
|
4
|
+
|
|
5
|
+
### Client-Side Components (Your Repo)
|
|
6
|
+
```
|
|
7
|
+
/Users/super/Documents/GitHub/things-factory/packages/dataset/client/
|
|
8
|
+
├── components/
|
|
9
|
+
│ ├── data-entry-form.ts - Form wrapper using ox-data-entry-form
|
|
10
|
+
│ └── checklist-entry-form.ts - Checklist wrapper using ox-checklist-entry-form
|
|
11
|
+
└── activities/
|
|
12
|
+
└── activity-data-collect-edit.ts - Workflow activity entry point
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Server-Side Types & Utils (Your Repo)
|
|
16
|
+
```
|
|
17
|
+
/Users/super/Documents/GitHub/things-factory/packages/dataset/server/
|
|
18
|
+
├── service/data-set/
|
|
19
|
+
│ └── data-item-type.ts - DataItemType enum + media options schema
|
|
20
|
+
└── utils/
|
|
21
|
+
└── media-validation.ts - Media file validation utilities
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Core Components (Dependency - Node Modules)
|
|
25
|
+
```
|
|
26
|
+
@operato/dataset (in node_modules)
|
|
27
|
+
├── ox-data-entry-form.js - Main form component
|
|
28
|
+
├── ox-data-entry-subgroup-form.js - Grouped items in Grist table
|
|
29
|
+
└── ox-data-input-factory.js - Type-to-component mapping factory
|
|
30
|
+
|
|
31
|
+
@operato/input (in node_modules)
|
|
32
|
+
├── ox-input-file.js - File upload component
|
|
33
|
+
├── ox-input-image.js - Image upload component
|
|
34
|
+
├── ox-input-signature.js - Digital signature component
|
|
35
|
+
└── ox-form-field.js - Base class for all input components
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## How Data Entry Works - 5 Step Flow
|
|
41
|
+
|
|
42
|
+
### Step 1: User Opens Activity
|
|
43
|
+
File: `activity-data-collect-edit.ts`
|
|
44
|
+
- Gets `dataSetId` from workflow
|
|
45
|
+
- Fetches DataSet with dataItems via GraphQL
|
|
46
|
+
|
|
47
|
+
### Step 2: OxDataEntryForm Renders
|
|
48
|
+
File: `@operato/dataset/ox-data-entry-form.js`
|
|
49
|
+
- Iterates through `dataItems.filter(item => item.active)`
|
|
50
|
+
- For grouped items: renders `ox-data-entry-subgroup-form`
|
|
51
|
+
- For non-grouped: calls `OxDataInputFactory.createInputElement()`
|
|
52
|
+
|
|
53
|
+
### Step 3: OxDataInputFactory Creates Input
|
|
54
|
+
File: `@operato/dataset/ox-data-input-factory.js`
|
|
55
|
+
- Switch statement on `dataItem.type`
|
|
56
|
+
- Currently supports: text, number, boolean, date, datetime, select, radio, file, signature
|
|
57
|
+
- **MISSING:** image, video, audio
|
|
58
|
+
|
|
59
|
+
### Step 4: User Submits Form
|
|
60
|
+
- Form collects values from all inputs by `name` attribute
|
|
61
|
+
- `buildValue()` extracts values into object: `{ [tag]: any }`
|
|
62
|
+
- GraphQL mutation sends with `context: { hasUpload: true }`
|
|
63
|
+
|
|
64
|
+
### Step 5: Server Processes Files
|
|
65
|
+
File: `create-data-sample.ts`
|
|
66
|
+
- Iterates `dataItems` looking for `isFileOrMediaType()`
|
|
67
|
+
- If media type: validates with `validateMediaFile()`
|
|
68
|
+
- Creates attachments and stores file paths in data
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Type Mapping (OxDataInputFactory)
|
|
73
|
+
|
|
74
|
+
### Current Types
|
|
75
|
+
```
|
|
76
|
+
'select' → <select name=${tag}> with options
|
|
77
|
+
'radio' → <label><input type="radio"> with options
|
|
78
|
+
'boolean' → <input type="checkbox">
|
|
79
|
+
'number' → <input type="number">
|
|
80
|
+
'date' → <input type="date">
|
|
81
|
+
'datetime' → <input type="datetime-local">
|
|
82
|
+
'file' → <ox-input-file multiple>
|
|
83
|
+
'signature' → <ox-input-signature>
|
|
84
|
+
'text' → <input type="text"> (default)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Missing Types (Need Implementation)
|
|
88
|
+
```
|
|
89
|
+
'image' → <ox-input-image> (TO BE CREATED)
|
|
90
|
+
'video' → <ox-input-video> (TO BE CREATED)
|
|
91
|
+
'audio' → <ox-input-audio> (TO BE CREATED)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Key Functions & Classes
|
|
97
|
+
|
|
98
|
+
### OxFormField (Base Class)
|
|
99
|
+
**Properties:**
|
|
100
|
+
- `name: string` - Form field identifier
|
|
101
|
+
- `value: T` - Field value (generic)
|
|
102
|
+
- `disabled: boolean` - Disabled state
|
|
103
|
+
|
|
104
|
+
**Methods:**
|
|
105
|
+
- `connectedCallback()` - Register with parent form
|
|
106
|
+
- `appendFormData(e: FormDataEvent)` - Add to form submission
|
|
107
|
+
|
|
108
|
+
### OxDataEntryForm
|
|
109
|
+
**Key Methods:**
|
|
110
|
+
- `buildInputs()` - Generate all input elements
|
|
111
|
+
- `buildValue()` - Extract form values as object
|
|
112
|
+
- `extractValuesFromInputs()` - Query DOM by name attribute
|
|
113
|
+
|
|
114
|
+
### OxDataInputFactory
|
|
115
|
+
**Static Methods:**
|
|
116
|
+
- `createInputElement(type, tag, value, options, idx)` - Route to correct component
|
|
117
|
+
- `mapGristType(type)` - Convert to Grist column type
|
|
118
|
+
- `getGristRecordOptions(type, options)` - Grid cell configuration
|
|
119
|
+
|
|
120
|
+
### Media Validation Utils
|
|
121
|
+
**Functions:**
|
|
122
|
+
- `validateMediaFile(file, mediaType, options)` - Main validator
|
|
123
|
+
- `isValidMimeType(mediaType, mimetype)` - Check MIME type
|
|
124
|
+
- `isAcceptedFormat(filename, acceptFormats)` - Check extension
|
|
125
|
+
- `isValidFileSize(fileSize, maxSize)` - Check size
|
|
126
|
+
- `isMediaType(type)` - Check if image/video/audio
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Adding New Media Components - Checklist
|
|
131
|
+
|
|
132
|
+
### 1. Create Component File
|
|
133
|
+
```
|
|
134
|
+
Location: packages/dataset/client/components/ox-input-image.ts
|
|
135
|
+
Extend: OxFormField
|
|
136
|
+
Pattern: Similar to ox-input-file
|
|
137
|
+
Methods needed:
|
|
138
|
+
- render()
|
|
139
|
+
- updated()
|
|
140
|
+
- firstUpdated()
|
|
141
|
+
- _onChangeValue()
|
|
142
|
+
- _notifyChange()
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### 2. Update OxDataInputFactory
|
|
146
|
+
File: Update @operato/dataset source (or create wrapper)
|
|
147
|
+
Add to switch:
|
|
148
|
+
```javascript
|
|
149
|
+
case 'image': return html`<ox-input-image ...>`;
|
|
150
|
+
case 'video': return html`<ox-input-video ...>`;
|
|
151
|
+
case 'audio': return html`<ox-input-audio ...>`;
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 3. Add to mapGristType()
|
|
155
|
+
```javascript
|
|
156
|
+
case 'image': return 'image';
|
|
157
|
+
case 'video': return 'video';
|
|
158
|
+
case 'audio': return 'audio';
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### 4. Add to getGristRecordOptions()
|
|
162
|
+
```javascript
|
|
163
|
+
case 'image':
|
|
164
|
+
case 'video':
|
|
165
|
+
case 'audio':
|
|
166
|
+
return { multiple: options.multiple || false };
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### 5. Import in Components
|
|
170
|
+
```typescript
|
|
171
|
+
import '@operato/dataset/ox-input-image.js'
|
|
172
|
+
import '@operato/dataset/ox-input-video.js'
|
|
173
|
+
import '@operato/dataset/ox-input-audio.js'
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Component Value Extraction (Important!)
|
|
179
|
+
|
|
180
|
+
### How Form Gets Values
|
|
181
|
+
```typescript
|
|
182
|
+
// In ox-data-entry-form.js, line ~89
|
|
183
|
+
const editors = Array.from(
|
|
184
|
+
this.renderRoot.querySelectorAll(`[name=${tag}]`)
|
|
185
|
+
)
|
|
186
|
+
// Extracts value from: name="product_image"
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Why Name Attribute Matters
|
|
190
|
+
- Form values keyed by `name` attribute
|
|
191
|
+
- Must match `dataItem.tag` value
|
|
192
|
+
- All OxInput* components must set name on native input
|
|
193
|
+
|
|
194
|
+
### File Upload Special Handling
|
|
195
|
+
Files passed as: `[{ file: FileUpload }, ...]`
|
|
196
|
+
Backend converts to: `[{ id, mimetype, name, fullpath }, ...]`
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## DataItem Configuration Examples
|
|
201
|
+
|
|
202
|
+
### Image Field Config
|
|
203
|
+
```typescript
|
|
204
|
+
{
|
|
205
|
+
name: 'Product Image',
|
|
206
|
+
tag: 'product_image', // ← Used as name attribute
|
|
207
|
+
type: 'image', // ← Routes to OxInputImage
|
|
208
|
+
description: 'Upload product photo',
|
|
209
|
+
unit: 'JPG/PNG',
|
|
210
|
+
quota: 3, // Allow up to 3 images
|
|
211
|
+
options: {
|
|
212
|
+
accept: ['jpeg', 'png'],
|
|
213
|
+
maxSize: 10485760, // 10MB
|
|
214
|
+
maxWidth: 4096,
|
|
215
|
+
maxHeight: 4096,
|
|
216
|
+
multiple: true
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Video Field Config
|
|
222
|
+
```typescript
|
|
223
|
+
{
|
|
224
|
+
name: 'Demo Video',
|
|
225
|
+
tag: 'demo_video',
|
|
226
|
+
type: 'video',
|
|
227
|
+
quota: 1,
|
|
228
|
+
options: {
|
|
229
|
+
accept: ['mp4', 'webm'],
|
|
230
|
+
maxSize: 104857600, // 100MB
|
|
231
|
+
maxDuration: 300, // 5 minutes
|
|
232
|
+
multiple: false
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Audio Field Config
|
|
238
|
+
```typescript
|
|
239
|
+
{
|
|
240
|
+
name: 'Voice Note',
|
|
241
|
+
tag: 'voice_note',
|
|
242
|
+
type: 'audio',
|
|
243
|
+
quota: 1,
|
|
244
|
+
options: {
|
|
245
|
+
accept: ['mp3', 'wav'],
|
|
246
|
+
maxSize: 52428800, // 50MB
|
|
247
|
+
maxDuration: 600, // 10 minutes
|
|
248
|
+
multiple: false
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## File Upload GraphQL Context
|
|
256
|
+
|
|
257
|
+
### Why `hasUpload: true`?
|
|
258
|
+
```typescript
|
|
259
|
+
// In data-entry-form.ts
|
|
260
|
+
context: {
|
|
261
|
+
hasUpload: true
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
This tells Apollo Client to:
|
|
265
|
+
1. Use `multipart/form-data` encoding (not JSON)
|
|
266
|
+
2. Include files in GraphQL variables
|
|
267
|
+
3. Stream files to server
|
|
268
|
+
|
|
269
|
+
### GraphQL Variable Structure
|
|
270
|
+
```typescript
|
|
271
|
+
{
|
|
272
|
+
dataSample: {
|
|
273
|
+
dataSet: { id: '...' },
|
|
274
|
+
data: {
|
|
275
|
+
product_image: [{file: FileUpload}, ...],
|
|
276
|
+
demo_video: [{file: FileUpload}],
|
|
277
|
+
...
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## Common Gotchas
|
|
286
|
+
|
|
287
|
+
### 1. OxInputImage vs OxInputFile
|
|
288
|
+
- **File**: Generic file upload
|
|
289
|
+
- **Image**: Image-specific with preview/validation
|
|
290
|
+
- Note: OxInputImage exists in @operato/input but not used in factory
|
|
291
|
+
|
|
292
|
+
### 2. Name Attribute is Critical
|
|
293
|
+
```typescript
|
|
294
|
+
// CORRECT - matches dataItem.tag
|
|
295
|
+
<ox-input-image name="product_image" ...></ox-input-image>
|
|
296
|
+
|
|
297
|
+
// WRONG - value won't be extracted
|
|
298
|
+
<ox-input-image ...></ox-input-image>
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### 3. Quota vs Multiple
|
|
302
|
+
```typescript
|
|
303
|
+
quota: 3, options: { multiple: true }
|
|
304
|
+
// Allows user to select 3 times, each time multiple files
|
|
305
|
+
|
|
306
|
+
quota: 1, options: { multiple: false }
|
|
307
|
+
// Single file selection
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### 4. Group vs Subgroup
|
|
311
|
+
```typescript
|
|
312
|
+
group: 'measurements' // Groups items in table (Grist)
|
|
313
|
+
subgroup: 'length' // Secondary grouping
|
|
314
|
+
// Non-grouped items show in main form
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### 5. Active vs Hidden
|
|
318
|
+
```typescript
|
|
319
|
+
active: true // Rendered in form
|
|
320
|
+
active: false // Skipped entirely
|
|
321
|
+
hidden: true // Rendered but CSS hidden (for validation specs)
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## File Paths in Codebase
|
|
327
|
+
|
|
328
|
+
### Where to Make Changes
|
|
329
|
+
1. **New Components**: `packages/dataset/client/components/`
|
|
330
|
+
2. **Type Updates**: Update @operato/dataset OR create wrapper
|
|
331
|
+
3. **Media Options**: Already defined in `data-item-type.ts`
|
|
332
|
+
4. **Validation**: Already implemented in `media-validation.ts`
|
|
333
|
+
|
|
334
|
+
### Dependencies Already Available
|
|
335
|
+
```json
|
|
336
|
+
{
|
|
337
|
+
"@operato/input": "^9.0.0",
|
|
338
|
+
"@operato/dataset": "^9.0.0",
|
|
339
|
+
"lit": "^2.x.x"
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Key Imports for New Components
|
|
344
|
+
```typescript
|
|
345
|
+
import { css, html } from 'lit'
|
|
346
|
+
import { customElement, property, query } from 'lit/decorators.js'
|
|
347
|
+
import { OxFormField } from '@operato/input'
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## Testing Checklist
|
|
353
|
+
|
|
354
|
+
Before deploying new media components:
|
|
355
|
+
|
|
356
|
+
- [ ] Component renders with correct icon/label
|
|
357
|
+
- [ ] File selection works (click and drag-drop)
|
|
358
|
+
- [ ] Value extracted correctly by name attribute
|
|
359
|
+
- [ ] Multiple/single file toggle works
|
|
360
|
+
- [ ] GraphQL mutation includes files
|
|
361
|
+
- [ ] Server-side validation passes
|
|
362
|
+
- [ ] Media validation errors displayed to user
|
|
363
|
+
- [ ] Attachment created in database
|
|
364
|
+
- [ ] File paths stored in DataSample.data
|
|
365
|
+
- [ ] Grist grid column type correct for subgroup items
|
|
@@ -4,13 +4,7 @@ import '@operato/context/ox-context-page-toolbar.js';
|
|
|
4
4
|
import { FetchOption } from '@operato/data-grist';
|
|
5
5
|
import { PageView } from '@operato/shell';
|
|
6
6
|
import './data-archive-request-popup.js';
|
|
7
|
-
declare const DataArchiveListPage_base: (new (...args: any[]) =>
|
|
8
|
-
_storeUnsubscribe: import("redux").Unsubscribe;
|
|
9
|
-
connectedCallback(): void;
|
|
10
|
-
disconnectedCallback(): void;
|
|
11
|
-
stateChanged(_state: unknown): void;
|
|
12
|
-
readonly isConnected: boolean;
|
|
13
|
-
}) & (new (...args: any[]) => import("lit").LitElement) & typeof PageView;
|
|
7
|
+
declare const DataArchiveListPage_base: (new (...args: any[]) => import("lit").LitElement) & typeof PageView;
|
|
14
8
|
export declare class DataArchiveListPage extends DataArchiveListPage_base {
|
|
15
9
|
static styles: import("lit").CSSResult[];
|
|
16
10
|
gristConfig: any;
|
|
@@ -5,16 +5,15 @@ import '@operato/context/ox-context-page-toolbar.js';
|
|
|
5
5
|
import gql from 'graphql-tag';
|
|
6
6
|
import { css, html } from 'lit';
|
|
7
7
|
import { customElement, query, state } from 'lit/decorators.js';
|
|
8
|
-
import { connect } from 'pwa-helpers/connect-mixin';
|
|
9
8
|
import { DataGrist } from '@operato/data-grist';
|
|
10
9
|
import { client } from '@operato/graphql';
|
|
11
10
|
import { i18next, localize } from '@operato/i18n';
|
|
12
11
|
import { openPopup } from '@operato/layout';
|
|
13
|
-
import { PageView
|
|
12
|
+
import { PageView } from '@operato/shell';
|
|
14
13
|
import { CommonHeaderStyles, ScrollbarStyles } from '@operato/styles';
|
|
15
14
|
import { isMobileDevice } from '@operato/utils';
|
|
16
15
|
import './data-archive-request-popup.js';
|
|
17
|
-
let DataArchiveListPage = class DataArchiveListPage extends
|
|
16
|
+
let DataArchiveListPage = class DataArchiveListPage extends localize(i18next)(PageView) {
|
|
18
17
|
constructor() {
|
|
19
18
|
super(...arguments);
|
|
20
19
|
this.mode = isMobileDevice() ? 'CARD' : 'GRID';
|
|
@@ -23,51 +22,41 @@ let DataArchiveListPage = class DataArchiveListPage extends connect(store)(local
|
|
|
23
22
|
ScrollbarStyles,
|
|
24
23
|
CommonHeaderStyles,
|
|
25
24
|
css `
|
|
26
|
-
:host {
|
|
27
|
-
display: flex;
|
|
25
|
+
:host { display: flex;
|
|
28
26
|
flex-direction: column;
|
|
29
27
|
|
|
30
28
|
overflow: hidden;
|
|
31
|
-
|
|
29
|
+
}
|
|
32
30
|
|
|
33
|
-
ox-grist {
|
|
34
|
-
overflow-y: auto;
|
|
31
|
+
ox-grist { overflow-y: auto;
|
|
35
32
|
flex: 1;
|
|
36
|
-
|
|
33
|
+
}
|
|
37
34
|
|
|
38
|
-
.header {
|
|
39
|
-
|
|
40
|
-
}
|
|
35
|
+
.header { grid-template-areas: 'filters actions';
|
|
36
|
+
}
|
|
41
37
|
`
|
|
42
38
|
]; }
|
|
43
39
|
get context() {
|
|
44
|
-
return {
|
|
45
|
-
|
|
46
|
-
search: {
|
|
47
|
-
handler: (search) => {
|
|
40
|
+
return { title: i18next.t('title.data-archive list'),
|
|
41
|
+
search: { handler: (search) => {
|
|
48
42
|
this.grist.searchText = search;
|
|
49
43
|
},
|
|
50
|
-
value: this.grist?.searchText || ''
|
|
51
|
-
|
|
52
|
-
filter: {
|
|
53
|
-
handler: () => {
|
|
44
|
+
value: this.grist?.searchText || '' },
|
|
45
|
+
filter: { handler: () => {
|
|
54
46
|
this.grist.toggleHeadroom();
|
|
55
47
|
}
|
|
56
48
|
},
|
|
57
49
|
help: 'dataset/data-archive',
|
|
58
50
|
actions: [
|
|
59
|
-
{
|
|
60
|
-
title: i18next.t('button.request-archive'),
|
|
51
|
+
{ title: i18next.t('button.request-archive'),
|
|
61
52
|
action: this.openArchivePopup.bind(this),
|
|
62
53
|
icon: 'archive'
|
|
63
54
|
}
|
|
64
55
|
],
|
|
65
|
-
exportable: {
|
|
66
|
-
name: i18next.t('title.data-archive list'),
|
|
56
|
+
exportable: { name: i18next.t('title.data-archive list'),
|
|
67
57
|
data: this._exportableData.bind(this)
|
|
68
58
|
},
|
|
69
|
-
toolbar: false
|
|
70
|
-
};
|
|
59
|
+
toolbar: false };
|
|
71
60
|
}
|
|
72
61
|
render() {
|
|
73
62
|
const mode = this.mode || (isMobileDevice() ? 'LIST' : 'GRID');
|
|
@@ -89,78 +78,65 @@ let DataArchiveListPage = class DataArchiveListPage extends connect(store)(local
|
|
|
89
78
|
`;
|
|
90
79
|
}
|
|
91
80
|
async pageInitialized(lifecycle) {
|
|
92
|
-
this.gristConfig = {
|
|
93
|
-
list: { fields: ['updater', 'updatedAt'] },
|
|
81
|
+
this.gristConfig = { list: { fields: ['updater', 'updatedAt'] },
|
|
94
82
|
columns: [
|
|
95
83
|
{ type: 'gutter', gutterName: 'sequence' },
|
|
96
84
|
// { type: 'gutter', gutterName: 'row-selector', multiple: true },
|
|
97
|
-
{
|
|
98
|
-
type: 'resource-object',
|
|
85
|
+
{ type: 'resource-object',
|
|
99
86
|
name: 'creator',
|
|
100
87
|
header: i18next.t('field.creator'),
|
|
101
88
|
sortable: true,
|
|
102
89
|
width: 120,
|
|
103
90
|
imex: true
|
|
104
91
|
},
|
|
105
|
-
{
|
|
106
|
-
type: 'datetime',
|
|
92
|
+
{ type: 'datetime',
|
|
107
93
|
name: 'createdAt',
|
|
108
94
|
header: i18next.t('field.created_at'),
|
|
109
95
|
sortable: true,
|
|
110
96
|
width: 180,
|
|
111
97
|
imex: true
|
|
112
98
|
},
|
|
113
|
-
{
|
|
114
|
-
type: 'datetime',
|
|
99
|
+
{ type: 'datetime',
|
|
115
100
|
name: 'updatedAt',
|
|
116
101
|
header: i18next.t('field.updated_at'),
|
|
117
102
|
sortable: true,
|
|
118
103
|
width: 180,
|
|
119
104
|
imex: true
|
|
120
105
|
},
|
|
121
|
-
{
|
|
122
|
-
type: 'json5',
|
|
106
|
+
{ type: 'json5',
|
|
123
107
|
name: 'requestParams',
|
|
124
108
|
header: i18next.t('field.request-params'),
|
|
125
|
-
record: {
|
|
126
|
-
editable: false
|
|
109
|
+
record: { editable: false
|
|
127
110
|
},
|
|
128
111
|
width: 200,
|
|
129
112
|
imex: true
|
|
130
113
|
},
|
|
131
|
-
{
|
|
132
|
-
type: 'string',
|
|
114
|
+
{ type: 'string',
|
|
133
115
|
name: 'downloadUrl',
|
|
134
116
|
label: true,
|
|
135
117
|
header: i18next.t('field.download-url'),
|
|
136
|
-
record: {
|
|
137
|
-
editable: false
|
|
118
|
+
record: { editable: false
|
|
138
119
|
},
|
|
139
120
|
width: 240,
|
|
140
121
|
imex: true
|
|
141
122
|
},
|
|
142
|
-
{
|
|
143
|
-
type: 'string',
|
|
123
|
+
{ type: 'string',
|
|
144
124
|
name: 'status',
|
|
145
125
|
label: true,
|
|
146
126
|
header: i18next.t('field.status'),
|
|
147
|
-
record: {
|
|
148
|
-
editable: false
|
|
127
|
+
record: { editable: false
|
|
149
128
|
},
|
|
150
129
|
sortable: true,
|
|
151
130
|
width: 120,
|
|
152
131
|
imex: true
|
|
153
132
|
}
|
|
154
133
|
],
|
|
155
|
-
rows: {
|
|
156
|
-
|
|
157
|
-
selectable: {
|
|
158
|
-
multiple: true
|
|
134
|
+
rows: { appendable: false,
|
|
135
|
+
selectable: { multiple: true
|
|
159
136
|
}
|
|
160
137
|
},
|
|
161
138
|
sorters: [
|
|
162
|
-
{
|
|
163
|
-
name: 'createdAt',
|
|
139
|
+
{ name: 'createdAt',
|
|
164
140
|
desc: true
|
|
165
141
|
}
|
|
166
142
|
]
|
|
@@ -174,46 +150,37 @@ let DataArchiveListPage = class DataArchiveListPage extends connect(store)(local
|
|
|
174
150
|
this.popup = openPopup(html ` <data-archive-request-popup
|
|
175
151
|
@requested=${this.closePopupAndRefesh.bind(this)}
|
|
176
152
|
@created=${this.closePopupAndRefesh.bind(this)}
|
|
177
|
-
></data-archive-request-popup>`, {
|
|
178
|
-
backdrop: true,
|
|
153
|
+
></data-archive-request-popup>`, { backdrop: true,
|
|
179
154
|
size: 'small',
|
|
180
155
|
title: i18next.t('title.data-archive request popup')
|
|
181
156
|
});
|
|
182
157
|
}
|
|
183
158
|
async fetchHandler({ page, limit, sortings = [], filters = [] }) {
|
|
184
|
-
const response = await client.query({
|
|
185
|
-
|
|
186
|
-
query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
|
|
187
|
-
responses: dataArchives(filters: $filters, pagination: $pagination, sortings: $sortings) {
|
|
188
|
-
items {
|
|
189
|
-
id
|
|
159
|
+
const response = await client.query({ query: gql `
|
|
160
|
+
query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) { responses: dataArchives(filters: $filters, pagination: $pagination, sortings: $sortings) { items { id
|
|
190
161
|
type
|
|
191
162
|
requestParams
|
|
192
163
|
downloadUrl
|
|
193
164
|
status
|
|
194
|
-
creator {
|
|
195
|
-
id
|
|
165
|
+
creator { id
|
|
196
166
|
name
|
|
197
|
-
|
|
198
|
-
updater {
|
|
199
|
-
id
|
|
167
|
+
}
|
|
168
|
+
updater { id
|
|
200
169
|
name
|
|
201
|
-
|
|
170
|
+
}
|
|
202
171
|
updatedAt
|
|
203
172
|
createdAt
|
|
204
|
-
|
|
173
|
+
}
|
|
205
174
|
total
|
|
206
|
-
|
|
207
|
-
|
|
175
|
+
}
|
|
176
|
+
}
|
|
208
177
|
`,
|
|
209
|
-
variables: {
|
|
210
|
-
filters,
|
|
178
|
+
variables: { filters,
|
|
211
179
|
pagination: { page, limit },
|
|
212
180
|
sortings
|
|
213
181
|
}
|
|
214
182
|
});
|
|
215
|
-
return {
|
|
216
|
-
total: response.data.responses.total || 0,
|
|
183
|
+
return { total: response.data.responses.total || 0,
|
|
217
184
|
records: response.data.responses.items || []
|
|
218
185
|
};
|
|
219
186
|
}
|
|
@@ -229,8 +196,7 @@ let DataArchiveListPage = class DataArchiveListPage extends connect(store)(local
|
|
|
229
196
|
.filter(column => column.type !== 'gutter' && column.record !== undefined && column.imex !== undefined)
|
|
230
197
|
.map(column => {
|
|
231
198
|
return column.imex === true
|
|
232
|
-
? {
|
|
233
|
-
header: column.header.renderer(column),
|
|
199
|
+
? { header: column.header.renderer(column),
|
|
234
200
|
key: column.name,
|
|
235
201
|
width: column.width,
|
|
236
202
|
type: column.type
|
|
@@ -238,8 +204,7 @@ let DataArchiveListPage = class DataArchiveListPage extends connect(store)(local
|
|
|
238
204
|
: column.imex;
|
|
239
205
|
});
|
|
240
206
|
var data = records.map(item => {
|
|
241
|
-
return {
|
|
242
|
-
id: item.id,
|
|
207
|
+
return { id: item.id,
|
|
243
208
|
...this.gristConfig.columns
|
|
244
209
|
.filter(column => column.type !== 'gutter' && column.record !== undefined && column.imex !== undefined)
|
|
245
210
|
.reduce((record, column) => {
|