;;; operations-console.el --- one complete ETAF application example -*- lexical-binding: t; -*- ;;; Commentary: ;; This single-file sample shows the public development path: `:view' ;; props/slots/styles, `:setup' state, a normal composable, `expr' for ;; dynamic Views, Context/Theme, callbacks/Actions/Behaviors, Data, Resource ;; cleanup, and public open/close commands. ;;; Code: (require 'cl-lib) (require 'etaf) (require 'etaf-ui) (defconst etaf-operations-console-buffer "*ETAF Operations Console*" "Default buffer used by `etaf-operations-console-open'.") (defvar etaf-operations-console-cleanup-count 0 "Observable count of composable cleanup calls for review and tests.") ;;; Pure `:view' Component: props, named/default slots, and `:styles'. (etaf-define-component etaf-operations-console-card (&key title) "Render a styled card with explicit named and default slot outlets." :styles (styles ("&" :width stretch :border ((1) solid "#687386") :padding (1 2)) (".operations-console-card-title" :face bold)) :view (column :class "operations-console-card" (text :class "operations-console-card-title" (expr :value title)) (slot :name 'header) (slot (label :text "This card has no default content.")))) ;;; A normal Elisp composable called synchronously from Component `:setup'. (defun etaf-operations-console-use-counter (name initial-value) "Create isolated counter state and effects for NAME and INITIAL-VALUE." (let* ((count (etaf-ref initial-value :name name)) (double (etaf-computed (lambda () (* 2 (etaf-value count))) :name (intern (format "%s-double" name)))) (updates (etaf-ref 0 :name (intern (format "%s-updates" name)))) (audit-text (format "effect saw %d" (* 2 (or initial-value 0)))) (audit (etaf-ref audit-text :name (intern (format "%s-audit" name))))) (etaf-watch count (lambda (_new _old) (cl-incf (etaf-value updates))) :immediate nil :name (intern (format "%s-watch" name))) (etaf-watch-effect (lambda () (let ((value (etaf-value double))) (let ((next (format "effect saw %d" value))) (unless (equal next audit-text) (setq audit-text next) (setf (etaf-value audit) next))))) :name (intern (format "%s-effect" name))) (etaf-on-scope-dispose (lambda () (cl-incf etaf-operations-console-cleanup-count))) (list :name name :count count :double double :updates updates :audit audit))) (defun etaf-operations-console-counter-ref (name operation) "Return a stable interactive ref for counter NAME and OPERATION." (intern (format "operations-console-%s-%s" name operation))) ;;; Stateful Component: its render closure retains the composable instance. (etaf-define-component etaf-operations-console-counter (&key name initial-value) "Render one isolated counter Component instance." :setup (let* ((instance-name name) (initial initial-value) (state (etaf-operations-console-use-counter (intern (format "operations-console-%s" instance-name)) initial)) (count (plist-get state :count)) (double (plist-get state :double)) (updates (plist-get state :updates)) (audit (plist-get state :audit)) (increment (lambda () (cl-incf (etaf-value count)))) (reset (lambda () (setf (etaf-value count) initial)))) (lambda () (etaf-view (operations-console-card :title (format "Counter %s" instance-name) (slot :name 'header (label :text "State belongs to this Component instance.")) (label :text (format "Value: %d · Double: %d" (etaf-value count) (etaf-value double))) (label :text (format "Watch updates: %d · Audit: %s" (etaf-value updates) (etaf-value audit))) (flex :gap '(0 (8)) (button :label "Increment" :ref (etaf-operations-console-counter-ref instance-name "increment") :on-press increment) (button :label "Reset" :ref (etaf-operations-console-counter-ref instance-name "reset") :on-press reset)) (expr :value (when (> (etaf-value count) 0) (etaf-view (text "Dynamic child is visible after Increment."))))))))) ;;; Context and Theme: the child consumes a value provided by the shell. ;;; Named Action: state is passed explicitly, so no hidden global app state. (etaf-action-define etaf-operations-console-named-note (runtime target) "Publish a message through a named Action." (ignore runtime) (setf (etaf-value target) "Named Action: pressed")) ;;; Behavior reuse: ordinary Elisp returns semantic interaction bundles. (defun etaf-operations-console-use-toggle-behaviors (toggle message) "Return reusable focus and toggle Behaviors for TOGGLE and MESSAGE." (list (etaf-focusable) (etaf-toggleable :value toggle :on-change (lambda (value) (setf (etaf-value toggle) value (etaf-value message) (if value "Behavior toggle: on" "Behavior toggle: off")))))) (etaf-define-component etaf-operations-console-action-panel () "Show a local callback, a named Action, and reusable Behaviors." :setup (let* ((message (etaf-ref "Callback action pending" :name 'operations-console-message)) (toggle (etaf-ref nil :name 'operations-console-toggle)) ;; Behavior installers use function identity. Construct this ;; reusable bundle once in setup so state renders retain it. (behaviors (etaf-operations-console-use-toggle-behaviors toggle message)) (local-callback (lambda () (setf (etaf-value message) "Local callback: pressed"))) (named-callback (lambda () (etaf-dispatch 'etaf-operations-console-named-note message)))) (lambda () (etaf-view (operations-console-card :title "Events, Actions, and Behaviors" (column :width 'stretch (label :text (etaf-value message))) (flex :gap '(0 (8)) (button :label "Local callback" :ref 'operations-console-local-callback :on-press local-callback) (button :label "Named Action" :ref 'operations-console-named-action :on-press named-callback) (button :label (if (etaf-value toggle) "Behavior: on" "Behavior: off") :ref 'operations-console-behavior-toggle :use behaviors))))))) ;;; Application model: detached resources are ready before the first render. (defun etaf-operations-console-create-model () "Create and load the external model before mounting the application." (let* ((source (etaf-data-memory-source '((:id 1 :name "Ada" :status "open") (:id 2 :name "Grace" :status "review") (:id 3 :name "Lin" :status "done")) :id-key :id :name 'operations-console-records)) (controller (etaf-data-controller source :page-size 3 :name 'operations-console-controller)) (fail-next (etaf-ref nil :name 'operations-console-fail-next)) (cleanups (etaf-ref 0 :name 'operations-console-resource-cleanups)) (health (etaf-ref "All systems nominal" :name 'operations-console-health-status)) (activity (etaf-ref "Theme provider promoted" :name 'operations-console-activity)) (trail (etaf-ref "Surface mounted · Data controller loaded" :name 'operations-console-event-trail)) (throughput (etaf-ref 2400 :name 'operations-console-throughput)) (generation 0)) (etaf-data-load controller) (let ((resource (etaf-resource (lambda () (cl-incf generation) (if (etaf-value fail-next) (progn (setf (etaf-value fail-next) nil) (error "Example load failed")) (etaf-resource-result (format "Loaded value %d" generation) :cleanup (lambda () (cl-incf (etaf-value cleanups)))))) :immediate t :name 'operations-console-resource))) (list :controller controller :resource resource :fail-next fail-next :cleanups cleanups :health health :activity activity :trail trail :throughput throughput :health-check (lambda () (setf (etaf-value health) "Health check complete" (etaf-value activity) "Health check completed" (etaf-value trail) "Health check · all owned surfaces responded")) :show-trail (lambda () (setf (etaf-value activity) "Event trail focused" (etaf-value trail) "Event trail opened for inspection")))))) (defun etaf-operations-console-dispose-model (model) "Stop MODEL's Data Controller and dispose its Resource." (etaf-data-stop (plist-get model :controller)) (etaf-resource-dispose (plist-get model :resource))) (defun etaf-operations-console-data-status (selection items) "Return visible status derived from SELECTION and ITEMS." (let ((selected (cl-find (car selection) items :key (lambda (row) (plist-get row :id)) :test #'equal))) (if selected (format "Selected %s" (plist-get selected :name)) "Rows loaded from the public controller."))) ;;; Data Controller + official `data-grid'. (etaf-define-component etaf-operations-console-data-panel (&key model) "Render MODEL's loaded Data Controller and interactive DataGrid." :setup (let* ((controller (plist-get model :controller)) (view-state (etaf-computed (lambda () (let ((selection (etaf-value (etaf-data-selection controller))) (items (etaf-value (etaf-data-items controller)))) (list :selected (car selection) :status (etaf-operations-console-data-status selection items)))) :name 'operations-console-data-view-state)) (row-key (lambda (row) (plist-get row :id))) (row-ref (lambda (row) (intern (format "operations-console-row-%s" (plist-get row :id))))) (row-press (lambda (row) (etaf-data-select controller (plist-get row :id)))) (clear-selection (lambda () (etaf-data-clear-selection controller)))) (lambda () (let ((state (etaf-value view-state))) (etaf-view (operations-console-card :title "Data Controller and DataGrid" (label :text (plist-get state :status)) (data-grid :controller controller :columns '((:key :id :label "ID" :width 5) (:key :name :label "NAME" :width 20) (:key :status :label "STATUS" :width 10)) :row-key row-key :row-ref row-ref :selected-key (plist-get state :selected) :on-row-press row-press) (button :label "Clear selection" :ref 'operations-console-clear-selection :on-press clear-selection))))))) ;;; Resource + explicit error boundary: load, reload, cleanup, and recovery. (etaf-define-component etaf-operations-console-resource-panel (&key model) "Render MODEL's Resource with reload, failure, and cleanup feedback." :setup (let* ((instance-model model) (fail-next (plist-get instance-model :fail-next)) (cleanups (plist-get instance-model :cleanups)) (boundary (etaf-ref "No boundary run yet." :name 'operations-console-boundary)) (resource (plist-get instance-model :resource)) (fail-change (lambda (value) (setf (etaf-value fail-next) value))) (reload (lambda () (etaf-resource-load resource))) (run-boundary (lambda () (setf (etaf-value boundary) (etaf-error-boundary-run (lambda () (error "Handled sample")) (lambda (condition) (format "Handled: %s" (error-message-string condition)))))))) (lambda () (etaf-view (operations-console-card :title "Resource and Error Boundary" (label :text (format "Status: %s" (etaf-resource-status resource))) (label :text (or (etaf-resource-value resource) (when-let ((condition (etaf-resource-error resource))) (format "Error: %s" (error-message-string condition))))) (label :text (format "Cleanup calls: %d" (etaf-value cleanups))) (checkbox :label "Fail next load" :ref 'operations-console-fail-next :checked (etaf-value fail-next) :on-change fail-change) (flex :gap '(0 (8)) (button :label "Reload resource" :ref 'operations-console-resource-reload :on-press reload) (button :label "Run handled boundary" :ref 'operations-console-error-boundary :on-press run-boundary)) (label :text (etaf-value boundary))))))) ;;; Page composition and navigation views. (defun etaf-operations-console-static-child (form tag) "Return the first static child named TAG from FORM. The static `.etaf' form is the composition authority; the companion only fills these safe named slots with reactive Views." (cl-find-if (lambda (entry) (and (consp entry) (eq (car entry) tag))) (cdr form))) (defun etaf-operations-console-static-value (form key default) "Return keyword KEY from static FORM, or DEFAULT. Keyword values are inert data; executable behavior never comes from `.etaf'." (let ((tail (member key (cdr form)))) (if tail (cadr tail) default))) (defun etaf-operations-console-static-child-value (form tag key default) "Return KEY from child TAG in static FORM, or DEFAULT. The helper keeps `.etaf' consumption at one validated data boundary instead of scattering plist reads through the application renderer." (etaf-operations-console-static-value (or (etaf-operations-console-static-child form tag) nil) key default)) (defun etaf-operations-console-static-child-by-value (form tag key value) "Return the child TAG whose KEY equals VALUE in static FORM." (cl-find-if (lambda (entry) (and (consp entry) (eq (car entry) tag) (equal (plist-get (cdr entry) key) value))) (cdr form))) (defun etaf-operations-console-hero-view (model hero-form) "Return the visual hero for MODEL using static HERO-FORM copy." (let ((eyebrow (etaf-operations-console-static-value hero-form :eyebrow "TUESDAY / 09:42 / LIVE REVIEW")) (title (etaf-operations-console-static-value hero-form :title "Make complex state feel calm."))) (etaf-view (column :class "operations-console-hero" :width 'stretch :padding '(2 3) :border "#17374A" :bgcolor "#17374A" :color "#F6F1E8" (column :width 'stretch (label :text eyebrow :face 'bold) (label :text title :face 'bold) (label :text "A single surface for components, context, behavior, data, and recovery — designed to make every ETAF update visible and explainable.") (flex :width 'stretch :gap '(1 (8)) (button :label "Run health check" :ref 'operations-console-health-check :on-press (plist-get model :health-check)) (button :label "View event trail" :ref 'operations-console-show-trail :on-press (plist-get model :show-trail)))))))) (etaf-define-component etaf-operations-console-metric (&key label value delta color) "Render one KPI metric with a retained Component owner." :setup (lambda () (etaf-view (column :class "operations-console-metric" :width 'stretch :padding '(1 2) :border (etaf-current-prop :color) :bgcolor (etaf-theme-value :surface "#FFFDF8") :color (etaf-theme-value :color "#142235") (label :text (etaf-current-prop :label)) (label :text (etaf-current-prop :value) :face 'bold) (label :text (etaf-current-prop :delta) :color (etaf-theme-value :success "#3E9B72")))))) (defun etaf-operations-console-metric-strip-view (model) "Return the four-card KPI strip for MODEL." (etaf-view (grid :width 'stretch :grid-template-columns '(1fr 1fr 1fr 1fr) :gap '(1 (8)) (operations-console-metric :label "Throughput" :value (format "%dk" (/ (etaf-value (plist-get model :throughput)) 1000)) :delta "↑ 18% this week" :color (etaf-theme-value :teal "#2E8B83")) (operations-console-metric :label "Active flows" :value "18" :delta "+3 since 08:00" :color (etaf-theme-value :coral "#E26D5A")) (operations-console-metric :label "Response" :value "42ms" :delta "p95 within target" :color (etaf-theme-value :amber "#D99A3D")) (operations-console-metric :label "Reliability" :value "99.8%" :delta "steady" :color (etaf-theme-value :success "#3E9B72"))))) (defun etaf-operations-console-activity-view (model) "Return the reactive Activity stream card for MODEL." (etaf-view (column :class "operations-console-card" :width 'stretch :padding '(1 2) :border (etaf-theme-value :line "#C8C1B6") :bgcolor (etaf-theme-value :surface "#FFFDF8") (flex :width 'stretch :align-items 'center (column :width 'stretch :flex-grow 1 :flex-shrink 1 :min-width 0 (label :text "Activity stream" :face 'bold) (label :text "Reactive events, rendered as a readable story.")) (label :text "4 EVENTS" :color (etaf-theme-value :teal "#2E8B83"))) (label :text (format "↗ %s" (etaf-value (plist-get model :activity)))) (label :text "◆ Counter alpha crossed 2k · one Component-owned update") (label :text "✓ Resource boundary recovered · shell stayed mounted")))) (defun etaf-operations-console-capability-view () "Return the static capability map card." (etaf-view (column :class "operations-console-card" :width 'stretch :padding '(1 2) :border (etaf-theme-value :line "#C8C1B6") :bgcolor (etaf-theme-value :surface "#FFFDF8") (flex :width 'stretch :align-items 'center (column :width 'stretch :flex-grow 1 :flex-shrink 1 :min-width 0 (label :text "Capability map" :face 'bold) (label :text "What this surface is proving.")) (label :text "ETAF" :color (etaf-theme-value :teal "#2E8B83"))) (label :text "✓ Component ownership · props, slots, setup, retained identity") (label :text "✓ Context + Theme · provider defaults and dark mode") (label :text "✓ Behavior + Actions · keyboard-ready stable refs") (label :text "✓ Data + Resource · selection, failure, boundary, cleanup")))) (defun etaf-operations-console-timeline-view (model) "Return the event trail card for MODEL." (etaf-view (column :class "operations-console-card" :width 'stretch :padding '(1 2) :border (etaf-theme-value :line "#C8C1B6") :bgcolor (etaf-theme-value :surface "#FFFDF8") (flex :width 'stretch :align-items 'center (column :width 'stretch :flex-grow 1 :flex-shrink 1 :min-width 0 (label :text "Event trail" :face 'bold) (label :text "Every meaningful action leaves a compact, inspectable trace.")) (button :label "Clear trail" :ref 'operations-console-clear-trail :on-press (lambda () (setf (etaf-value (plist-get model :trail)) "Trail cleared · new actions append here")))) (label :text (format "● %s" (etaf-value (plist-get model :trail))))))) ;; These wrappers make the HTML sections real ETAF Components. The plain ;; `*-view' helpers stay small and readable, while the Component boundary ;; gives every dynamic `expr' a reviewed semantic owner. (etaf-define-component etaf-operations-console-hero (&key model hero-form) "Render the operations hero as a retained Component." :setup (lambda () (etaf-operations-console-hero-view (etaf-current-prop :model) (etaf-current-prop :hero-form)))) (etaf-define-component etaf-operations-console-metric-strip (&key model) "Render the operations KPI strip as a retained Component." :setup (lambda () (etaf-operations-console-metric-strip-view (etaf-current-prop :model)))) (etaf-define-component etaf-operations-console-activity (&key model) "Render the reactive activity card as a retained Component." :setup (lambda () (etaf-operations-console-activity-view (etaf-current-prop :model)))) (etaf-define-component etaf-operations-console-capabilities () "Render the static capability map as a reusable Component." :setup (lambda () (etaf-operations-console-capability-view))) (etaf-define-component etaf-operations-console-timeline (&key model) "Render the event trail as a retained Component." :setup (lambda () (etaf-operations-console-timeline-view (etaf-current-prop :model)))) (defun etaf-operations-console-overview-page (model main-form) "Return the Overview page View for MODEL using MAIN-FORM sections." (let* ((overview-form (etaf-operations-console-static-child main-form 'overview)) (hero-form (etaf-operations-console-static-child overview-form 'hero))) (etaf-view (column :class "operations-console-page" :width 'stretch (operations-console-hero :model model :hero-form hero-form) (operations-console-metric-strip :model model) (grid :width 'stretch :grid-template-columns '(5fr 3fr) :gap '(1 (12)) (operations-console-activity :model model) (operations-console-capabilities)) (operations-console-timeline :model model) (grid :width 'stretch :grid-template-columns '(1fr 1fr) :gap '(1 (12)) (operations-console-counter :name "alpha" :initial-value 0) (operations-console-counter :name "beta" :initial-value 10) (operations-console-action-panel)))))) (defun etaf-operations-console-data-page (model) "Return the Data page View for MODEL." (etaf-view (column :class "operations-console-page" :width 'stretch (operations-console-data-panel :model model)))) (defun etaf-operations-console-resource-page (model) "Return the Resource page View for MODEL." (etaf-view (column :class "operations-console-page" :width 'stretch (operations-console-resource-panel :model model)))) (etaf-define-component etaf-operations-console-overview-surface (&key model main-form) "Own the material Overview page surface." :setup (lambda () (etaf-operations-console-overview-page (etaf-current-prop :model) (etaf-current-prop :main-form)))) (etaf-define-component etaf-operations-console-data-surface (&key model) "Own the material Data page surface." :setup (lambda () (etaf-operations-console-data-page (etaf-current-prop :model)))) (etaf-define-component etaf-operations-console-resource-surface (&key model) "Own the material Resource page surface." :setup (lambda () (etaf-operations-console-resource-page (etaf-current-prop :model)))) (defun etaf-operations-console-page-view (page model main-form) "Return the selected page Component call for PAGE, MODEL, and MAIN-FORM. The function is called from an `expr' Range, so the page signal belongs to the retained route owner while the structural forms remain ordinary compiled View calls." (pcase page ('data (etaf-view (operations-console-data-surface :model model))) ('resource (etaf-view (operations-console-resource-surface :model model))) (_ (etaf-view (operations-console-overview-surface :model model :main-form main-form))))) (etaf-define-component etaf-operations-console-page-router (&key page-ref model main-form) "Render the current material page from PAGE-REF and MODEL. The page signal is read by this retained router Component, not by the root shell, so navigation does not invalidate the whole application generation." :setup (lambda () ;; Keep one material Host as the route owner's layout anchor. Page ;; surfaces are Components, so the route never injects a raw View through ;; an unowned expr and the containing-block width remains explicit. (let ((model (etaf-current-prop :model)) (main-form (etaf-current-prop :main-form)) (page-ref (etaf-current-prop :page-ref))) (etaf-view (fragment (column :class "operations-console-page-router" :width 'stretch :ref 'operations-console-page-slot (expr :value (etaf-operations-console-page-view (etaf-value page-ref) model main-form)))))))) ;;; Root shell: Context provider, two composable instances, and viewport. (etaf-define-component etaf-operations-console-shell (&key model static-form page-ref) "Compose the complete public ETAF application." :styles (styles (".operations-console-shell" :width stretch :padding (1 2)) (".operations-console-shell-header" :width stretch :padding (1 2)) (".operations-console-nav" :padding (0 2) :border ((1) solid "#687386")) (".operations-console-main" :width stretch :padding (1 2)) (".operations-console-page" :width stretch) (".operations-console-status" :width stretch :padding (0 2) :border ((1) solid "#687386"))) :setup (let* ((instance-model model) (page-cell page-ref) (title (etaf-operations-console-static-value static-form :title "Operations Console")) (kicker (etaf-operations-console-static-value static-form :kicker "ETAF / reference workspace")) (header-form (etaf-operations-console-static-child static-form 'header)) (navigation-form (etaf-operations-console-static-child static-form 'navigation)) (main-form (etaf-operations-console-static-child static-form 'main)) (status-form (etaf-operations-console-static-child static-form 'status)) (brand-form (etaf-operations-console-static-child header-form 'brand)) (summary-form (etaf-operations-console-static-child header-form 'summary)) (theme-control-form (etaf-operations-console-static-child header-form 'theme-control)) (overview-tab (etaf-operations-console-static-child-by-value navigation-form 'tab :key "overview")) (data-tab (etaf-operations-console-static-child-by-value navigation-form 'tab :key "data")) (resource-tab (etaf-operations-console-static-child-by-value navigation-form 'tab :key "resource")) (brand-mark (etaf-operations-console-static-value brand-form :mark "OC")) (brand-name (etaf-operations-console-static-value brand-form :name title)) (summary-status (etaf-operations-console-static-value summary-form :status "All systems nominal")) (theme-label (etaf-operations-console-static-value theme-control-form :label "Theme")) (overview-label (etaf-operations-console-static-value overview-tab :label "Overview")) (data-label (etaf-operations-console-static-value data-tab :label "Data")) (resource-label (etaf-operations-console-static-value resource-tab :label "Resource")) (dark (etaf-ref nil :name 'operations-console-dark-theme)) (theme (etaf-computed (lambda () (if (etaf-value dark) '(:color "#EDF2F4" :bgcolor "#111923" :surface "#182433" :line "#344455" :teal "#61C6BA" :coral "#FF957F" :amber "#EFC06C" :success "#73D29D") '(:color "#142235" :bgcolor "#F6F1E8" :surface "#FFFDF8" :line "#C8C1B6" :teal "#2E8B83" :coral "#E26D5A" :amber "#D99A3D" :success "#3E9B72")))))) (unless (and header-form navigation-form main-form status-form brand-form summary-form theme-control-form overview-tab data-tab resource-tab) (error "Invalid Operations Console shell composition: %S" static-form)) (etaf-provide 'operations-console-theme theme) (etaf-theme-provide theme) (etaf-on-unmounted (lambda () (etaf-operations-console-dispose-model instance-model))) (lambda () (etaf-view (column :class "operations-console-shell" :width 'stretch :height '(viewport-height) (column :class "operations-console-shell-header" :width 'stretch (flex :width 'stretch :align-items 'center (column :width 'stretch :flex-grow 1 :flex-shrink 1 :min-width 0 (label :face 'bold :text (format "%s %s" brand-mark brand-name)) (label :text kicker)) (label :text (format "● %s" summary-status) :color (etaf-theme-value :success "#3E9B72"))) (label :text "A calm reference surface for complex state, ownership, and recovery.")) (flex :class "operations-console-nav" :width 'max-content :ref 'operations-console-nav :align-items 'center :gap '(0 (8)) (button :label overview-label :ref 'operations-console-nav-overview :on-press (lambda () (setf (etaf-value page-cell) 'overview))) (button :label data-label :ref 'operations-console-nav-data :on-press (lambda () (setf (etaf-value page-cell) 'data))) (button :label resource-label :ref 'operations-console-nav-resource :on-press (lambda () (setf (etaf-value page-cell) 'resource))) (checkbox :label theme-label :ref 'operations-console-theme-toggle :checked (etaf-value dark) :color (etaf-theme-value :color "#252A2E") :bgcolor (etaf-theme-value :bgcolor "#F8F5EE") :on-change (lambda (value) (setf (etaf-value dark) value))) ;; Reserve the small status slot explicitly so a theme flip changes ;; paint/content inside the control bar without reflowing its parent. (label :width 12 :text (if (etaf-value dark) "Theme: Dark" "Theme: Light"))) (column :class "operations-console-main" :width 'stretch :flex-grow 1 :flex-shrink 1 :ref 'operations-console-main (operations-console-page-router :page-ref page-cell :model instance-model :main-form main-form)) (column :class "operations-console-status" :width 'stretch :flex-shrink 0 :ref 'operations-console-status (label :text (or (etaf-operations-console-static-value status-form :label nil) "Ready for review")))))))) ;;; Public View/open/close entry points. (defun etaf-operations-console-view (model static-form page-ref) "Return the root View for MODEL, STATIC-FORM, and stable PAGE-REF." (etaf-view (operations-console-shell :model model :static-form static-form :page-ref page-ref))) (defun etaf-operations-console-root (static-form) "Consume validated STATIC-FORM and return one owned application root View." (unless (equal static-form '(operations-console-shell :title "Operations Console" :kicker "ETAF / reference workspace" (header (brand :mark "OC" :name "Operations Console") (summary :status "All systems nominal") (theme-control :label "Theme")) (navigation (tab :key "overview" :label "Overview" :index "01") (tab :key "data" :label "Data desk" :index "02") (tab :key "resource" :label "Resource lab" :index "03")) (main (overview (hero :eyebrow "Tuesday / 09:42 / live review" :title "Make complex state feel calm.") (metric-strip (metric :key "throughput" :label "Throughput") (metric :key "flows" :label "Active flows") (metric :key "response" :label "Response") (metric :key "reliability" :label "Reliability")) (workspace (activity-panel :title "Activity stream") (capability-panel :title "Capability map")) (timeline :title "Event trail")) (data :title "Data desk") (resource :title "Resource lab")) (status :label "Ready for review"))) (error "Unsupported Operations Console static root: %S" static-form)) (let ((model (etaf-operations-console-create-model)) (page (etaf-ref 'overview :name 'operations-console-page))) (lambda () (etaf-operations-console-view model static-form page)))) ;;;###autoload (defun etaf-operations-console-open (&optional buffer-name) "Open the canonical Playground pair in BUFFER-NAME." (interactive) (require 'etaf-playground) (etaf-playground-open (or buffer-name etaf-operations-console-buffer))) ;;;###autoload (defun etaf-operations-console-close (&optional buffer-name) "Unmount and kill the application buffer named BUFFER-NAME." (interactive) (let* ((name (or buffer-name etaf-operations-console-buffer)) (runtime (etaf-runtime-for-buffer name)) (buffer (get-buffer name))) (when runtime (etaf-unmount runtime)) (when (buffer-live-p buffer) (kill-buffer buffer)) buffer)) (provide 'etaf-operations-console) ;;; operations-console.el ends here