@nice2dev/ui-forms 1.3.9 → 1.3.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -3,31 +3,38 @@ import { ForwardRefExoticComponent } from 'react';
3
3
  import { NiceBaseProps } from '@nice2dev/ui-core';
4
4
  import { NiceComponentTutorial } from '@nice2dev/ui';
5
5
  import { NiceComponentTutorial as NiceComponentTutorial_2 } from '@nice2dev/ui-core';
6
- import { NiceConsoleTab } from '@nice2dev/ui';
7
6
  import { NiceDataSourceDef } from '@nice2dev/ui';
7
+ import { NiceDataSourceSchemaTable } from '@nice2dev/ui';
8
8
  import { NiceFieldValidationRule } from '@nice2dev/ui';
9
9
  import { NiceFormItem } from '@nice2dev/ui';
10
10
  import { NiceHookBinding } from '@nice2dev/ui';
11
- import { NiceLifecycleHandlerOption } from '@nice2dev/ui';
12
- import { NiceLifecycleTrigger } from '@nice2dev/ui';
13
- import { NiceLogEntry } from '@nice2dev/ui';
14
11
  import { NiceRbacModel } from '@nice2dev/ui';
15
- import { NiceRevision } from '@nice2dev/ui';
16
12
  import { NiceScriptRunnerProps } from '@nice2dev/ui';
17
13
  import { NiceStandardProps } from '@nice2dev/ui';
18
14
  import { NiceViewDefinition } from '@nice2dev/ui';
19
15
  import { NiceWorkflowDefinition } from '@nice2dev/ui';
20
16
  import { RefAttributes } from 'react';
21
17
 
22
- declare interface AIGeneratedField {
23
- label: string;
24
- field: string;
25
- type: string;
26
- required?: boolean;
27
- options?: string[];
28
- placeholder?: string;
29
- helpText?: string;
30
- }
18
+ /** Generated fields → NiceSchemaForm fields, with their validation rules. */
19
+ export declare function aiFormConfigToFormFields(config: {
20
+ fields: readonly NiceAIFormFieldLike[];
21
+ } | readonly NiceAIFormFieldLike[]): FormFieldDefinition[];
22
+
23
+ /** The schema-form field type of a generated field's type (unknown types become `text`). */
24
+ export declare function aiFormFieldType(type: string | undefined): FormFieldType;
25
+
26
+ /** A file holding one array, either bare or under `property`; the rest of the file is kept. */
27
+ export declare function arrayFileKind<T>(o: NiceArrayFileKindOptions): NiceStudioFileKind<T[]>;
28
+
29
+ /**
30
+ * The documents of a module: files grouped by kind and group, each decoded. A document whose
31
+ * files a kind cannot decode — or would not store unchanged — opens raw, one JSON / text
32
+ * document per file, with the error.
33
+ */
34
+ export declare function buildDocuments(kinds: readonly NiceStudioFileKind[], files: readonly NiceStudioFile[], ctx: NiceStudioCodecContext): NiceStudioDocument[];
35
+
36
+ /** A provider over modules held in memory, with versions, conflicts and revisions. */
37
+ export declare function createMemoryStudioProvider(options: NiceMemoryStudioOptions): NiceMemoryStudioProvider;
31
38
 
32
39
  /**
33
40
  * Identity helper that infers the precise `schema` type from a section literal,
@@ -36,6 +43,44 @@ declare interface AIGeneratedField {
36
43
  */
37
44
  export declare function defineManifestSection<TSchema extends JsonSchema>(section: NiceManifestSection<TSchema>): NiceManifestSection<TSchema>;
38
45
 
46
+ /** A starter access model: admin / user × view / create / edit / delete over the module's views and entities. */
47
+ export declare function deriveDefaultRbac(module: {
48
+ manifest?: Row;
49
+ views?: ReadonlyArray<{
50
+ id: string;
51
+ name: string;
52
+ }>;
53
+ entities?: readonly Row[];
54
+ }): NiceRbacModel;
55
+
56
+ /** Reads how `text` is written: BOM, line breaks, indentation, final newline, colon spacing. */
57
+ export declare function detectJsonTextFormat(text: string): NiceJsonTextFormat;
58
+
59
+ /**
60
+ * The file changes that store a document's new model: only files whose text differs from what
61
+ * was read, plus files the encoder adds or removes.
62
+ */
63
+ export declare function encodeDocument(doc: NiceStudioDocument, model: unknown, files: readonly NiceStudioFile[], ctx: NiceStudioCodecContext): NiceStudioFileChange[];
64
+
65
+ /** Ends with one of the suffixes (case-insensitive). */
66
+ export declare const endsWithAny: (...suffixes: string[]) => (path: string) => boolean;
67
+
68
+ /** The module's entities as the tables NiceDataSourceBuilder queries. */
69
+ export declare function entitiesToSchemas(entities: readonly Row[]): NiceDataSourceSchemaTable[];
70
+
71
+ /** The file name of a path. */
72
+ export declare const fileName: (path: string) => string;
73
+
74
+ /**
75
+ * A section narrowed to the properties a form can edit in this manifest: a value that does not fit
76
+ * its property's schema ({@link jsonValueFitsSchema}) leaves the section and is edited as JSON
77
+ * among the "Other properties".
78
+ */
79
+ export declare function fitManifestSection(section: NiceManifestSection, manifest: Record<string, unknown>): {
80
+ section: NiceManifestSection;
81
+ keys: string[];
82
+ };
83
+
39
84
  /** Convert a FormSchema into NiceForm items (for `NiceForm`). */
40
85
  export declare function formBuilderSchemaToNiceFormItems(schema: FormSchema): NiceFormItem[];
41
86
 
@@ -161,6 +206,27 @@ export declare interface FormSectionDefinition {
161
206
  fields: FormFieldDefinition[];
162
207
  }
163
208
 
209
+ /**
210
+ * Translations split into one file per language, edited as one document. A new language gets a
211
+ * file shaped and formatted like its siblings; a language removed in the editor loses its file.
212
+ */
213
+ export declare function i18nFileKind(o?: NiceI18nFileKindOptions): NiceStudioFileKind<NiceStudioTranslations>;
214
+
215
+ /**
216
+ * A file holding a list of entries edited one at a time (views, workflows). Entries the editor
217
+ * does not understand stay raw and round-trip as they are.
218
+ */
219
+ export declare function itemsFileKind<D>(o: NiceItemsFileKindOptions<D>): NiceStudioFileKind<Array<NiceStudioItem<D>>>;
220
+
221
+ /** Any JSON file, edited as JSON. */
222
+ export declare const jsonFallbackKind: NiceStudioFileKind<unknown>;
223
+
224
+ /**
225
+ * A kind for one JSON file per document: `select` picks the model out of the file, `assign` puts
226
+ * it back, and the file's text is patched so only the changed values move.
227
+ */
228
+ export declare function jsonFileKind<M>(o: NiceJsonFileKindOptions<M>): NiceStudioFileKind<M>;
229
+
164
230
  export declare interface JsonSchema {
165
231
  $schema?: string;
166
232
  $id?: string;
@@ -200,6 +266,78 @@ export declare interface JsonSchemaToFormItemsOptions {
200
266
  renderObjectField?: (value: Record<string, unknown>, onChange: (v: Record<string, unknown>) => void, schema: JsonSchema, label?: string) => default_2.ReactNode;
201
267
  }
202
268
 
269
+ /**
270
+ * Whether a value has exactly the shape its schema describes — every object key known to the
271
+ * schema, every array item of the item schema, an `enum` value among its options — so a form can
272
+ * edit it without losing or reshaping anything. Seeds written by hand often do not (a per-language
273
+ * `description` object, a list of strings where the schema has objects); such a value is edited
274
+ * as JSON instead.
275
+ */
276
+ export declare function jsonValueFitsSchema(value: unknown, schema: JsonSchema | undefined): boolean;
277
+
278
+ /** Whether two JSON values are equal (objects compared by their keys, not their order). */
279
+ export declare function jsonValuesEqual(a: unknown, b: unknown): boolean;
280
+
281
+ /**
282
+ * Text from an editor given the line breaks and BOM of the file it replaces. A browser text box
283
+ * hands back LF only (and some drop a BOM), which would rewrite every line of a CRLF file.
284
+ */
285
+ export declare function keepTextFormat(text: string, original: string | undefined): string;
286
+
287
+ /** The manifest keys the sections' schemas cover — the rest shows on an "Other properties" tab. */
288
+ export declare function manifestSectionKeys(sections: readonly NiceManifestSection[]): Set<string>;
289
+
290
+ /** The prefix a module's files share (`orders` of `orders.manifest.json`). */
291
+ export declare function modulePrefix(files: readonly NiceStudioFile[]): string;
292
+
293
+ export declare const nativeDataSourcesKind: NiceStudioFileKind<NiceDataSourceDef[]>;
294
+
295
+ export declare const nativeEntitiesKind: NiceStudioFileKind<Row_2[]>;
296
+
297
+ /** The file kinds of the native format, in matching order. */
298
+ export declare const nativeFileKinds: NiceStudioFileKind[];
299
+
300
+ export declare const nativeHooksKind: NiceStudioFileKind<NiceHookBinding[]>;
301
+
302
+ export declare const nativeI18nKind: NiceStudioFileKind<NiceStudioTranslations>;
303
+
304
+ export declare const nativeManifestKind: NiceStudioFileKind<Row_2>;
305
+
306
+ export declare const nativeRbacKind: NiceStudioFileKind<NiceRbacModel>;
307
+
308
+ /** The studio's own format: manifest, entities, translations, views, workflows, data sources, access, hooks. */
309
+ export declare const nativeStudioPreset: NiceStudioPreset;
310
+
311
+ export declare const nativeViewsKind: NiceStudioFileKind<NiceStudioItem<NiceViewDefinition>[]>;
312
+
313
+ export declare const nativeWorkflowsKind: NiceStudioFileKind<NiceStudioItem<NiceWorkflowDefinition>[]>;
314
+
315
+ /** A generated field, as an AI form generator describes it. */
316
+ export declare interface NiceAIFormFieldLike {
317
+ id?: string;
318
+ /** The data key, when the generator names it apart from `id`. */
319
+ name?: string;
320
+ field?: string;
321
+ type?: string;
322
+ label?: string;
323
+ required?: boolean;
324
+ placeholder?: string;
325
+ helpText?: string;
326
+ defaultValue?: unknown;
327
+ validation?: {
328
+ min?: number;
329
+ max?: number;
330
+ minLength?: number;
331
+ maxLength?: number;
332
+ pattern?: string;
333
+ message?: string;
334
+ };
335
+ options?: Array<{
336
+ value: string | number;
337
+ label: string;
338
+ } | string>;
339
+ }
340
+
203
341
  export declare const NiceArrayField: ForwardRefExoticComponent<NiceArrayFieldProps & RefAttributes<HTMLDivElement>>;
204
342
 
205
343
  export declare interface NiceArrayFieldProps {
@@ -222,6 +360,62 @@ export declare interface NiceArrayFieldProps {
222
360
  'data-testid'?: string;
223
361
  }
224
362
 
363
+ /** Options of {@link arrayFileKind}. */
364
+ export declare interface NiceArrayFileKindOptions {
365
+ id: string;
366
+ label: string;
367
+ labelKey?: string;
368
+ icon?: string;
369
+ editor: NiceStudioEditorId;
370
+ match(path: string): boolean;
371
+ /** The property holding the array (`views`); the file may also be the bare array. */
372
+ property: string;
373
+ /** The property that identifies an item, for minimal diffs. */
374
+ itemKey?: string;
375
+ }
376
+
377
+ export declare const NiceDevelopmentStudio: ForwardRefExoticComponent<NiceDevelopmentStudioProps & RefAttributes<HTMLDivElement>>;
378
+
379
+ export declare interface NiceDevelopmentStudioProps extends NiceStandardProps {
380
+ /** Where modules come from and go to. Without it the studio shows an empty explorer. */
381
+ provider?: NiceStudioProvider;
382
+ /**
383
+ * How the host's modules look (file kinds, manifest sections, languages, rules, generator).
384
+ * A function gets the translator, for translated section titles. Default: the native format.
385
+ */
386
+ preset?: NiceStudioPreset | ((t: (key: string, fallback: string) => string) => NiceStudioPreset);
387
+ /** A module to open at start (e.g. from a `?module=` link). */
388
+ defaultModule?: NiceStudioModuleKey;
389
+ /** Which explorer tree shows first. Default `'modules'`. */
390
+ defaultExplorerTab?: 'modules' | 'templates';
391
+ /** A module was opened. */
392
+ onModuleOpen?: (key: NiceStudioModuleKey) => void;
393
+ /** A module was saved. */
394
+ onSaved?: (key: NiceStudioModuleKey, result: Extract<NiceStudioWriteResult, {
395
+ ok: true;
396
+ }>) => void;
397
+ /** A provider call failed (also logged in the output panel). */
398
+ onError?: (error: unknown, context: string) => void;
399
+ /** Show the changed files before saving. Default `true`. */
400
+ reviewBeforeSave?: boolean;
401
+ /** Runs script files (`script` documents) in a NiceScriptRunner. */
402
+ scriptRunner?: Omit<NiceScriptRunnerProps, 'value' | 'onChange'>;
403
+ /** The host's own preview of a view (e.g. its runtime renderer), next to the designer. */
404
+ renderViewPreview?: (ctx: NiceStudioViewPreviewContext) => React.ReactNode;
405
+ /** Extra panels on a module's overview (payments, webhooks, …). */
406
+ modulePanels?: (ctx: NiceStudioModulePanelContext) => NiceStudioPanel[];
407
+ /** Browse and read only. */
408
+ readOnly?: boolean;
409
+ /** Console theme. Default `'light'`. */
410
+ theme?: 'dark' | 'light';
411
+ /** Studio height. Default `720`. */
412
+ height?: number | string;
413
+ /** Explorer width in px. Default `300`. */
414
+ explorerWidth?: number;
415
+ /** Optional guided tour. `true` = built-in tour; array/object = custom steps. Shows a "?" button. */
416
+ tutorial?: NiceComponentTutorial;
417
+ }
418
+
225
419
  export declare type NiceEntity = Record<string, unknown>;
226
420
 
227
421
  export declare const NiceEntityEditor: ForwardRefExoticComponent<NiceEntityEditorProps & RefAttributes<HTMLDivElement>>;
@@ -251,45 +445,6 @@ export declare interface NiceEntityEditorProps extends NiceStandardProps {
251
445
  tutorial?: NiceComponentTutorial;
252
446
  }
253
447
 
254
- export declare const NiceFormBuilderAI: default_2.ForwardRefExoticComponent<NiceFormBuilderAIProps & default_2.RefAttributes<NiceFormBuilderAIRef>>;
255
-
256
- export declare interface NiceFormBuilderAIProps {
257
- /** Enable AI features (requires NiceAIProvider) */
258
- enableAI?: boolean;
259
- /** AI model to use */
260
- aiModel?: string;
261
- /** Enable form generation from description */
262
- enableGenerate?: boolean;
263
- /** Enable field suggestions */
264
- enableSuggestions?: boolean;
265
- /** Callback when AI generates form */
266
- onGenerate?: (description: string, fields: AIGeneratedField[]) => void;
267
- /** Show AI toolbar */
268
- showAIToolbar?: boolean;
269
- /** Preset form templates */
270
- templates?: {
271
- name: string;
272
- description: string;
273
- }[];
274
- /** Initial form fields */
275
- fields?: FormFieldDefinition[];
276
- /** Callback when form fields change */
277
- onChange?: (fields: FormFieldDefinition[]) => void;
278
- /** Test ID */
279
- 'data-testid'?: string;
280
- }
281
-
282
- declare interface NiceFormBuilderAIRef {
283
- /** Generate form from natural language description */
284
- generateForm: (description: string) => Promise<AIGeneratedField[]>;
285
- /** Get current form fields */
286
- getFields: () => FormFieldDefinition[];
287
- /** Apply generated fields to the form */
288
- applyFields: (fields: AIGeneratedField[]) => void;
289
- /** Clear all fields */
290
- clearFields: () => void;
291
- }
292
-
293
448
  export declare const NiceI18nEditor: ForwardRefExoticComponent<NiceI18nEditorProps & RefAttributes<HTMLDivElement>>;
294
449
 
295
450
  export declare interface NiceI18nEditorProps extends NiceBaseProps {
@@ -313,51 +468,91 @@ export declare interface NiceI18nEditorProps extends NiceBaseProps {
313
468
  tutorial?: NiceComponentTutorial_2;
314
469
  }
315
470
 
471
+ /** Options of {@link i18nFileKind}. */
472
+ export declare interface NiceI18nFileKindOptions {
473
+ id?: string;
474
+ label?: string;
475
+ labelKey?: string;
476
+ /**
477
+ * The locale of a path and the path without it, or `null` when the path is not a translation.
478
+ * Default: `{prefix}.{locale}.i18n.json` (`en`, `pl`, `pt-BR`, `zh-CN`).
479
+ */
480
+ parse?(path: string): {
481
+ group: string;
482
+ locale: string;
483
+ } | null;
484
+ /** The path of a new language's file in a group. Default: `{group}.{locale}.i18n.json`. */
485
+ pathFor?(group: string, locale: string): string;
486
+ }
487
+
316
488
  export declare type NiceI18nValue = Record<string, Record<string, string>>;
317
489
 
318
- export declare const NiceManifestEditor: ForwardRefExoticComponent<NiceManifestEditorProps & RefAttributes<HTMLDivElement>>;
490
+ /** Options of {@link itemsFileKind}. */
491
+ export declare interface NiceItemsFileKindOptions<D> extends NiceArrayFileKindOptions {
492
+ /** A stored entry as a list item: with `definition` when the editor understands it. */
493
+ toItem(raw: unknown, index: number): NiceStudioItem<D>;
494
+ /** A list item back as the stored entry (merge onto `item.source` to keep unknown fields). */
495
+ fromItem(item: NiceStudioItem<D>): unknown;
496
+ }
319
497
 
320
- export declare interface NiceManifestEditorProps extends NiceStandardProps {
321
- /** The manifest object being edited (controlled). Omit it to let the editor keep its own. */
322
- value?: Record<string, unknown>;
323
- /** Initial manifest when uncontrolled. */
324
- defaultValue?: Record<string, unknown>;
325
- /** Section descriptors — each renders a NiceSchemaForm over the manifest. */
326
- sections?: NiceManifestSection[];
327
- /** Change callback with the full updated manifest. */
328
- onChange?: (manifest: Record<string, unknown>) => void;
329
- /** Offer a Form ⇄ JSON toggle in each section. Default `true`. */
330
- jsonView?: boolean;
331
- /** When provided, adds a "Scripts" tab hosting a NiceScriptRunner. */
332
- scriptRunner?: NiceScriptRunnerProps;
333
- /** Lifecycle triggers — when provided, adds a "Lifecycle" tab. */
334
- triggers?: NiceLifecycleTrigger[];
335
- /** Current hook bindings. */
336
- bindings?: NiceHookBinding[];
337
- /** Handlers offered in the lifecycle binding picker. */
338
- handlers?: NiceLifecycleHandlerOption[];
339
- /** Bindings change callback. */
340
- onBindingsChange?: (bindings: NiceHookBinding[]) => void;
341
- /** Revisions — when provided, adds a "History" tab. */
342
- revisions?: NiceRevision[];
343
- /** Rollback callback for the history tab. */
344
- onRollback?: (id: string) => void;
345
- /** Lazy content resolver for the history diff. */
346
- loadContent?: (id: string) => Promise<string>;
347
- /** Logs for the bottom dock — when provided, a NiceLogConsole is shown. */
348
- logs?: NiceLogEntry[];
349
- /** Clear-logs callback. */
350
- onClearLogs?: () => void;
351
- /** Extra tabs appended after the built-in ones (e.g. payment / webhook panels). */
352
- extraTabs?: NiceConsoleTab[];
353
- /** Manifest-level validation surfaced in the status bar. */
354
- validate?: (manifest: Record<string, unknown>) => NiceSchemaFormError[];
355
- /** Console theme. Default `'light'`. */
356
- theme?: 'dark' | 'light';
357
- /** Editor height. Default `560`. */
358
- height?: number | string;
359
- /** Optional guided tour. `true` = built-in; array/object = custom steps. Shows a "?" button. */
360
- tutorial?: NiceComponentTutorial;
498
+ /** Options of {@link jsonFileKind}. */
499
+ export declare interface NiceJsonFileKindOptions<M> {
500
+ id: string;
501
+ label: string;
502
+ labelKey?: string;
503
+ icon?: string;
504
+ match(path: string): boolean;
505
+ editor: NiceStudioEditorId;
506
+ /** The editor's model out of the file's parsed JSON. */
507
+ select(root: unknown, ctx: NiceStudioCodecContext): M;
508
+ /** The file's JSON with the model put back (return a new root; the text is patched in place). */
509
+ assign(root: unknown, model: M, ctx: NiceStudioCodecContext): unknown;
510
+ /** Identifies array items for the patch (see {@link NiceJsonPatchOptions.arrayKey}). */
511
+ arrayKey?: NiceJsonPatchOptions['arrayKey'];
512
+ }
513
+
514
+ /** Options of {@link patchJsonText}. */
515
+ export declare interface NiceJsonPatchOptions {
516
+ /**
517
+ * The property that identifies the items of an array (by JSON pointer of the array), so a
518
+ * removed or inserted item does not shift every item after it. Without it the items are
519
+ * matched by `name`, `id`, `code`, `key`, `slug`, `state` or `Id` when every item has a unique
520
+ * one, otherwise by position.
521
+ */
522
+ arrayKey?: (pointer: string) => string | undefined;
523
+ }
524
+
525
+ /** What {@link patchJsonTextDetailed} did. */
526
+ export declare interface NiceJsonPatchResult {
527
+ text: string;
528
+ /** `false`: the text could not be patched in place and was written anew in its format. */
529
+ exact: boolean;
530
+ /** Why it was written anew. */
531
+ reason?: string;
532
+ }
533
+
534
+ /**
535
+ * JSON text that keeps its look (NiceDevelopmentStudio).
536
+ *
537
+ * Seed files are written by hand and by many tools: a UTF-8 BOM, CRLF, two or four spaces or tabs,
538
+ * rows aligned in columns, `25.0` instead of `25`. Writing them back with `JSON.stringify` turns a
539
+ * one-field edit into a diff of the whole file. `patchJsonText` changes only the bytes of what
540
+ * changed: untouched values keep their exact text, a changed value replaces only its own token,
541
+ * added and removed members follow the indentation around them.
542
+ *
543
+ * No React and no dependencies — usable in Node (validators, CI) as well as in the studio.
544
+ */
545
+ /** How a JSON file is written. */
546
+ export declare interface NiceJsonTextFormat {
547
+ /** Starts with a UTF-8 byte order mark (kept as a leading U+FEFF). */
548
+ bom: boolean;
549
+ eol: '\n' | '\r\n';
550
+ /** One level of indentation (`' '`, `' '`, `'\t'`). */
551
+ indent: string;
552
+ /** Ends with a line break. */
553
+ finalNewline: boolean;
554
+ /** A space after the colon of a property. */
555
+ colonSpace: boolean;
361
556
  }
362
557
 
363
558
  /**
@@ -371,7 +566,7 @@ export declare interface NiceManifestEditorProps extends NiceStandardProps {
371
566
  export declare interface NiceManifestSection<TSchema extends JsonSchema = JsonSchema> {
372
567
  id: string;
373
568
  title: string;
374
- icon?: React.ReactNode;
569
+ icon?: default_2.ReactNode;
375
570
  /** JSON Schema describing this section's fields (subset of the manifest). */
376
571
  schema?: TSchema;
377
572
  /** Or the repo's field-descriptor model. */
@@ -380,80 +575,48 @@ export declare interface NiceManifestSection<TSchema extends JsonSchema = JsonSc
380
575
  uiSchema?: Record<string, Partial<NiceFormItem>>;
381
576
  }
382
577
 
383
- /** Pluggable persistence — implement over a filesystem, API, or in-memory store. */
384
- export declare interface NiceModuleDataProvider {
385
- listModules(): Promise<NiceModuleSummary[]>;
386
- loadModule(id: string): Promise<NiceModuleFiles>;
387
- saveModule(id: string, files: NiceModuleFiles): Promise<void>;
388
- createModule?(input: {
389
- id: string;
390
- name?: string;
391
- }): Promise<NiceModuleSummary>;
578
+ /** A module given to {@link createMemoryStudioProvider}. */
579
+ export declare interface NiceMemoryStudioModule {
580
+ id: string;
581
+ packageId?: string;
582
+ label?: string;
583
+ description?: string;
584
+ icon?: string;
585
+ version?: string;
586
+ readOnly?: boolean;
587
+ /** Its files: path → exact text. */
588
+ files: Record<string, string>;
392
589
  }
393
590
 
394
- export declare const NiceModuleEditor: ForwardRefExoticComponent<NiceModuleEditorProps & RefAttributes<HTMLDivElement>>;
395
-
396
- export declare interface NiceModuleEditorProps extends NiceStandardProps {
397
- /** Persistence adapter. */
398
- dataProvider: NiceModuleDataProvider;
399
- /** Manifest sections (schema-driven). Provide the real target schema (e.g. OmniVerk). */
400
- manifestSections?: NiceManifestSection[];
401
- /** Entity-editor configuration (schemas, ER preview slot). */
402
- entityConfig?: NiceModuleEntityConfig;
403
- /** Locales offered in the i18n editor. */
404
- locales?: string[];
405
- /** Extra module-level validation, merged with manifest-section schema validation. */
406
- validate?: (files: NiceModuleFiles) => NiceSchemaFormError[];
407
- /** Wires a Scripts tab (NiceScriptRunner). */
408
- scriptRunner?: NiceScriptRunnerProps;
409
- /** Wires a Lifecycle tab. */
410
- triggers?: NiceLifecycleTrigger[];
411
- bindings?: NiceHookBinding[];
412
- handlers?: NiceLifecycleHandlerOption[];
413
- onBindingsChange?: (bindings: NiceHookBinding[]) => void;
414
- /** Wires a History tab. */
415
- revisions?: NiceRevision[];
416
- onRollback?: (id: string) => void;
417
- loadContent?: (id: string) => Promise<string>;
418
- /** Console theme. Default `'light'`. */
419
- theme?: 'dark' | 'light';
420
- /** Editor height. Default `640`. */
421
- height?: number | string;
422
- /** Optional guided tour. `true` = built-in tour; array/object = custom steps. Shows a "?" button. */
423
- tutorial?: NiceComponentTutorial;
591
+ /** Options of {@link createMemoryStudioProvider}. */
592
+ export declare interface NiceMemoryStudioOptions {
593
+ workspaces: NiceMemoryStudioWorkspace[];
594
+ templates?: NiceStudioTemplate[];
595
+ /** Keep earlier versions of written files (default true). */
596
+ revisions?: boolean;
424
597
  }
425
598
 
426
- export declare interface NiceModuleEntityConfig {
427
- entityMetaSchema?: JsonSchema;
428
- fieldSchema?: JsonSchema;
429
- fieldsKey?: string;
430
- nameKey?: string;
431
- renderErPreview?: (entities: NiceEntity[]) => React.ReactNode;
599
+ /** {@link NiceStudioProvider} plus a way to read everything back. */
600
+ export declare interface NiceMemoryStudioProvider extends NiceStudioProvider {
601
+ /** The current state, in the shape the provider was created from. */
602
+ snapshot(): NiceMemoryStudioOptions;
432
603
  }
433
604
 
434
- /** The editable files of one module. */
435
- export declare interface NiceModuleFiles {
436
- manifest: Record<string, unknown>;
437
- entities?: NiceEntity[];
438
- i18n?: NiceI18nValue;
439
- /** The module's views (`*.view.json`) — unified `NiceViewDefinition` standard. */
440
- views?: NiceViewDefinition[];
441
- /** The module's workflows (`*.workflow.json`). */
442
- workflows?: NiceWorkflowDefinition[];
443
- /** The module's data sources (no-SQL query definitions). */
444
- dataSources?: NiceDataSourceDef[];
445
- /** The module's RBAC model (roles + per-resource access). */
446
- rbac?: NiceRbacModel;
447
- /** Any extra parts the adapter wants to round-trip untouched. */
448
- extra?: Record<string, unknown>;
605
+ /** A workspace given to {@link createMemoryStudioProvider}. */
606
+ export declare interface NiceMemoryStudioWorkspace extends NiceStudioWorkspace {
607
+ /** Stored packages; without them packages are the modules' `packageId`s. */
608
+ packages?: Array<Omit<NiceStudioPackage, 'workspaceId'>>;
609
+ modules: NiceMemoryStudioModule[];
449
610
  }
450
611
 
451
- /** A module entry shown in the browser. */
452
- export declare interface NiceModuleSummary {
612
+ /** Options of {@link objectFileKind}. */
613
+ export declare interface NiceObjectFileKindOptions {
453
614
  id: string;
454
- name?: string;
455
- category?: string;
456
- description?: string;
615
+ label: string;
616
+ labelKey?: string;
617
+ icon?: string;
618
+ editor: NiceStudioEditorId;
619
+ match(path: string): boolean;
457
620
  }
458
621
 
459
622
  export declare const NiceSchemaForm: ForwardRefExoticComponent<NiceSchemaFormProps & RefAttributes<HTMLDivElement>>;
@@ -499,9 +662,442 @@ export declare interface NiceSchemaFormProps extends NiceStandardProps {
499
662
  tutorial?: NiceComponentTutorial;
500
663
  }
501
664
 
665
+ /** What a file kind's decode and encode know about the module. */
666
+ export declare interface NiceStudioCodecContext {
667
+ moduleId: string;
668
+ /** All files of the module (e.g. to read the manifest while decoding views). */
669
+ files: readonly NiceStudioFile[];
670
+ locales: readonly string[];
671
+ }
672
+
673
+ /** A document of an open module: the files one editor works on. */
674
+ export declare interface NiceStudioDocument<M = unknown> {
675
+ /** Stable within the module: `${kind.id}:${group}`. */
676
+ key: string;
677
+ kind: NiceStudioFileKind<M>;
678
+ paths: string[];
679
+ /** For the explorer and the tab (the file name, or the group). */
680
+ label: string;
681
+ /** The decoded model; absent when decoding failed (`error`) — the document then opens raw. */
682
+ model?: M;
683
+ error?: string;
684
+ }
685
+
686
+ /** The built-in editors a file kind can open in. */
687
+ export declare type NiceStudioEditorId = 'manifest' | 'entities' | 'i18n' | 'views' | 'workflows' | 'permissions' | 'rbac' | 'dataSources' | 'seeds' | 'hooks' | 'script' | 'json' | 'text';
688
+
689
+ /** New and removed files of an encoded document. */
690
+ export declare interface NiceStudioEncoded {
691
+ files: Array<{
692
+ path: string;
693
+ text: string;
694
+ }>;
695
+ deleted?: string[];
696
+ }
697
+
698
+ /** Entity editor settings of a preset. */
699
+ export declare interface NiceStudioEntityOptions {
700
+ /** JSON Schema of an entity's own properties (name, table, flags). */
701
+ entityMetaSchema?: JsonSchema;
702
+ /** JSON Schema of one field. */
703
+ fieldSchema?: JsonSchema;
704
+ /** Property holding the fields. Default `fields`. */
705
+ fieldsKey?: string;
706
+ /** Property holding the name. Default `name`. */
707
+ nameKey?: string;
708
+ }
709
+
710
+ /** One file of a module: its path inside the module and its exact text (a BOM as a leading U+FEFF). */
711
+ export declare interface NiceStudioFile {
712
+ /** Relative to the module folder, `/`-separated (e.g. `inv.invoices.entities.json`, `services/x.js`). */
713
+ path: string;
714
+ text: string;
715
+ /** Opaque version for conflict checks (hash, `lastModified:size`, ETag). */
716
+ version?: string;
717
+ /** This file cannot be written (e.g. shipped and read-only in production). */
718
+ readOnly?: boolean;
719
+ }
720
+
721
+ /** A change the studio asks the provider to write. */
722
+ export declare type NiceStudioFileChange = {
723
+ type: 'write';
724
+ path: string;
725
+ text: string;
726
+ baseVersion?: string;
727
+ } | {
728
+ type: 'delete';
729
+ path: string;
730
+ baseVersion?: string;
731
+ };
732
+
733
+ /**
734
+ * A kind of file and how the studio edits it. A document is one file, or several when `group`
735
+ * puts them together (the translations of one prefix in every locale).
736
+ */
737
+ export declare interface NiceStudioFileKind<M = unknown> {
738
+ id: string;
739
+ label: string;
740
+ labelKey?: string;
741
+ /** NiceIcon name. */
742
+ icon?: string;
743
+ match(path: string): boolean;
744
+ /** The document a file belongs to (files with the same group open together). Default: the path. */
745
+ group?(path: string): string;
746
+ editor: NiceStudioEditorId;
747
+ /** The files of one document → the editor's model. Throwing opens the files as raw JSON / text. */
748
+ decode(files: readonly NiceStudioFile[], ctx: NiceStudioCodecContext): M;
749
+ /** The model → the document's files (only their text; unchanged files may be returned as they were). */
750
+ encode(model: M, files: readonly NiceStudioFile[], ctx: NiceStudioCodecContext): NiceStudioEncoded;
751
+ }
752
+
753
+ /** A generated module, before it is created. */
754
+ export declare interface NiceStudioGeneratedModule {
755
+ id: string;
756
+ packageId?: string;
757
+ files: Array<{
758
+ path: string;
759
+ text: string;
760
+ }>;
761
+ }
762
+
763
+ /** A problem found in a module. */
764
+ export declare interface NiceStudioIssue {
765
+ severity: 'error' | 'warning' | 'info';
766
+ /** Stable code of the rule (e.g. `manifest.required`). */
767
+ code?: string;
768
+ /** English text. */
769
+ message: string;
770
+ /** Translation key of `message`, with `{name}` placeholders filled from `params`. */
771
+ messageKey?: string;
772
+ params?: Record<string, string | number>;
773
+ moduleId?: string;
774
+ /** The file it is about. */
775
+ path?: string;
776
+ /** Where in that file: a JSON pointer (`/entities/0/fields/2`). */
777
+ pointer?: string;
778
+ }
779
+
780
+ /**
781
+ * An entry of a list document — a view, a workflow — that its editor may or may not understand.
782
+ * An entry in a shape the editor does not know keeps only `source` and is edited as raw JSON.
783
+ */
784
+ export declare interface NiceStudioItem<D> {
785
+ /** Stable within the document (an id, a name, a position). */
786
+ key: string;
787
+ label: string;
788
+ /** The editor's model of the entry; absent for an entry edited raw. */
789
+ definition?: D;
790
+ /** The entry as it is stored. */
791
+ source: unknown;
792
+ /** Why the entry is edited raw (shown to the user). */
793
+ rawReason?: string;
794
+ }
795
+
796
+ /** What validators and generators get. */
797
+ export declare interface NiceStudioModuleContext {
798
+ key: NiceStudioModuleKey;
799
+ files: readonly NiceStudioFile[];
800
+ documents: readonly NiceStudioDocument[];
801
+ }
802
+
803
+ /** Which module, in which workspace. */
804
+ export declare interface NiceStudioModuleKey {
805
+ workspaceId: string;
806
+ id: string;
807
+ }
808
+
809
+ /** What `modulePanels` gets for the module open in the studio. */
810
+ export declare interface NiceStudioModulePanelContext {
811
+ module: NiceStudioModuleKey;
812
+ files: readonly NiceStudioFile[];
813
+ /** Whether the module has unsaved edits. */
814
+ dirty: boolean;
815
+ }
816
+
817
+ /** A module as listed in the explorer. */
818
+ export declare interface NiceStudioModuleRef extends NiceStudioModuleKey {
819
+ packageId?: string;
820
+ label: string;
821
+ description?: string;
822
+ icon?: string;
823
+ version?: string;
824
+ /** Where it lives, for display (a folder, a URL). */
825
+ location?: string;
826
+ readOnly?: boolean;
827
+ /** Another workspace's module with the same id wins over this one (e.g. shipped over overlay). */
828
+ shadowedBy?: string;
829
+ /** Its file paths, when the listing knows them (lets the explorer show files without reading). */
830
+ files?: string[];
831
+ /** Extra text the explorer's search looks in. */
832
+ search?: string;
833
+ }
834
+
835
+ /** The answers of the new-module wizard. */
836
+ export declare interface NiceStudioModuleSpec {
837
+ workspaceId: string;
838
+ packageId?: string;
839
+ /** Display name, e.g. "Bike rental". */
840
+ name: string;
841
+ description?: string;
842
+ icon?: string;
843
+ /** Entities to create, in the preset's entity shape. */
844
+ entities: Array<Record<string, unknown>>;
845
+ locales: string[];
846
+ /** Scaffold a list and a form view per entity. */
847
+ views?: boolean;
848
+ /** Scaffold viewer / editor / admin permissions. */
849
+ permissions?: boolean;
850
+ }
851
+
852
+ /** A group of modules in a workspace (a category, a product line). */
853
+ export declare interface NiceStudioPackage {
854
+ id: string;
855
+ workspaceId: string;
856
+ label: string;
857
+ description?: string;
858
+ icon?: string;
859
+ /** Computed from the modules (e.g. their `category`) rather than stored: it cannot be edited. */
860
+ derived?: boolean;
861
+ readOnly?: boolean;
862
+ }
863
+
864
+ /** An extra panel on a module's overview (payments, webhooks — anything host-specific). */
865
+ export declare interface NiceStudioPanel {
866
+ key: string;
867
+ label: string;
868
+ content: default_2.ReactNode;
869
+ }
870
+
871
+ /** The model of the `permissions` editor: permission codes and the groups (roles) granting them. */
872
+ export declare interface NiceStudioPermissions {
873
+ permissions: Array<{
874
+ code: string;
875
+ name?: string;
876
+ description?: string;
877
+ }>;
878
+ groups: Array<{
879
+ id: string;
880
+ label: string;
881
+ description?: string;
882
+ permissions: string[];
883
+ }>;
884
+ }
885
+
886
+ /**
887
+ * How one host's modules look: which files there are (kinds), what the manifest holds (sections),
888
+ * which languages are required, how a module is checked and generated.
889
+ */
890
+ export declare interface NiceStudioPreset {
891
+ id: string;
892
+ /** Tried in order; a path no kind matches opens as raw JSON (`*.json`) or text. */
893
+ kinds: NiceStudioFileKind[];
894
+ /** The manifest's sections, each a form over part of the manifest. */
895
+ manifestSections?: NiceManifestSection[];
896
+ entities?: NiceStudioEntityOptions;
897
+ /** Languages offered for translations. */
898
+ locales?: string[];
899
+ /** Languages every module must have. */
900
+ requiredLocales?: string[];
901
+ /** The module's id from its files (e.g. the manifest's `packageName`). */
902
+ moduleId?(files: readonly NiceStudioFile[]): string | undefined;
903
+ validateModule?(ctx: NiceStudioModuleContext): NiceStudioIssue[];
904
+ generateModule?(spec: NiceStudioModuleSpec, ctx: {
905
+ existingIds: ReadonlySet<string>;
906
+ }): Promise<NiceStudioGeneratedModule>;
907
+ duplicateModule?(files: readonly NiceStudioFile[], target: {
908
+ id: string;
909
+ packageId?: string;
910
+ name?: string;
911
+ }): Promise<NiceStudioGeneratedModule>;
912
+ /** A new, empty file of a kind (the explorer's "New file"). */
913
+ newFile?(kindId: string, ctx: NiceStudioModuleContext): {
914
+ path: string;
915
+ text: string;
916
+ } | undefined;
917
+ /** Lifecycle triggers offered by a `hooks` document. */
918
+ hooks?: {
919
+ triggers: Array<{
920
+ id: string;
921
+ label: string;
922
+ description?: string;
923
+ group?: string;
924
+ }>;
925
+ handlers?: Array<{
926
+ id: string;
927
+ label: string;
928
+ description?: string;
929
+ }>;
930
+ };
931
+ /** Extra template properties (shown in the template editor). */
932
+ templateSchema?: JsonSchema;
933
+ }
934
+
935
+ /**
936
+ * How the studio reaches the host's modules. Only the four list/read/write methods are needed;
937
+ * each optional one turns on the matching feature (create, delete, packages, templates,
938
+ * validation, history) and its absence hides it.
939
+ */
940
+ export declare interface NiceStudioProvider {
941
+ listWorkspaces(): Promise<NiceStudioWorkspace[]>;
942
+ listModules(workspaceId: string): Promise<NiceStudioModuleRef[]>;
943
+ readModule(key: NiceStudioModuleKey): Promise<NiceStudioFile[]>;
944
+ /** Writes only the files given (the studio drops changes that leave a file's text as it was). */
945
+ writeModule(key: NiceStudioModuleKey, changes: NiceStudioFileChange[]): Promise<NiceStudioWriteResult>;
946
+ /** Stored packages. Absent: the explorer groups modules by their `packageId`. */
947
+ listPackages?(workspaceId: string): Promise<NiceStudioPackage[]>;
948
+ createModule?(input: {
949
+ workspaceId: string;
950
+ packageId?: string;
951
+ id: string;
952
+ files: Array<{
953
+ path: string;
954
+ text: string;
955
+ }>;
956
+ }): Promise<NiceStudioModuleRef>;
957
+ deleteModule?(key: NiceStudioModuleKey): Promise<void>;
958
+ savePackage?(pkg: NiceStudioPackage): Promise<NiceStudioPackage>;
959
+ deletePackage?(ref: {
960
+ workspaceId: string;
961
+ id: string;
962
+ }): Promise<void>;
963
+ listTemplates?(): Promise<NiceStudioTemplate[]>;
964
+ /** `previousId`: the template's id before a rename. */
965
+ saveTemplate?(template: NiceStudioTemplate, options?: {
966
+ previousId?: string;
967
+ }): Promise<NiceStudioTemplate>;
968
+ deleteTemplate?(id: string): Promise<void>;
969
+ /** Server-side checks, on top of the preset's own. */
970
+ validate?(key: NiceStudioModuleKey, files: NiceStudioFile[]): Promise<NiceStudioIssue[]>;
971
+ listRevisions?(key: NiceStudioModuleKey, path?: string): Promise<NiceStudioRevision[]>;
972
+ readRevision?(key: NiceStudioModuleKey, revisionId: string, path?: string): Promise<string>;
973
+ rollback?(key: NiceStudioModuleKey, revisionId: string, path?: string): Promise<void>;
974
+ }
975
+
976
+ /** A saved earlier version of a module or one of its files. */
977
+ export declare interface NiceStudioRevision {
978
+ id: string;
979
+ /** When it was saved: epoch ms. */
980
+ timestamp: number;
981
+ label?: string;
982
+ author?: string;
983
+ summary?: string;
984
+ /** The file it belongs to (absent: the whole module). */
985
+ path?: string;
986
+ }
987
+
988
+ /** The model of the `seeds` editor: rows per entity, plus demo rows. */
989
+ export declare interface NiceStudioSeeds {
990
+ seeds: Record<string, Array<Record<string, unknown>>>;
991
+ demoSeeds?: Record<string, Array<Record<string, unknown>>>;
992
+ }
993
+
994
+ /** A template: a set of modules installed together (an industry bundle). */
995
+ export declare interface NiceStudioTemplate {
996
+ id: string;
997
+ category?: string;
998
+ subCategory?: string;
999
+ parentId?: string;
1000
+ icon?: string;
1001
+ sortOrder?: number;
1002
+ tags?: string[];
1003
+ /** Name and description per language: `{ en: { name, description } }`. */
1004
+ translations: Record<string, {
1005
+ name: string;
1006
+ description?: string;
1007
+ }>;
1008
+ modules: NiceStudioTemplateModule[];
1009
+ /** Anything else the host's template carries, kept as it is. */
1010
+ extra?: Record<string, unknown>;
1011
+ readOnly?: boolean;
1012
+ }
1013
+
1014
+ /** A module of a template. */
1015
+ export declare interface NiceStudioTemplateModule {
1016
+ moduleId: string;
1017
+ required?: boolean;
1018
+ condition?: string;
1019
+ description?: string;
1020
+ }
1021
+
1022
+ /** Translations of one document: `{ en: { key: text }, pl: { … } }` (the shape of NiceI18nEditor). */
1023
+ export declare type NiceStudioTranslations = Record<string, Record<string, string>>;
1024
+
1025
+ /** What `renderViewPreview` gets: the view being edited and the module's current files. */
1026
+ export declare interface NiceStudioViewPreviewContext {
1027
+ module: NiceStudioModuleKey;
1028
+ /** The view as listed (its stored form in `source`, the editor's model in `definition`). */
1029
+ item: NiceStudioItem<NiceViewDefinition>;
1030
+ /** The module's files with the unsaved edits applied. */
1031
+ files: readonly NiceStudioFile[];
1032
+ }
1033
+
1034
+ /** A place modules live in — a project: shipped seeds, a custom overlay, a tenant's modules. */
1035
+ export declare interface NiceStudioWorkspace {
1036
+ id: string;
1037
+ label: string;
1038
+ description?: string;
1039
+ icon?: string;
1040
+ /** Modules here can be opened but not changed. */
1041
+ readOnly?: boolean;
1042
+ }
1043
+
1044
+ /** The outcome of writing a module. */
1045
+ export declare type NiceStudioWriteResult = {
1046
+ ok: true;
1047
+ versions?: Record<string, string>;
1048
+ revision?: string;
1049
+ } | {
1050
+ ok: false;
1051
+ conflicts: Array<{
1052
+ path: string;
1053
+ currentVersion?: string;
1054
+ }>;
1055
+ };
1056
+
1057
+ /** A file whose whole content is the model (a manifest, an access model). */
1058
+ export declare function objectFileKind<T extends object>(o: NiceObjectFileKindOptions): NiceStudioFileKind<T>;
1059
+
1060
+ /** Parses JSON text that may start with a BOM, and tells how it is written. */
1061
+ export declare function parseJsonText(text: string): {
1062
+ value: unknown;
1063
+ format: NiceJsonTextFormat;
1064
+ };
1065
+
1066
+ /**
1067
+ * `previous` with its content replaced by `next`, changing as few bytes as possible. Falls back
1068
+ * to {@link stringifyJsonText} in the file's own format when the text cannot be patched (invalid
1069
+ * JSON, duplicate keys) or the patch would not read back as `next`.
1070
+ */
1071
+ export declare function patchJsonText(previous: string, next: unknown, options?: NiceJsonPatchOptions): string;
1072
+
1073
+ /** {@link patchJsonText}, also telling whether the patch was exact. */
1074
+ export declare function patchJsonTextDetailed(previous: string, next: unknown, options?: NiceJsonPatchOptions): NiceJsonPatchResult;
1075
+
1076
+ /** The translations inside a file: `translations`, `keys`, or the whole file when it is a flat map. */
1077
+ export declare function readTranslations(root: unknown): Record<string, string>;
1078
+
1079
+ /** The kind a path opens with: the first that matches, else JSON or text. */
1080
+ export declare function resolveFileKind(kinds: readonly NiceStudioFileKind[], path: string): NiceStudioFileKind;
1081
+
1082
+ declare type Row = Record<string, unknown>;
1083
+
1084
+ declare type Row_2 = Record<string, unknown>;
1085
+
1086
+ /** Parses JSON without a BOM and returns `fallback` when the text is not JSON. */
1087
+ export declare function safeJson<T = unknown>(text: string, fallback: T): T;
1088
+
502
1089
  /** Convert a FormSchema into DevExtreme-style form items. */
503
1090
  export declare function schemaToFormItems(schema: FormSchema): any[];
504
1091
 
1092
+ /** A file-name-safe id out of a display name: "Bike rental" → `bike-rental`. */
1093
+ export declare function slugifyModuleId(name: string): string;
1094
+
1095
+ /** Writes `value` in a given format (defaults: two spaces, LF, final newline, no BOM). */
1096
+ export declare function stringifyJsonText(value: unknown, format?: Partial<NiceJsonTextFormat>): string;
1097
+
1098
+ /** Any other file, edited as text. */
1099
+ export declare const textFallbackKind: NiceStudioFileKind<string>;
1100
+
505
1101
  /**
506
1102
  * Validate a value object against a (subset of) Draft-07 JSON Schema.
507
1103
  * Covers required, type, enum, minLength/maxLength, minimum/maximum and pattern.
@@ -514,4 +1110,7 @@ export declare function validateFormSchema(schema: FormSchema): {
514
1110
  errors: string[];
515
1111
  };
516
1112
 
1113
+ /** The file with its translations replaced, in the same place they were. */
1114
+ export declare function writeTranslations(root: unknown, entries: Record<string, string>): unknown;
1115
+
517
1116
  export { }