Skip to content

Commit 88568ba

Browse files
authored
Merge pull request #152 from eviltester/151-continue-refactoring-ui-into-components
151 continue refactoring UI into components
2 parents d48a049 + b307524 commit 88568ba

103 files changed

Lines changed: 4187 additions & 7612 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/web/src/stories/export-preview-story-harness.js

Lines changed: 51 additions & 230 deletions
Large diffs are not rendered by default.

apps/web/src/stories/format-option-panel-basic.stories.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const meta = {
2020
docs: {
2121
description: {
2222
component: `
23-
Shared \`FormatOptionsPanel\` is the component boundary around the existing export/import option-panel classes.
23+
Shared \`FormatOptionsPanel\` renders declarative export/import option definitions through the component contract.
2424
2525
This Basic section maps to the non-code tabs in the current product:
2626
- \`CSV\` and \`DSV\` for delimiter, header, and quoting controls

apps/web/src/stories/import-export-workspace.stories.js

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,25 @@ function renderImportExportWorkspaceStory(args) {
5050
const storyGrid = new StoryMemoryGrid(createSampleGridData());
5151
const exporter = new Exporter(storyGrid);
5252
const importer = new Importer(storyGrid);
53+
if (args.unsupported === true) {
54+
exporter.canExport = () => false;
55+
importer.canImport = () => false;
56+
}
5357
const component = createImportExportWorkspaceComponent({
5458
root,
5559
documentObj: document,
5660
props: {
5761
previewRowLimit: args.previewRowLimit,
62+
importBusy: args.importBusy,
63+
exportBusy: args.exportBusy,
64+
importStatusMessage: args.importStatusMessage,
65+
importStatusLoading: args.importStatusLoading,
66+
exportStatusMessage: args.exportStatusMessage,
67+
exportStatusLoading: args.exportStatusLoading,
68+
errorStatusMessage: args.errorStatusMessage,
69+
},
70+
services: {
71+
requestConfirm: async () => true,
5872
},
5973
});
6074

@@ -83,13 +97,21 @@ const meta = {
8397
docs: {
8498
description: {
8599
component:
86-
'ImportExportWorkspace is the Phase 6 app-side feature boundary for import/export controls, format selection, text preview/editing, and options-panel composition.',
100+
'ImportExportWorkspace is the app-side component-owned import/export feature. It composes the toolbar, format selector, options panel, preview/edit text editor, row-count control, file import, copy, and download behavior without delegating to the old legacy controls.',
87101
},
88102
},
89103
},
90104
args: {
91105
format: 'csv',
92106
previewRowLimit: 10,
107+
importBusy: false,
108+
exportBusy: false,
109+
importStatusMessage: '',
110+
importStatusLoading: false,
111+
exportStatusMessage: '',
112+
exportStatusLoading: false,
113+
errorStatusMessage: '',
114+
unsupported: false,
93115
},
94116
argTypes: {
95117
format: {
@@ -151,3 +173,64 @@ export const JsonPreview = {
151173
await expect(applyButton).toBeEnabled();
152174
},
153175
};
176+
177+
export const ImportBusy = {
178+
args: {
179+
importBusy: true,
180+
importStatusMessage: 'Importing full data into grid...',
181+
importStatusLoading: true,
182+
},
183+
parameters: {
184+
docs: {
185+
description: {
186+
story:
187+
'Shows the workspace while an import is active. The Set Text From Grid and Download affordances become busy/disabled, and the import status remains visible with loading styling.',
188+
},
189+
},
190+
},
191+
};
192+
193+
export const ExportBusy = {
194+
args: {
195+
exportBusy: true,
196+
exportStatusMessage: 'Generating export text...',
197+
exportStatusLoading: true,
198+
},
199+
parameters: {
200+
docs: {
201+
description: {
202+
story:
203+
'Shows the workspace while a download/export is active. The download button is disabled and the export status explains the current operation.',
204+
},
205+
},
206+
},
207+
};
208+
209+
export const UnsupportedFormat = {
210+
args: {
211+
format: 'json',
212+
unsupported: true,
213+
},
214+
parameters: {
215+
docs: {
216+
description: {
217+
story:
218+
'Shows how the toolbar renders when the selected format is not importable or exportable. Import controls and download are hidden while the selector/editor remain mounted.',
219+
},
220+
},
221+
},
222+
};
223+
224+
export const ErrorState = {
225+
args: {
226+
errorStatusMessage: 'Import failed. Check file format/options.',
227+
},
228+
parameters: {
229+
docs: {
230+
description: {
231+
story:
232+
'Shows the persistent error/status surface used when import/export validation or parsing fails. Retry Set Grid From Text after editing the preview text.',
233+
},
234+
},
235+
},
236+
};

apps/web/src/stories/text-preview-editor.stories.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const meta = {
2424
docs: {
2525
description: {
2626
component:
27-
'TextPreviewEditor is the Phase 6 app-side component that owns preview/edit controls, the shared text area, and the options/preview split-panel shell.',
27+
'TextPreviewEditor is the app-side preview/edit component. It renders the Preview/Edit toggle, Auto Preview checkbox, compact preview row-count spinbutton, shared text area, copy button, and options/preview split-panel shell.',
2828
},
2929
},
3030
},

apps/web/src/tests/jest/utils/help-content-coverage.test.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,16 @@ describe('help content coverage', () => {
4444
});
4545

4646
test('options panel help icons resolve to inline text or help entries', () => {
47-
const optionsDir = path.join(repoRoot, 'packages', 'core-ui', 'js', 'gui_components', 'options_panels');
48-
const panelFiles = fs.readdirSync(optionsDir).filter((filename) => filename.endsWith('.js'));
47+
const optionsDir = path.join(
48+
repoRoot,
49+
'packages',
50+
'core-ui',
51+
'js',
52+
'gui_components',
53+
'shared',
54+
'format-options-panel'
55+
);
56+
const panelFiles = ['format-option-panel-definition.js', 'format-option-help.js'];
4957

5058
const missing = [];
5159
panelFiles.forEach((filename) => {

docs/frontend-component-architecture.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,13 @@ Storybook is a review, documentation, and lightweight interaction-example layer.
6868
- When practical, presenter stories should include a destroy-and-remount example so reviewers can confirm lifecycle safety without reading Jest tests first.
6969
- Storybook cleanup is centralized in `.storybook/preview.js`; stories may expose `root.__storybookCleanup`, and the global decorator will run that teardown before the next story and remove common body-level artifacts such as modals, method-picker overlays, tooltip poppers, and inline help containers.
7070
- Prefer returning the story root directly instead of manually appending it to `document.body` unless the component behavior genuinely depends on top-level overlays or body-scoped positioning.
71-
- Current intentional body-aware Storybook exceptions are the app page bootstrap story and the export-preview harness, because both still exercise document-scoped page/bootstrap behavior rather than a purely root-scoped component contract.
71+
- Current intentional body-aware Storybook exception is the app page bootstrap story, because it still exercises document-scoped page/bootstrap behavior rather than a purely root-scoped component contract.
72+
73+
## Format Options
74+
75+
`FormatOptionsPanel` renders format-specific option panels from declarative definitions under `shared/format-options-panel/`. A format option panel definition owns the field schema and returns a panel object with `render`, `read`, `write`, `validate`, `setDirty`, `destroy`, and `onApply` behavior. The shared view mounts those panels directly; there is no separate legacy `options_panels/*` class layer or `addToGui()` adapter path.
76+
77+
Option sanitization remains in the generator/app options services, not in the view. The view reads user input into an explicit `{ outputFormat, options }` payload and the controller sends that payload through the injected sanitization service before emitting applied options.
7278

7379
## Test Layering
7480

docs/frontend-component-migration-plan.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ This is an internal engineering plan for moving the current plain JavaScript UI
99

1010
This plan intentionally does not require React, Vue, Svelte, or Lit. The structure should make a future Lit migration possible by replacing `ThingView` with a Lit element while keeping controllers, services, and adapters stable.
1111

12+
## Status Note
13+
14+
The first component migration established the main page and feature component boundaries, but later review found that several componentized shells still delegate core behavior to older controls, DOM helpers, or compatibility facades. For the stricter goal of eliminating legacy UI approaches before a future React, Web Components, or Lit migration, use `docs/frontend-legacy-ui-elimination-plan.md` as the active follow-on plan. That document supersedes any "complete" status in this migration checklist where old UI orchestration still remains underneath a component boundary.
15+
16+
For the related test-layer cleanup needed after app/generator component sharing increased, use `docs/frontend-ui-matrix-rationalization-plan.md` to track reduction of redundant app-vs-generator UI matrix coverage.
17+
1218
## Goals
1319

1420
- Split the app and generator UIs into feature components that can be mounted independently.
@@ -363,7 +369,7 @@ Current status:
363369
- `ImportExportWorkspace` now lives under `app/import-export-workspace/` with a controller, view, and create-component factory.
364370
- `ImportExportToolbar`, `FormatSelector`, and `TextPreviewEditor` now live under their own app feature folders and are mounted through `ImportExportWorkspace` rather than through direct page bootstrap wiring.
365371
- The app bootstrap now mounts the import/export area through `createImportExportWorkspaceComponent(...)`, and the `tabbedTextArea` preview region now lives inside that feature boundary instead of as a separate sibling shell.
366-
- The extracted workspace reuses the shared `FormatOptionsPanel` while preserving the current import/export behavior through the existing import/export controls path underneath.
372+
- The extracted workspace reuses the shared `FormatOptionsPanel`, and the current import/export behavior now runs through the workspace controller/services path instead of the old import/export controls path underneath.
367373
- File input, drag/drop, file reading, download, and clipboard behavior now flow through explicit Phase 6 app-side adapters/services under `app/import-export-adapters/`, so the legacy import/export control layer no longer talks directly to `FileReader`, `DragDropControl`, or download/copy browser APIs.
368374
- Storybook now documents `ImportExportWorkspace`, `ImportExportToolbar`, `FormatSelector`, and `TextPreviewEditor` directly with small component stories instead of relying only on the older broader app/export harnesses.
369375
- The export-format preview stories now mount through `ImportExportWorkspace` via a dedicated `export-preview-story-harness.js` helper rather than the older split `ImportExportControls + TabbedTextControl` story path or the broader omnibus `storybook-harnesses.js` module.

0 commit comments

Comments
 (0)