Skip to content

Svelte client fixes - #77

Open
yrodzikau wants to merge 12 commits into
alexanderoster:developfrom
yrodzikau:svelte_client_fixes
Open

yrodzikau wants to merge 12 commits into
alexanderoster:developfrom
yrodzikau:svelte_client_fixes

Conversation

@yrodzikau

Copy link
Copy Markdown

Svelte client: LayerView feature parity, System Settings values, dialog overflow and UI event fixes

This PR brings the Svelte client closer to the Vue 2 client and fixes several
server-side issues in the V2 frontend (/api/frontend) that the Svelte client
depends on. It is rebased on the current develop (after "Added Layerview
transforms"); the LayerView changes were merged with the new coordinate
transform / axes indicator code.

Server (Implementation/UI)

  • Page show events in the V2 frontend. CUIPage::frontendWritePageStatusToJSON()
    now writes showevent, so AMCPage.setActive() triggers it again. Without it
    the ScanlabOCM System Settings page showed the config.xml defaults instead of
    the active machine configuration.
  • Values set by UI event handlers are reported. CUIFrontendState::writeModuleAttributesToJSON()
    writes the session client variable for an attribute when one exists
    (set via UIEnvironment::SetUIProperty), instead of the definition value.
    Attributes bound with sync: are still evaluated from the state machine, as
    in the legacy syncClientVariables(). Adds
    CUIFrontendDefinitionAttribute::isSynchronized(),
    writeClientValueToFrontendJSON() and CUIFrontendDefinitionModuleStore::getPath().
  • LayerView base image resolved to a UUID in client variables. Client
    variables take precedence over module attributes in the new frontend, so the
    resource name written by populateClientVariables() overrode the resolved
    UUID and the Svelte client could not load the platform image. The name is now
    resolved through one shared helper in all three places; an empty name yields
    the null UUID (empty string for the dark image = fall back to the light one).
  • Unit tests: new UIFrontend test group (amc_unittests_uifrontend.hpp).

Client core (shared JS)

  • triggerUIEvent(): an errorcode in the /event response or a failed
    request is shown in the snackbar via the new showEventError(); the success
    path no longer runs for a failed event.
  • New showSnackBar() sets every snackbar field and bumps a Sequence
    counter, so repeated identical messages restart the auto-hide timer.
  • triggerWidgetRequest(): optional failureCallback(err) for callers that
    need to roll back optimistic UI state.
  • Removed the mouse-move debug logging from WebGLLocalizedPointsElement.

Svelte client

  • LayerView at the Vue 2 feature set: scatter plot points and the laser
    channel (laseron, power), color modes, LaserOff point toggle, toolpath
    visibility toggle, hover info for the point / toolpath segment under the
    cursor (one raycast per animation frame), platform label and loading
    indicator. Layer slider: correct range (layercount - 1), changelayer sent
    only on release, -/+ step buttons, sliderfixed support, optimistic change
    with rollback on failure. The canvas and resize observer are re-attached when
    the module is hidden and shown again. Stale toolpath / scatter plot responses
    are ignored; the null UUID is treated as "no build" / "no image".
  • BuildList / ExecutionList use the shared triggerButtonEvent() helper:
    selectionvalueuuid receives the item, buttonvalueuuid the button, so the
    server-side handler can tell which button was pressed.
  • ConfigurationList: Load / Set Active no longer send a placeholder id as
    the button UUID (rejected by the server with "invalid uuid string"). The
    Delete fallback was removed, no plugin handles deleteconfiguration.
  • Tabs: invisible tabs are hidden.
  • Dialogs: DialogContent / DialogFooter / DialogTitle (shadcn-svelte)
    get an overflow-safe layout, so long 3MF file names and multiple buttons stay
    inside the dialog (Build Library and Build History details, config.xml
    dialogs). Note: re-running shadcn-svelte add dialog would overwrite these
    files.
  • mdi-timer-outline is mapped to the Clock icon.
  • Snackbar.svelte reacts to the new Sequence counter.

Vue 2 client

  • App.vue: snackBarVisible gets a setter, otherwise Vuetify cannot reset
    Visible and the next error is never shown.

Testing

  • amc_unittest passes with the new UIFrontend group.
  • svelte-check reports no errors in the touched modules.
  • Clean Windows build (build_clean_win64.bat) and a rebuilt Svelte client
    package; the ScanlabOCM configuration was run in simulation mode and a build
    job started and executed layers without errors.

Notes

  • Artifacts/clientdist/clientpackage_svelte.zip is not part of these commits
    and must be rebuilt with Artifacts/build_client_svelte_clean.bat.
  • <buttongroup> rows in config.xml dialogs still do not wrap.

…Footer and DialogTitle to keep long 3MF names and buttons inside dialogs

On the Build Library page, selecting a build opened the details dialog
with the 3MF file name and the "Close"/"Select" buttons running past
the dialog border. DialogContent is a single-column CSS grid whose
implicit auto column grows to the min-content width of its widest
child. A file name without spaces is one unbreakable word, so the
column grew beyond the 500px dialog box and the right-aligned footer
moved with it. The fix is applied to the shared shadcn-svelte dialog
components, so every dialog in the Svelte client gets it.

feat(dialog-content): cap the content column and wrap long words
- Add grid-cols-[minmax(0,1fr)]: the column can no longer grow wider
  than the dialog, so header, body and footer stay inside the border.
- Add wrap-anywhere (overflow-wrap: anywhere). The property is
  inherited, so long names, paths and module content wrap in every
  dialog. Unlike wrap-break-word it also lowers the min-content width,
  which the grid column needs in order to shrink. Button captions keep
  whitespace-nowrap and stay on one line.

feat(dialog-footer): wrap footer buttons
- Add sm:flex-wrap. Buttons are shrink-0 and whitespace-nowrap, so
  several or long buttons (e.g. multiple <button> entries in a
  <buildlist>) now move to the next row instead of overflowing.

feat(dialog-title): reserve space for the close button
- Add pe-6 so a title that wraps does not run under the absolutely
  positioned close (X) button.

Affected dialogs:
- Build Library details dialog (ModuleBuildList): fixes the reported
  overflow.
- Build History details dialog (ModuleExecutionList): same markup,
  same fix.
- config.xml dialogs rendered in routes/+page.svelte (e.g.
  pausedialog): long titles now wrap instead of being clipped.

Notes:
- components/ui/dialog/* are shadcn-svelte generated files. Running
  "shadcn-svelte add dialog" again will overwrite these changes.
- <buttongroup> rows (ModuleButtonGroup) still do not wrap. In
  config.xml dialogs, long captions produce a horizontal scrollbar.
  This commit does not change that.
- The prebuilt package Artifacts/clientdist/clientpackage_svelte.zip
  is not part of this commit. Rebuild it with
  Artifacts/build_client_svelte_clean.bat and commit it separately.

Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
…oad/Set Active and tab visibility

The Svelte client showed the config.xml defaults on the ScanlabOCM
System Settings page instead of the active machine configuration. The
page fills its fields in the "onshowsystemsettings" show event with
UIEnvironment::SetUIProperty, but the V2 frontend (/api/frontend) did
not include the show event and ignored values set by SetUIProperty.

feat(ui): send the page show event in the V2 frontend
- CUIPage::frontendWritePageStatusToJSON() writes "showevent", so
  AMCPage.setActive() triggers it again.

feat(ui): report values and visibility set by UI event handlers
- CUIFrontendState::writeModuleAttributesToJSON() writes the session
  client variable with the attribute's name, if one exists, instead of
  the definition value. Attributes bound with sync: are still
  evaluated from the state machine, as in the legacy
  syncClientVariables().
- Add CUIFrontendDefinitionAttribute::isSynchronized(),
  writeClientValueToFrontendJSON() and
  CUIFrontendDefinitionModuleStore::getPath().

feat(svelte-client): fix the configuration list fallback buttons
- Load and Set Active no longer send their placeholder id as the
  button UUID, which the server rejected with "invalid uuid string".
- Remove the Delete fallback: no plugin handles "deleteconfiguration".

feat(svelte-client): hide invisible tabs in ModuleTabs

feat(unittest): add the UIFrontend test group

Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
Client variables take precedence over module attributes in the new
frontend, so the resource name written by populateClientVariables()
overrode the resolved UUID and the Svelte client could not load the
platform image. Resolve the name in all three places through a shared
helper; an empty name yields the null UUID (empty string for the dark
image, meaning "fall back to the light one").

Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
… in the snackbar

- triggerUIEvent(): an errorcode in the /event response or a request
  failure is shown via the new showEventError(); a failed event no
  longer runs the success path
- add showSnackBar() that sets every SnackBar field and bumps a new
  Sequence counter, so repeated identical messages restart auto-hide
- Snackbar.svelte depends on Sequence
- App.vue: snackBarVisible gets a setter, otherwise Vuetify cannot
  reset Visible and the next error is never shown
- triggerWidgetRequest(): optional failureCallback(err) for callers
  that need to roll back optimistic UI state

Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
…ExecutionList

ExecutionList wrote the execution UUID into buttonvalueuuid and BuildList
wrote the build UUID into both form fields, so the server-side handler
could not tell which button was pressed. Reuse the core helper that the
Vue 2 client already uses: selectionvalueuuid receives the item,
buttonvalueuuid the button.

Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
…ture set

- load scatter plot points and the laser channel (laseron, power),
  color modes, LaserOff point toggle, toolpath visibility toggle
- hover info for the point or toolpath segment under the cursor,
  throttled to one raycast per animation frame
- layer slider: correct range (layercount - 1), send changelayer only
  on release, -/+ step buttons, sliderfixed support, follow the server
  only on changed values, optimistic change with rollback on failure
- platform label and loading indicator
- re-attach the canvas and resize observer when the module is hidden
  and shown again
- ignore stale toolpath/scatter plot responses, treat the null UUID as
  "no build"/"no image"
- remove the mouse-move debug logging from WebGLLocalizedPointsElement

Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
…n page host in +page.svelte

Pages whose layout is taller than the viewport (for example the System
Settings grid with 1080pt of fixed-height rows) were clipped in the Svelte
client: the page host had no scroll container, so the lower form fields and
the Save/Cancel row were unreachable. The Vue 2 client scrolls the whole
page inside its `.amc-content-card`; this change brings the Svelte shell
in line with that behaviour.

feat(svelte-client): make <main> the single page scroll container

  - Replace `relative` with `overflow-y-auto` on the page host `<main>`.
  - Header, sidebar and footer keep their fixed placement; only the page
    content scrolls.
  - Grids with fixed pt/px rows (AMCModule_Grid.js emits `height:100%`)
    now overflow into the scrollable area instead of being clipped by the
    `h-screen overflow-hidden` app root.
  - Grids with `free` rows and modules using `h-full` are unaffected and
    still fill exactly the viewport.

feat(svelte-client): render the active page wrapper in normal flow as a flex column

  - Replace `absolute inset-2` with `h-full p-2 flex flex-col`.
  - `h-full` keeps the same box as the previous inset positioning, so
    full-height modules (Content, Tabs, ParameterList, LayerView) behave
    as before.
  - `flex flex-col` lets modules placed directly on a page that rely on
    `flex-1 min-h-0` (Logs, ParameterList, ConfigurationList) fill the
    viewport and scroll internally. Previously the System Logs page
    overflowed the block wrapper and was clipped.

Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
…n modal dialogs that the user cannot close, for the "Pausing Build…" / "Canceling Build…" wait screens

State machines cannot open dialogs and UI event handlers cannot set machine
parameters, so a dialog could only be opened by a click and closed by the
user. The pause/resume/cancel build controls need dialogs that main opens
while it finishes the current layer, that cannot be dismissed, and that close
by themselves once the machine is ready. This adds that generically; the
ScanlabOCM machine uses it for "Pausing Build…" and "Canceling Build…".

feat(ui-core): dialog attributes sync:active and closable

- <dialog> accepts `active` / `sync:active` and `closable` (default "1"),
  stored as CUIExpression in CUIDialog, validated at startup, passed through
  addDialog_Unsafe (signature extended).
- /api/frontend emits "closable" for every dialog and "active" only for
  dialogs with an active expression, so event-driven dialogs stay untouched.
  Legacy /api/ui/state emits "closable" too. New keys
  AMC_API_KEY_UI_DIALOGACTIVE / AMC_API_KEY_UI_DIALOGCLOSABLE.
- The server is authoritative: a dialog is open while the bound parameter
  is true and re-asserted on every frontend poll.

feat(client-core): follow server-driven dialog state

- AMCApplicationDialog initialises `closable` and `serverDriven` in the
  constructor (Vue 2 reactivity).
- retrieveFrontendState() indexes dialog modules into frontendLookup and
  calls new _syncServerDrivenDialogs(), which opens a dialog via showDialog()
  when "active" turns true and clears dialogIsActive when it turns false.
  Dialogs without "active" keep the client-action driven behaviour.

feat(svelte-client): non-closable dialogs

- Dialog.Content gets showCloseButton, escapeKeydownBehavior and
  interactOutsideBehavior from dialog.closable; setDialogOpen() ignores
  close requests for closable="0"; dialogIsClosable() reads through the
  poll tick so the property mutation re-renders.

feat(vue2-client): non-closable dialogs

- v-dialog gets :persistent and :no-click-animation for closable === false.

Backward compatible: dialogs without the new attributes behave as before.

Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
…e platform

feat(create_package_xml): write the resolved client variant into amc_server.xml

The package builder already resolved which web client to ship (from the
`--client` flag, then the `client` attribute on `<machinedefinition>` in
config.xml, then the default `vue2`) and wrote it to the package XML as
`<coreclients default="...">`. The generated amc_server.xml, however, was
written without a `client` attribute on the `<amc>` root element.

The server reads that attribute at startup to pick the client package,
so every clean build silently reset the served UI to the Vue 2 client
until `client="svelte"` was re-added to amc_server.xml by hand.

The `<amc>` element now carries `client="<variant>"` with the same
resolved value that goes into the package XML, e.g.:

    <amc xmlns="http://schemas.autodesk.com/amc/2020/06" client="svelte">

Both files are generated in one run, so the package SHA-256 recorded in
amc_server.xml always matches the package XML written alongside it.

feat(build_clean_win64): pass -A x64 to the Visual Studio generator

The Windows clean build configures CMake with an explicit x64 platform
instead of relying on the generator default. This makes the architecture
deterministic across machines with different default toolchains.

Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
…erView

CenterOnRectangle() works in plate coordinates: the plate image is drawn
from (0, 0) to (sizex, sizey) and the toolpath is shifted by the origin.
The framing introduced with "Layer Viewer updates" subtracted the origin
from the frame, which put the plate corner into the view center for
origin = (sizex/2, sizey/2) on the ScanlabOCM machine.

centerOnPlatform() frames 0 .. size again, keeping the paddingx/paddingy
attributes and the auto-framing behaviour. The Vue 2 client is unchanged.

Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
The package committed by upstream ("Updated Svelte Client") was built from
the upstream sources and does not contain the local Svelte client changes,
but build_clean_win64.bat ships it as <hash>_core_svelte.client. Rebuilt
with Artifacts/build_client_svelte_clean.bat.

Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant