Compare commits

..

No commits in common. "496bc1c29e5adbb2211e7119f0a11e4205082073" and "cf878d9e3e8dc3472fe35c61c307454c22db0924" have entirely different histories.

4 changed files with 57 additions and 82 deletions

View file

@ -225,6 +225,9 @@ script_mod! {
} }
} }
} }
}
}
}
mod.widgets.AddRoomModal = Modal { mod.widgets.AddRoomModal = Modal {
width: 400.0 width: 400.0

View file

@ -530,7 +530,7 @@ collaboration-safe acknowledged frontier.
- [ ] CrdtDocEditor widget runtime integration test - [ ] CrdtDocEditor widget runtime integration test
- [x] Separate CrdtDocWorkspace runtime-test view - [x] Separate CrdtDocWorkspace runtime-test view
- [x] Wire application navigation switch to CrdtDocWorkspace - [ ] Wire application navigation switch to CrdtDocWorkspace
## CRDT-native table rendering ## CRDT-native table rendering
@ -687,28 +687,6 @@ toolbar with CRDT engine routing:
Deliberate gaps, matching documented limitations: the mobile Edit/Done Deliberate gaps, matching documented limitations: the mobile Edit/Done
IME toggle is absent from the CRDT toolbar (the native widget has no IME IME toggle is absent from the CRDT toolbar (the native widget has no IME
interaction mode yet), and in-cell table editing remains future work. interaction mode yet), and in-cell table editing remains future work.
The former `crdt_docs` runtime-test tab still instantiates the same
## Application navigation switch to CrdtDocWorkspace full workspace view; consolidating the duplicated docs tabs and pointing
navigation at the CRDT view is the next roadmap item.
With the DSL switch complete, the temporary "Docs CRDT" runtime-test tab
was an exact duplicate of the real "Docs" tab, so navigation has been
consolidated onto a single CRDT destination:
- The desktop dock's `workspace_tabs` keeps one "Docs" tab
(`docs_content` containing `CrdtDocWorkspace`); the `crdt_docs_tab`
definition, its `crdt_docs_content` view, the sidebar's
"Documents CRDT Test" button and its `select_tab` handler are removed.
"Documents" in the sidebar and the dock tab bar both land on the CRDT
editor.
- Mobile's workspace drawer resolves "Documents" to `doc_page` (whose
`m_doc_content` is `CrdtDocWorkspace`). That mapping is now the pure
function `workspace_page_id` in `pages/workspace/project/mod.rs`,
pinned by unit tests that assert the Documents destination, the
label-to-page table, page distinctness, and the CAD fallback for
unknown labels.
The legacy fallback posture is unchanged: `mod.widgets.DocWorkspace`
remains registered, so reverting any navigation node to the classic
editor is again a one-line DSL change. The standalone runtime-test view
roadmap item stays checked historically — it served as the pre-switch
verification surface and was removed only after becoming a duplicate.

View file

@ -18,7 +18,7 @@ pub fn script_mod(vm: &mut ScriptVm) {
// 2. cad — CadWorkspace + CAD script bindings // 2. cad — CadWorkspace + CAD script bindings
// 3. spreadsheet — SpreadsheetGrid widget prototype // 3. spreadsheet — SpreadsheetGrid widget prototype
// 4. invoice — InvoiceWorkspace widget prototype // 4. invoice — InvoiceWorkspace widget prototype
// 5. doc — CrdtDocWorkspace (active) + DocWorkspace (fallback) // 5. doc — DocWorkspace widget prototype
// 6. project_management — ProjectManagementWorkspace widget prototype // 6. project_management — ProjectManagementWorkspace widget prototype
// 7. project — BuildProjectsPage (references all above) // 7. project — BuildProjectsPage (references all above)
cost_estimator::script_mod(vm); cost_estimator::script_mod(vm);

View file

@ -69,7 +69,7 @@ script_mod! {
// ---- Right dock: CAD, Docs, Spreadsheet, Invoice, Schedule, Solar (tabbed) ---- // ---- Right dock: CAD, Docs, Spreadsheet, Invoice, Schedule, Solar (tabbed) ----
workspace_tabs := DockTabs { workspace_tabs := DockTabs {
tabs: [@cad_tab, @docs_tab, @spreadsheet_tab, @invoice_tab, @pm_tab, @solar_tab] tabs: [@cad_tab, @docs_tab, @crdt_docs_tab, @spreadsheet_tab, @invoice_tab, @pm_tab, @solar_tab]
selected: 0 selected: 0
} }
@ -79,6 +79,12 @@ script_mod! {
template: @PermanentTab template: @PermanentTab
} }
crdt_docs_tab := DockTab {
name: "Docs CRDT"
kind: @crdt_docs_content
template: @PermanentTab
}
docs_tab := DockTab { docs_tab := DockTab {
name: "Docs" name: "Docs"
kind: @docs_content kind: @docs_content
@ -284,6 +290,23 @@ script_mod! {
draw_bg +: { color: #x2a333c, color_hover: #x3f4b56, color_down: #x4a5b66, border_radius: 10.0 } draw_bg +: { color: #x2a333c, color_hover: #x3f4b56, color_down: #x4a5b66, border_radius: 10.0 }
draw_text +: { color: #xe6edf3, text_style: theme.font_bold { font_size: 13.0 } } draw_text +: { color: #xe6edf3, text_style: theme.font_bold { font_size: 13.0 } }
} }
desktop_open_crdt_docs_btn := Button {
width: Fill
height: 44
text: "Documents CRDT Test"
draw_bg +: {
color: #x4C1D95
color_hover: #x5B21B6
color_down: #6D28D9
border_radius: 10
}
draw_text +: {
color: #xFFFFFF
text_style: theme.font_bold { font_size: 13 }
}
}
desktop_open_excel_btn := Button { desktop_open_excel_btn := Button {
width: Fill, height: 44 width: Fill, height: 44
text: "Spreadsheet" text: "Spreadsheet"
@ -324,6 +347,13 @@ script_mod! {
docs_workspace := mod.widgets.CrdtDocWorkspace {} docs_workspace := mod.widgets.CrdtDocWorkspace {}
} }
crdt_docs_content := View {
width: Fill
height: Fill
crdt_docs_workspace := mod.widgets.CrdtDocWorkspace {}
}
// Right dock: Spreadsheet workspace content // Right dock: Spreadsheet workspace content
spreadsheet_content := View { spreadsheet_content := View {
width: Fill, height: Fill width: Fill, height: Fill
@ -929,6 +959,15 @@ impl BuildProjectsPage {
dock.select_tab(cx, id!(docs_tab)); dock.select_tab(cx, id!(docs_tab));
self.view.redraw(cx); self.view.redraw(cx);
} }
if self
.view
.button(cx, ids!(desktop_open_crdt_docs_btn))
.clicked(actions)
{
let dock = self.view.dock(cx, ids!(dock));
dock.select_tab(cx, id!(crdt_docs_tab));
self.view.redraw(cx);
}
if self if self
.view .view
.button(cx, ids!(desktop_open_excel_btn)) .button(cx, ids!(desktop_open_excel_btn))
@ -1475,7 +1514,15 @@ impl BuildProjectsPage {
.label(cx, ids!(m_workspace_title)) .label(cx, ids!(m_workspace_title))
.set_text(cx, workspace_type); .set_text(cx, workspace_type);
let page = workspace_page_id(workspace_type); let page = match workspace_type {
"CAD Workspace" => id!(cad_page),
"Spreadsheet" => id!(spreadsheet_page),
"Documents" => id!(doc_page),
"Invoice Builder" => id!(invoice_page),
"Project Management" => id!(project_management_page),
"Solar Calculator" => id!(solar_calculator_page),
_ => id!(cad_page),
};
self.view self.view
.page_flip(cx, ids!(m_workspace_flip)) .page_flip(cx, ids!(m_workspace_flip))
.set_active_page(cx, page); .set_active_page(cx, page);
@ -1632,56 +1679,3 @@ impl BuildProjectsPage {
self.view.redraw(cx); self.view.redraw(cx);
} }
} }
/// Maps a mobile workspace-drawer label to its overlay page. "Documents"
/// resolves to `doc_page`, whose `m_doc_content` is the CRDT-native
/// `CrdtDocWorkspace` — the mobile half of the navigation switch, kept as
/// a pure function so the destination stays pinned by tests.
fn workspace_page_id(workspace_type: &str) -> LiveId {
match workspace_type {
"CAD Workspace" => id!(cad_page),
"Spreadsheet" => id!(spreadsheet_page),
"Documents" => id!(doc_page),
"Invoice Builder" => id!(invoice_page),
"Project Management" => id!(project_management_page),
"Solar Calculator" => id!(solar_calculator_page),
_ => id!(cad_page),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn documents_navigation_targets_the_crdt_doc_page() {
assert_eq!(workspace_page_id("Documents"), id!(doc_page));
}
#[test]
fn every_workspace_label_maps_to_a_distinct_page() {
let labels = [
("CAD Workspace", id!(cad_page)),
("Spreadsheet", id!(spreadsheet_page)),
("Documents", id!(doc_page)),
("Invoice Builder", id!(invoice_page)),
("Project Management", id!(project_management_page)),
("Solar Calculator", id!(solar_calculator_page)),
];
for &(label, expected) in &labels {
assert_eq!(workspace_page_id(label), expected, "label {label}");
}
let pages: Vec<LiveId> = labels.iter().map(|&(label, _)| workspace_page_id(label)).collect();
for (i, page) in pages.iter().enumerate() {
for other in pages.iter().skip(i + 1) {
assert_ne!(page, other, "workspace pages must not alias");
}
}
}
#[test]
fn unknown_workspace_falls_back_to_cad_page() {
assert_eq!(workspace_page_id(""), id!(cad_page));
assert_eq!(workspace_page_id("Does Not Exist"), id!(cad_page));
}
}