feat: project chip + file-wins guard (multi-project stage 2)
When the open flow declares its own top-level project:, show it as a chip in the tab action strip. On mismatch with the host's active workspace, an amber file-wins pill offers a one-click Switch to <project> — the file always wins for the run; switching only aligns the workspace view. New optional FlowEditorPage.activeProject + onSwitchToFileProject. Parse + normalize (mirrors the hub's normalize_project_slug) lives in flow_project.dart, unit-tested. flutter analyze clean, 57 tests green. Signed-off-by: flemming-it <sf@flemming.it>
This commit is contained in:
parent
9196251e00
commit
9e73036d0e
6 changed files with 253 additions and 1 deletions
47
test/flow_project_test.dart
Normal file
47
test/flow_project_test.dart
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:chain_studio_flow_editor/src/flow_project.dart';
|
||||
|
||||
void main() {
|
||||
group('parseFlowProject', () {
|
||||
test('reads a bare top-level project key', () {
|
||||
const yaml = 'name: demo\nproject: client-a\nsteps: []\n';
|
||||
expect(parseFlowProject(yaml), 'client-a');
|
||||
});
|
||||
|
||||
test('strips quotes and normalizes casing/spaces', () {
|
||||
expect(parseFlowProject('project: "Client A"'), 'client-a');
|
||||
// Non-[a-z0-9] that isn't a separator is dropped without a
|
||||
// dash — matches the hub's normalize_project_slug.
|
||||
expect(parseFlowProject("project: 'Recl∆Im'"), 'reclim');
|
||||
});
|
||||
|
||||
test('returns empty when no top-level project is declared', () {
|
||||
const yaml = 'name: demo\ninputs:\n topic: text\nsteps: []\n';
|
||||
expect(parseFlowProject(yaml), '');
|
||||
});
|
||||
|
||||
test('ignores an indented project inside a step with-block', () {
|
||||
const yaml =
|
||||
'name: demo\nsteps:\n - id: s\n use: x@^0\n with:\n project: not-this\n';
|
||||
expect(parseFlowProject(yaml), '');
|
||||
});
|
||||
|
||||
test('a top-level project still wins over a later nested one', () {
|
||||
const yaml =
|
||||
'project: top\nsteps:\n - id: s\n with:\n project: nested\n';
|
||||
expect(parseFlowProject(yaml), 'top');
|
||||
});
|
||||
});
|
||||
|
||||
group('normalizeProjectSlug', () {
|
||||
test('collapses separators and trims trailing dashes', () {
|
||||
expect(normalizeProjectSlug('Projekt Alpha__'), 'projekt-alpha');
|
||||
expect(normalizeProjectSlug('a - b - c'), 'a-b-c');
|
||||
});
|
||||
|
||||
test('empty stays empty', () {
|
||||
expect(normalizeProjectSlug(' '), '');
|
||||
});
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue