-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathdataset.form.ts
More file actions
63 lines (61 loc) · 3.35 KB
/
Copy pathdataset.form.ts
File metadata and controls
63 lines (61 loc) · 3.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
import { defineForm } from './view.zod';
/**
* Form layout for the Dataset metadata editor (ADR-0021 analytics semantic layer).
*
* Bound to {@link DatasetSchema}. Until this entry existed, `dataset` was the
* only UI-authorable metadata type WITHOUT a registered {@link FormView}, so the
* metadata-admin create surface fell back to the auto-generated single-section
* layout. That fallback (a) silently DROPPED the optional `include` (joins) and
* `filter` (intrinsic scope) fields — making joined / scoped datasets
* un-authorable online — and (b) rendered the base `object` and dimension/
* measure `field`s as bare free-text inputs with no object context.
*
* This layout restores `include` + `filter`, groups the surface into sections
* with guidance, and uses pickers (`ref:object`, `filter-builder` scoped to the
* base object) so a business user can author a dataset without memorising
* machine names. Mirrors {@link reportForm} — the sibling analytics editor.
*/
export const datasetForm = defineForm({
schemaId: 'dataset',
type: 'simple',
sections: [
{
name: 'basics',
label: 'Basics',
description: 'Dataset identity.',
columns: 2,
fields: [
{ field: 'name', type: 'text', colSpan: 1, required: true, immutable: true, helpText: 'snake_case unique identifier' },
{ field: 'label', type: 'text', colSpan: 1, required: true, helpText: 'Display name' },
{ field: 'description', type: 'textarea', colSpan: 2, helpText: 'What this dataset measures' },
],
},
{
name: 'source',
label: 'Source',
description: 'The base object, the relationships to join, and the dataset’s intrinsic scope. Joins are derived from the object graph — pick relationship (lookup / master_detail) names, never write an ON clause.',
fields: [
{ field: 'object', widget: 'ref:object', required: true, helpText: 'Base object — the FROM' },
{ field: 'include', widget: 'string-tags', helpText: 'Relationship (lookup / master_detail) field names to join — enables `relationship.field` dimensions/measures (e.g. include "account" → group by account.region)' },
{ field: 'filter', widget: 'filter-builder', dependsOn: 'object', helpText: 'Intrinsic scope filter (e.g. exclude soft-deleted records), ANDed into every query' },
],
},
{
name: 'dimensions',
label: 'Dimensions',
description: 'Groupable axes. Use a base field, or `relationship.field` (e.g. account.region) for a relationship included above.',
fields: [
{ field: 'dimensions', type: 'repeater', required: true, helpText: 'Each: name (referenced by presentations), field, type, and — for dates — a default bucketing granularity' },
],
},
{
name: 'measures',
label: 'Measures',
description: 'Aggregatable values defined once and referenced by name. A measure is sum/avg/count/… of a field; a derived measure combines other measures (ratio/sum/difference/product). Measure-scoped filters and derived ops are edited per-row in the dataset designer.',
fields: [
{ field: 'measures', type: 'repeater', required: true, helpText: 'Each: name, aggregate, field (optional for count), display format/currency, and a “certified” governance flag' },
],
},
],
});