@inspectorhub/field-ui 0.4.0 → 0.6.0

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 CHANGED
@@ -65,6 +65,10 @@ What the host has to provide:
65
65
  down explicitly; leaving the slot out does not turn the gate off.
66
66
  - `slots.renderUnsavedGuard`, if leaving the editor with unsaved work should be
67
67
  intercepted. Absent means leaving is never intercepted.
68
+ - `slots.renderStatus`, an optional status element of the host's own (an offline indicator, say). The editor shows it
69
+ beside the save state in the desktop header and in the phone and tablet app bars, and never in place of it. Absent,
70
+ nothing is added. The host owns its semantics. It must be pure and may be called more than once per render. It cannot
71
+ shrink or truncate, so keep it small: the phone app bar shares one row with the title.
68
72
  - The theme (see Theme) and the peer dependencies (see below).
69
73
 
70
74
  A member of `urls`, `resources` or `slots` that the host leaves out hides the
@@ -138,6 +142,15 @@ signatures):
138
142
  neutral notice and counts the batch as saved, not failed.
139
143
  - `urls`: `FieldUrls`, the address builders for photos, reports, presence and
140
144
  in-app paths.
145
+ `photo()` is synchronous; a host that can only produce an address later (a photo it fetches and caches) provides the
146
+ optional `subscribe(listener)` and calls the listener whenever any photo address may have changed. The editor then asks
147
+ `photo()` again and its thumbnails, viewer and previews show the new address. Calls may be batched; `subscribe` returns
148
+ the unsubscribe function. Absent, nothing changes.
149
+ `photo()` also takes an optional third argument, `size`: a `PhotoSize` (`'thumb'`, `'view'` or `'original'`). It is a
150
+ hint. The editor asks for `thumb` in photo strips and the side-rail preview, and for `original` where the exact bytes
151
+ matter (the side-rail download, the source a crop or an annotation is made from, the photo studio). `view` is part
152
+ of the contract but nothing in the editor requests it yet. A host with smaller copies may return one for `thumb`
153
+ or `view`; a host without them ignores the argument and nothing changes.
141
154
  - `resources`: `FieldResources`, optional capabilities (preferences, canned
142
155
  comments, cost items, repair items, media pool, settings sheet, AI assist,
143
156
  publish readiness, template search, version history, video). A member the
@@ -524,6 +524,12 @@ interface TagLibraryEntry {
524
524
  name: string;
525
525
  color: string;
526
526
  }
527
+ /** The tags on each checklist item of one inspection, keyed by the item's id (the editor's chips). */
528
+ type ItemTagMap = Record<string, Array<{
529
+ id: string;
530
+ name: string;
531
+ color?: string;
532
+ }>>;
527
533
  /** The loader returns `{ id, name, color }` rows. */
528
534
  interface DefectCategory {
529
535
  id: string;
@@ -1156,7 +1162,11 @@ type PendingMediaRecord = (PendingMediaBase & {
1156
1162
  meta: PhotoAnnotateMeta;
1157
1163
  });
1158
1164
  interface PendingMediaStore {
1159
- /** Must reject on failure. */
1165
+ /**
1166
+ * Must reject on failure. A host may attach a stable `code` to the error;
1167
+ * the editor recognizes `UNSUPPORTED_TYPE` and `TOO_LARGE` for safe photo
1168
+ * guidance. Unknown errors keep the generic rejection notice.
1169
+ */
1160
1170
  put(rec: PendingMediaRecord): Promise<void>;
1161
1171
  get(pendingId: string): Promise<PendingMediaRecord | null>;
1162
1172
  list(inspectionId?: string): Promise<PendingMediaRecord[]>;
@@ -1172,10 +1182,12 @@ interface MediaFileResult {
1172
1182
  index: number;
1173
1183
  ok: boolean;
1174
1184
  key?: string;
1175
- /** `NO_KEY`, `HTTP_<status>` or `EXCEPTION`. */
1185
+ /** A fixed host code such as `TOO_LARGE`, `NO_KEY`, `HTTP_<status>` or `EXCEPTION`; never render arbitrary values. */
1176
1186
  error?: string;
1177
1187
  /** The upload failed but the host kept the bytes on the device (see `MediaUploader`): not a lost photo. */
1178
1188
  kept?: boolean;
1189
+ /** The host refused the file itself (see `MediaUploader`): nothing is waiting to be saved, so it is not a failed save. */
1190
+ permanent?: boolean;
1179
1191
  }
1180
1192
  /**
1181
1193
  * Online media upload. It is NOT a `FieldCommand`: the editor never routes photo
@@ -1193,7 +1205,8 @@ interface MediaFileResult {
1193
1205
  * - `kind: 'crop'`: `key` is the derived `croppedKey`.
1194
1206
  * - `kind: 'annotate'`: `key` is the derived `annotatedKey`.
1195
1207
  *
1196
- * Failure is `{ ok: false, error }` and never a throw. A host that stored the bytes on the device and wrote the
1208
+ * Failure is `{ ok: false, error }` and never a throw. `permanent: true` says the host will refuse these very bytes every time
1209
+ * (the server rejected the file itself, not the connection): the offline drain then stops retrying the queued record. A host that stored the bytes on the device and wrote the
1197
1210
  * pending entry itself (see `appendPendingPhoto`) adds `kept: true`: the photo is not lost and uploads later, so the
1198
1211
  * editor counts it as saved on the device instead of as a failure.
1199
1212
  */
@@ -1206,6 +1219,7 @@ interface MediaUploader {
1206
1219
  ok: false;
1207
1220
  error: string;
1208
1221
  kept?: true;
1222
+ permanent?: true;
1209
1223
  }>;
1210
1224
  }
1211
1225
 
@@ -1362,8 +1376,21 @@ interface CollabConnector {
1362
1376
  }): ResultsDocHandle;
1363
1377
  purge(inspectionId: string): Promise<void>;
1364
1378
  }
1379
+ /** How much picture a caller needs: `thumb` (a tile), `view` (a full-screen viewer) or `original` (a download, or a crop or annotation source). */
1380
+ type PhotoSize = 'thumb' | 'view' | 'original';
1365
1381
  interface FieldUrls {
1366
- photo(inspectionId: string, key: string): string;
1382
+ /**
1383
+ * The address of a photo. `size` is an optional hint: a host with smaller copies may return one for `thumb` or
1384
+ * `view`; a host without them ignores it and answers as before. `original` is always the exact stored bytes.
1385
+ */
1386
+ photo(inspectionId: string, key: string, size?: PhotoSize): string;
1387
+ /**
1388
+ * Optional. `photo()` is synchronous, so a host that can only produce an address later (a photo it fetches and
1389
+ * caches, a signed address it renews) calls the listener whenever any photo address may have changed; the editor then
1390
+ * asks `photo()` again and its thumbnails, viewer and previews show the new address. Calls may be batched. Returns
1391
+ * the unsubscribe function. Absent: addresses are read when the editor renders, as before.
1392
+ */
1393
+ subscribe?(listener: () => void): () => void;
1367
1394
  reportPreview(tenantSlug: string, inspectionId: string): string | null;
1368
1395
  reportPdf(inspectionId: string): string | null;
1369
1396
  /**
@@ -1431,6 +1458,20 @@ interface FieldResources {
1431
1458
  id?: string;
1432
1459
  }>>;
1433
1460
  };
1461
+ /**
1462
+ * The tags on each checklist item of one inspection (the web host serves it from
1463
+ * `/resources/inspection-item-tags`). `list` never rejects: `null` means the host could not read it, and the
1464
+ * editor then shows what it already has. `add` and `remove` never reject either: a not-ok answer means the host
1465
+ * did not store the change, and the editor takes it back. Both are idempotent (adding a tag that is attached, or
1466
+ * removing one that is not, changes nothing), and the tag must be one of the company's own (`EditorData.tagLibrary`).
1467
+ * Absent means the host cannot keep item tags: the editor holds them in memory for the session only, as it did
1468
+ * before this member existed.
1469
+ */
1470
+ itemTags?: {
1471
+ list(inspectionId: string): Promise<ItemTagMap | null>;
1472
+ add(inspectionId: string, itemId: string, tagId: string): Promise<CommandResult>;
1473
+ remove(inspectionId: string, itemId: string, tagId: string): Promise<CommandResult>;
1474
+ };
1434
1475
  /** The tenant's repair-item catalogue (it is not per inspection). `list` never rejects: a failed read answers none. */
1435
1476
  repairItems?: {
1436
1477
  list(): Promise<RepairItemOption[]>;
@@ -1561,5 +1602,5 @@ interface FieldDataSource {
1561
1602
  platform: 'web' | 'ios' | 'android';
1562
1603
  }
1563
1604
 
1564
- export { METADATA_PRESETS as M, isDecodeImageError as aw, resolvePcaNarrative as ax, DecodeImageError as t };
1565
- export type { PsqView as $, AiAssistInput as A, BulkCreateUnitsBody as B, CommandResult as C, DateFormat as D, EditorData as E, FieldCommand as F, FieldResources as G, FieldUrls as H, InspectionPrefs as I, GalleryPhoto as J, InspectionUnit as K, MediaFileResult as L, MediaPoolListing as N, MediaUploader as O, NotifyOptions as P, NotifyVariant as Q, OutboundCoolingWindow as R, PcaNarrative as S, PcaNarrativeData as T, PendingMediaRecord as U, PendingMediaStore as V, PhotoAnnotateMeta as W, PhotoCropMeta as X, PhotoCropTransform as Y, PhotoUploadMeta as Z, PropertyMetaField as _, CommandData as a, PublishBlockingDefect as a0, PublishReadiness as a1, RatingLevel as a2, RelianceText as a3, RepairItemOption as a4, ReportLinkTtl as a5, ReportProfileOption as a6, ReportSignoffView as a7, ResultMap as a8, ResultsDocHandle as a9, RevisionStatus as aa, SaveStructureTemplateCommand as ab, SchemaItem as ac, SchemaSection as ad, SessionInfo as ae, SettingsSheetData as af, StatutoryCoverage as ag, StatutoryDetails as ah, TagLibraryEntry as ai, TemplateItemBody as aj, TemplateSchema as ak, TemplateSearchResult as al, TemplateSnapshot as am, TemplateSummary as an, TimeFormat as ao, UnitCommand as ap, UnitProgress as aq, VersionSnapshotContent as ar, VersionSnapshotEntry as as, VideoFinalizeInput as at, VideoUploadRef as au, VideoUploadTicket as av, FieldDataSource as b, AiAssistResult as c, AutoAdvanceMode as d, AutofillReason as e, CollabConnector as f, CommandDataMap as g, CommandKey as h, CommentsLibraryEntry as i, CommentsLibraryQuery as j, CommentsLibraryRow as k, CommercialPresets as l, ComplianceCommand as m, CompliancePanelData as n, CostItemView as o, CostItemWrite as p, CostItemsListing as q, CoverPhotoOption as r, DecodeImage as s, DecodeImageOptions as u, DecodedImage as v, DefectCategory as w, DocumentReviewItemView as x, EditorInspection as y, ExecuteOptions as z };
1605
+ export { METADATA_PRESETS as M, isDecodeImageError as ax, resolvePcaNarrative as ay, DecodeImageError as t };
1606
+ export type { PropertyMetaField as $, AiAssistInput as A, BulkCreateUnitsBody as B, CommandResult as C, DateFormat as D, EditorData as E, FieldCommand as F, FieldResources as G, FieldUrls as H, InspectionPrefs as I, GalleryPhoto as J, InspectionUnit as K, MediaFileResult as L, MediaPoolListing as N, MediaUploader as O, NotifyOptions as P, NotifyVariant as Q, OutboundCoolingWindow as R, PcaNarrative as S, PcaNarrativeData as T, PendingMediaRecord as U, PendingMediaStore as V, PhotoAnnotateMeta as W, PhotoCropMeta as X, PhotoCropTransform as Y, PhotoSize as Z, PhotoUploadMeta as _, CommandData as a, PsqView as a0, PublishBlockingDefect as a1, PublishReadiness as a2, RatingLevel as a3, RelianceText as a4, RepairItemOption as a5, ReportLinkTtl as a6, ReportProfileOption as a7, ReportSignoffView as a8, ResultMap as a9, ResultsDocHandle as aa, RevisionStatus as ab, SaveStructureTemplateCommand as ac, SchemaItem as ad, SchemaSection as ae, SessionInfo as af, SettingsSheetData as ag, StatutoryCoverage as ah, StatutoryDetails as ai, TagLibraryEntry as aj, TemplateItemBody as ak, TemplateSchema as al, TemplateSearchResult as am, TemplateSnapshot as an, TemplateSummary as ao, TimeFormat as ap, UnitCommand as aq, UnitProgress as ar, VersionSnapshotContent as as, VersionSnapshotEntry as at, VideoFinalizeInput as au, VideoUploadRef as av, VideoUploadTicket as aw, FieldDataSource as b, AiAssistResult as c, AutoAdvanceMode as d, AutofillReason as e, CollabConnector as f, CommandDataMap as g, CommandKey as h, CommentsLibraryEntry as i, CommentsLibraryQuery as j, CommentsLibraryRow as k, CommercialPresets as l, ComplianceCommand as m, CompliancePanelData as n, CostItemView as o, CostItemWrite as p, CostItemsListing as q, CoverPhotoOption as r, DecodeImage as s, DecodeImageOptions as u, DecodedImage as v, DefectCategory as w, DocumentReviewItemView as x, EditorInspection as y, ExecuteOptions as z };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { F as FieldCommand, C as CommandResult, a as CommandData, b as FieldDataSource, E as EditorData, I as InspectionPrefs } from './data-source-IaWUdrIc.js';
2
- export { A as AiAssistInput, c as AiAssistResult, d as AutoAdvanceMode, e as AutofillReason, B as BulkCreateUnitsBody, f as CollabConnector, g as CommandDataMap, h as CommandKey, i as CommentsLibraryEntry, j as CommentsLibraryQuery, k as CommentsLibraryRow, l as CommercialPresets, m as ComplianceCommand, n as CompliancePanelData, o as CostItemView, p as CostItemWrite, q as CostItemsListing, r as CoverPhotoOption, D as DateFormat, s as DecodeImage, t as DecodeImageError, u as DecodeImageOptions, v as DecodedImage, w as DefectCategory, x as DocumentReviewItemView, y as EditorInspection, z as ExecuteOptions, G as FieldResources, H as FieldUrls, J as GalleryPhoto, K as InspectionUnit, M as METADATA_PRESETS, L as MediaFileResult, N as MediaPoolListing, O as MediaUploader, P as NotifyOptions, Q as NotifyVariant, R as OutboundCoolingWindow, S as PcaNarrative, T as PcaNarrativeData, U as PendingMediaRecord, V as PendingMediaStore, W as PhotoAnnotateMeta, X as PhotoCropMeta, Y as PhotoCropTransform, Z as PhotoUploadMeta, _ as PropertyMetaField, $ as PsqView, a0 as PublishBlockingDefect, a1 as PublishReadiness, a2 as RatingLevel, a3 as RelianceText, a4 as RepairItemOption, a5 as ReportLinkTtl, a6 as ReportProfileOption, a7 as ReportSignoffView, a8 as ResultMap, a9 as ResultsDocHandle, aa as RevisionStatus, ab as SaveStructureTemplateCommand, ac as SchemaItem, ad as SchemaSection, ae as SessionInfo, af as SettingsSheetData, ag as StatutoryCoverage, ah as StatutoryDetails, ai as TagLibraryEntry, aj as TemplateItemBody, ak as TemplateSchema, al as TemplateSearchResult, am as TemplateSnapshot, an as TemplateSummary, ao as TimeFormat, ap as UnitCommand, aq as UnitProgress, ar as VersionSnapshotContent, as as VersionSnapshotEntry, at as VideoFinalizeInput, au as VideoUploadRef, av as VideoUploadTicket, aw as isDecodeImageError, ax as resolvePcaNarrative } from './data-source-IaWUdrIc.js';
1
+ import { F as FieldCommand, C as CommandResult, a as CommandData, b as FieldDataSource, E as EditorData, I as InspectionPrefs } from './data-source-Do9_Rv50.js';
2
+ export { A as AiAssistInput, c as AiAssistResult, d as AutoAdvanceMode, e as AutofillReason, B as BulkCreateUnitsBody, f as CollabConnector, g as CommandDataMap, h as CommandKey, i as CommentsLibraryEntry, j as CommentsLibraryQuery, k as CommentsLibraryRow, l as CommercialPresets, m as ComplianceCommand, n as CompliancePanelData, o as CostItemView, p as CostItemWrite, q as CostItemsListing, r as CoverPhotoOption, D as DateFormat, s as DecodeImage, t as DecodeImageError, u as DecodeImageOptions, v as DecodedImage, w as DefectCategory, x as DocumentReviewItemView, y as EditorInspection, z as ExecuteOptions, G as FieldResources, H as FieldUrls, J as GalleryPhoto, K as InspectionUnit, M as METADATA_PRESETS, L as MediaFileResult, N as MediaPoolListing, O as MediaUploader, P as NotifyOptions, Q as NotifyVariant, R as OutboundCoolingWindow, S as PcaNarrative, T as PcaNarrativeData, U as PendingMediaRecord, V as PendingMediaStore, W as PhotoAnnotateMeta, X as PhotoCropMeta, Y as PhotoCropTransform, Z as PhotoSize, _ as PhotoUploadMeta, $ as PropertyMetaField, a0 as PsqView, a1 as PublishBlockingDefect, a2 as PublishReadiness, a3 as RatingLevel, a4 as RelianceText, a5 as RepairItemOption, a6 as ReportLinkTtl, a7 as ReportProfileOption, a8 as ReportSignoffView, a9 as ResultMap, aa as ResultsDocHandle, ab as RevisionStatus, ac as SaveStructureTemplateCommand, ad as SchemaItem, ae as SchemaSection, af as SessionInfo, ag as SettingsSheetData, ah as StatutoryCoverage, ai as StatutoryDetails, aj as TagLibraryEntry, ak as TemplateItemBody, al as TemplateSchema, am as TemplateSearchResult, an as TemplateSnapshot, ao as TemplateSummary, ap as TimeFormat, aq as UnitCommand, ar as UnitProgress, as as VersionSnapshotContent, at as VersionSnapshotEntry, au as VideoFinalizeInput, av as VideoUploadRef, aw as VideoUploadTicket, ax as isDecodeImageError, ay as resolvePcaNarrative } from './data-source-Do9_Rv50.js';
3
3
  import * as React from 'react';
4
4
  import { ReactNode } from 'react';
5
5
  import * as Y from 'yjs';
@@ -50,6 +50,13 @@ interface FieldHostSlots {
50
50
  renderUnsavedGuard?: (props: {
51
51
  atRisk: boolean;
52
52
  }) => ReactNode;
53
+ /**
54
+ * A status element of the host's own (an offline indicator, say), shown beside the save state in the editor's header
55
+ * (desktop) and app bar (phone and tablet). It adds to the save state and never replaces it. Absent, or returning
56
+ * nothing, leaves the header as it was. It must be pure: it may be called more than once per render. The host owns the element's semantics (role, live region) and should keep it
57
+ * small: the phone app bar shares one row with the title and the More button.
58
+ */
59
+ renderStatus?: () => ReactNode;
53
60
  /** Told which layout band the browser really shows (after mount, and on change); a host that remembers it returns it as `EditorData.initialLayout`. */
54
61
  onLayoutObserved?: (layout: 'phone' | 'tablet' | 'desktop') => void;
55
62
  }