portal-mojo 0.2.19 → 0.2.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/README.md +7 -1
- package/docs/admin-credentials.md +27 -0
- package/docs/admin-deployments.md +201 -0
- package/docs/admin-dns-certificates.md +160 -0
- package/docs/admin-dns-domains.md +92 -0
- package/docs/admin-dns.md +18 -0
- package/docs/admin-edge.md +200 -196
- package/docs/admin-fleet-configuration.md +98 -2
- package/docs/admin-geolocation.md +100 -0
- package/docs/admin-identity-directories.md +12 -0
- package/docs/admin-maintenance.md +133 -0
- package/docs/admin-modals.md +45 -2
- package/docs/admin-operational-fleet.md +206 -0
- package/docs/admin-presentation.md +51 -0
- package/docs/admin-signin.md +12 -2
- package/docs/auth-pages.md +18 -6
- package/docs/auth.md +16 -2
- package/docs/client.md +7 -0
- package/docs/collection-select.md +14 -0
- package/docs/combobox.md +18 -0
- package/docs/popover.md +5 -4
- package/package.json +1 -1
- package/src/admin/core/OperationsHelp.tsx +10 -0
- package/src/admin/core/index.ts +6 -4
- package/src/admin/core/route-context.ts +6 -0
- package/src/admin/credentials/AcmeConsumerKeyDialog.tsx +88 -0
- package/src/admin/credentials/acme-consumer-key.ts +34 -0
- package/src/admin/credentials/group-api-keys.tsx +5 -3
- package/src/admin/deployments/ApiDeploymentDetail.tsx +58 -0
- package/src/admin/deployments/DeploymentsPage.tsx +73 -0
- package/src/admin/deployments/WebAppDeploySetup.tsx +49 -0
- package/src/admin/deployments/WebAppDeploymentDetail.tsx +59 -0
- package/src/admin/deployments/WebAppDetail.tsx +104 -0
- package/src/admin/deployments/WebAppEditDialog.tsx +70 -0
- package/src/admin/deployments/WebAppKeyDialog.tsx +25 -0
- package/src/admin/deployments/WebAppOnboardingDialog.tsx +217 -0
- package/src/admin/deployments/WebAppRollbackDialog.tsx +82 -0
- package/src/admin/deployments/WebAppUploadPanel.tsx +132 -0
- package/src/admin/deployments/api.ts +158 -0
- package/src/admin/deployments/authority-state.ts +9 -0
- package/src/admin/deployments/deployment-state.ts +13 -0
- package/src/admin/deployments/index.ts +4 -0
- package/src/admin/deployments/onboarding-state.ts +11 -0
- package/src/admin/deployments/permissions.ts +37 -0
- package/src/admin/deployments/receipts.ts +78 -0
- package/src/admin/deployments/sanitize.ts +73 -0
- package/src/admin/deployments/shared.tsx +39 -0
- package/src/admin/deployments/types.ts +238 -0
- package/src/admin/deployments/upload.ts +53 -0
- package/src/admin/deployments/useDeploymentObservation.ts +104 -0
- package/src/admin/dns/CertificateDetail.tsx +8 -3
- package/src/admin/dns/CertificateRequestDialog.tsx +45 -7
- package/src/admin/dns/DomainDetail.tsx +14 -4
- package/src/admin/dns/DomainOnboardingContent.tsx +44 -0
- package/src/admin/dns/DomainOnboardingDialog.tsx +5 -24
- package/src/admin/dns/DomainPurchaseWizard.tsx +1 -1
- package/src/admin/dns/DomainRegisterExisting.tsx +63 -0
- package/src/admin/dns/DomainRegistrarSettings.tsx +52 -0
- package/src/admin/dns/DomainsPage.tsx +26 -13
- package/src/admin/dns/SharedValidationDialog.tsx +298 -0
- package/src/admin/dns/SharedValidationPanel.tsx +76 -0
- package/src/admin/dns/api.ts +4 -2
- package/src/admin/dns/domain-navigation.ts +16 -0
- package/src/admin/dns/registrar-api.ts +13 -0
- package/src/admin/dns/shared-validation-api.ts +90 -0
- package/src/admin/dns/shared-validation-data.ts +106 -0
- package/src/admin/domains/assistant.ts +5 -4
- package/src/admin/domains/communications.ts +10 -9
- package/src/admin/domains/identity.ts +8 -7
- package/src/admin/domains/infrastructure.ts +19 -13
- package/src/admin/domains/lazy-page.ts +6 -0
- package/src/admin/domains/observability.ts +6 -5
- package/src/admin/domains/operations.ts +27 -10
- package/src/admin/domains/security.ts +16 -15
- package/src/admin/edge/EdgeHelp.tsx +10 -0
- package/src/admin/edge/ServingReadiness.tsx +54 -0
- package/src/admin/edge/VhostDetail.tsx +145 -139
- package/src/admin/edge/VhostWizard.tsx +204 -115
- package/src/admin/edge/VhostsPage.tsx +27 -28
- package/src/admin/edge/api.ts +24 -10
- package/src/admin/edge/models.ts +4 -4
- package/src/admin/edge/serving-data.ts +78 -0
- package/src/admin/fleet/CapacityEditor.tsx +81 -0
- package/src/admin/fleet/CapacityInspector.tsx +19 -0
- package/src/admin/fleet/CapacityProgress.tsx +9 -0
- package/src/admin/fleet/FleetHelp.tsx +7 -0
- package/src/admin/fleet/FleetOverview.tsx +150 -0
- package/src/admin/fleet/FleetPage.tsx +11 -0
- package/src/admin/fleet/FleetWorkspace.tsx +82 -0
- package/src/admin/fleet/ScaleFleetDialog.tsx +169 -0
- package/src/admin/fleet/access.ts +22 -0
- package/src/admin/fleet/api.ts +77 -0
- package/src/admin/fleet/data.ts +148 -0
- package/src/admin/fleet/index.ts +8 -0
- package/src/admin/fleet/operations.ts +179 -0
- package/src/admin/fleet/standalone-data.ts +87 -0
- package/src/admin/fleet/types.ts +208 -0
- package/src/admin/fleet-configuration/FleetConfigurationPage.tsx +14 -8
- package/src/admin/fleet-configuration/SharedValidationConnectionPanel.tsx +166 -0
- package/src/admin/fleet-configuration/data.ts +4 -0
- package/src/admin/fleet-configuration/operator-destinations.ts +20 -0
- package/src/admin/fleet-configuration/shared-validation-data.ts +143 -0
- package/src/admin/geolocation/GeoLocationPage.tsx +171 -0
- package/src/admin/geolocation/data.ts +138 -0
- package/src/admin/geolocation/index.ts +3 -0
- package/src/admin/identity/groups/group-sections/SubGroupsSection.tsx +73 -2
- package/src/admin/identity/groups/models.ts +2 -0
- package/src/admin/identity/members/GroupMembersPanel.tsx +2 -8
- package/src/admin/index.ts +8 -0
- package/src/admin/maintenance/MaintenanceDialogs.tsx +161 -0
- package/src/admin/maintenance/MaintenancePage.tsx +442 -0
- package/src/admin/maintenance/data.ts +486 -0
- package/src/admin/maintenance/index.ts +3 -0
- package/src/admin/maintenance/operations.ts +208 -0
- package/src/admin/public/infrastructure.ts +1 -0
- package/src/admin/public/operations.ts +3 -0
- package/src/admin/registry.ts +6 -2
- package/src/admin/settings/SettingDetail.tsx +7 -2
- package/src/admin/settings/SettingEditor.tsx +2 -1
- package/src/admin/settings/SettingsPage.tsx +3 -1
- package/src/admin/settings/model.ts +1 -0
- package/src/admin/signin/SigninPage.tsx +17 -3
- package/src/admin/signin/api.ts +2 -0
- package/src/charts/MetricsChartView.tsx +4 -11
- package/src/charts/MetricsMiniWidget.tsx +3 -15
- package/src/client/auth.ts +77 -25
- package/src/client/client.ts +6 -0
- package/src/client/deployments-mock.ts +375 -0
- package/src/client/domain-operations-mock.ts +37 -0
- package/src/client/fleet-mock.ts +73 -1
- package/src/client/geo-provider-mock.ts +82 -0
- package/src/client/index.ts +2 -2
- package/src/client/maintenance-mock.ts +285 -0
- package/src/client/mock.ts +280 -11
- package/src/client/operational-fleet-mock.ts +279 -0
- package/src/client/operations-mock.ts +85 -0
- package/src/client/serving-mock.ts +22 -0
- package/src/styles/components/admin-deployments.css +35 -0
- package/src/styles/components/admin-dns-certificates.css +33 -0
- package/src/styles/components/admin-domains.css +12 -0
- package/src/styles/components/admin-edge.css +125 -1
- package/src/styles/components/admin-geolocation.css +40 -0
- package/src/styles/components/admin-maintenance.css +127 -0
- package/src/styles/components/admin-operational-fleet.css +38 -0
- package/src/styles/components/admin-operations.css +9 -0
- package/src/styles/components/admin-signin.css +2 -0
- package/src/styles/components/combobox.css +12 -2
- package/src/styles/components/fleet-page.css +9 -0
- package/src/styles/index.css +7 -0
- package/src/ui/CollectionSelect.tsx +30 -8
- package/src/ui/ComboBox.tsx +39 -8
- package/src/ui/FilterBar.tsx +3 -5
- package/src/ui/ModelTable.tsx +2 -8
- package/src/ui/Popover.tsx +15 -7
- package/src/ui/date/TimePicker.tsx +4 -14
- package/src/ui/image-editor/ImageEditor.tsx +4 -5
- package/src/ui/schema-form-core.tsx +3 -5
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# GeoLocation provider setup
|
|
2
|
+
|
|
3
|
+
`GeoLocationPage` (`portal-mojo/admin/operations`) is the global Operations →
|
|
4
|
+
GeoLocation surface. GeoIP Cache inspects IPs; Fleet Configuration applies
|
|
5
|
+
published settings. Dashboard is unchanged. Hosts may override the mount-derived Fleet link with
|
|
6
|
+
`fleetConfigurationPath`; Showcase opens the actual Fleet Configuration page with a return link.
|
|
7
|
+
|
|
8
|
+
Admission requires literal `is_superuser === true` and a current interactive
|
|
9
|
+
session. The backend also rejects key-backed sessions, requires same-origin
|
|
10
|
+
POSTs and authentication within 600 seconds. Global/group grants do not replace
|
|
11
|
+
these checks. `usePrivateOperator` remounts on session change, aborts requests and
|
|
12
|
+
owned dialogs, and rechecks authority before sending and accepting responses.
|
|
13
|
+
|
|
14
|
+
## Tasks
|
|
15
|
+
|
|
16
|
+
Primary, fallback and ordered additional providers form one visible configuration task,
|
|
17
|
+
with add, remove and move controls. MojoVerify credentials and threat sharing sit
|
|
18
|
+
below the chain. One retained draft and Save/Discard footer cover the form; there
|
|
19
|
+
is no tab navigation for parts of the same task. The uncontrolled password element
|
|
20
|
+
stays mounted while editing, and shared Tabs is unchanged.
|
|
21
|
+
|
|
22
|
+
MojoVerify always uses `https://api.mojoverify.com`; no URL control is shown.
|
|
23
|
+
Older origins remain readable, but this page stages the hosted URL and warns
|
|
24
|
+
that switching requires a replacement key. Provider names are human-readable;
|
|
25
|
+
unknown configured identifiers are retained. New additional rows exclude primary,
|
|
26
|
+
fallback and existing rows. Runtime deduplicates the chain; existing overlaps are
|
|
27
|
+
not silently rewritten. Non-Mojo credentials are configured outside this endpoint.
|
|
28
|
+
The server's values are authoritative: setup defaults differ from runtime defaults.
|
|
29
|
+
|
|
30
|
+
No key shows **Add key**; a configured key shows **Replace key** and **Remove
|
|
31
|
+
key**. Test key sits with the credential. Blank replacement preserves the stored
|
|
32
|
+
key; confirmed removal is staged until Save changes and does not revoke remotely.
|
|
33
|
+
Save/Discard reflect actual draft changes. Refresh and the page-owned Open Fleet Configuration link confirm before discarding an
|
|
34
|
+
unsaved draft. Keep editing preserves both provider selections and the entered key;
|
|
35
|
+
explicit departure wipes the key before navigation. An in-flight operation cannot
|
|
36
|
+
be interrupted through that link. Info popovers hold secondary explanations; Configuration information
|
|
37
|
+
opens a focused native dialog for revision and publication facts. No disclosure
|
|
38
|
+
sections or sidebar modal are used.
|
|
39
|
+
|
|
40
|
+
Last stored-key check shows its historical outcome and timestamp separately from
|
|
41
|
+
the draft result. Pending activation and Open Fleet Configuration remain visible.
|
|
42
|
+
A false pending flag concerns only this request node, never proves fleet health.
|
|
43
|
+
|
|
44
|
+
## Private protocol
|
|
45
|
+
|
|
46
|
+
`readGeoLocation()` positively projects only `provider_setup` from schema-v1
|
|
47
|
+
`/api/account/admin/settings`. Catalog, SMS, unknown fields and raw credentials
|
|
48
|
+
are discarded. Form state is imperative, outside Query/Mutation caches.
|
|
49
|
+
|
|
50
|
+
`buildGeoPayload(action, configuration_revision, draft, keyEdit)` sends exactly
|
|
51
|
+
`{action,topic:'geoip',providers:{expected_revision,geoip}}`. The revision is sent
|
|
52
|
+
even when null. The five static keys are primary, fallback, additional, Mojo URL
|
|
53
|
+
and sync. Untouched/blank replacement omits credentials; nonempty replacement
|
|
54
|
+
adds `GEOIP_API_KEY_MOJO`; confirmed removal adds `clear_api_key:true`.
|
|
55
|
+
Additional providers are unique and ordered, at most 16. Identifiers match
|
|
56
|
+
`^[a-z][a-z0-9_-]{0,31}$`. HTTPS origins permit no credentials, path, query,
|
|
57
|
+
fragment or alternate port (443 allowed); keys are at most 4096 characters.
|
|
58
|
+
|
|
59
|
+
Secrets stay only in the password DOM and short-lived request objects, whose
|
|
60
|
+
raw key is deleted in `finally`. They never enter React/Query/Mutation state,
|
|
61
|
+
URLs, storage, logs or mock observations. Editing retains the element and candidate;
|
|
62
|
+
Save attempts, explicit discard, fresh-auth refusal, session change and unmount
|
|
63
|
+
clear it. A stable ref callback wipes the password element before detachment;
|
|
64
|
+
removing the DOM node alone is insufficient. Writes are single-flight. A 440 invokes fresh authentication without
|
|
65
|
+
replaying; Refresh and a deliberate retry are required. Stale revisions
|
|
66
|
+
(400 “changed; reload before publishing”, or 409), unreadable state and uncertain
|
|
67
|
+
saves require authoritative Refresh before another write.
|
|
68
|
+
|
|
69
|
+
Test verifies **only MojoVerify credentials**, regardless of primary. It requires
|
|
70
|
+
the five delegated descriptor keys but not Fleet bucket/object/KMS/restart
|
|
71
|
+
availability; Save requires the publishing plane. Sharing requires the remote
|
|
72
|
+
key's `geoip_sync` permission. The current backend also verifies Mojo on every
|
|
73
|
+
Save except explicit removal: selecting another primary does not enable an
|
|
74
|
+
independent no-Mojo setup. This page does not invent provider-chain testing,
|
|
75
|
+
other-provider key editing, provisioning, revocation or an Apply endpoint.
|
|
76
|
+
|
|
77
|
+
A draft-key test does not rewrite stored verification. The backend's stored-test
|
|
78
|
+
predicate is no replacement plus the node-loaded origin and sync value; chain
|
|
79
|
+
changes do not affect it. Tests reread stored evidence without rebasing the
|
|
80
|
+
draft's revision. Revision changes or lost normalization authority block retry;
|
|
81
|
+
publishing-only unavailability does not block diagnostics. Loaded/desired origin
|
|
82
|
+
drift can prevent stored-key reuse until Fleet apply or explicit replacement.
|
|
83
|
+
|
|
84
|
+
Save rereads authoritative configuration. `published:true` means static
|
|
85
|
+
publication with restart pending; `unchanged:true` can still mean the database
|
|
86
|
+
credential changed. Neither result proves activation. Failed, stale and uncertain
|
|
87
|
+
requests keep errors actionable and never become successful saves.
|
|
88
|
+
|
|
89
|
+
## Verification
|
|
90
|
+
|
|
91
|
+
`geo-provider-mock.ts` supplies isolated safe observations (action, key action,
|
|
92
|
+
stored-test predicate, expected revision), with no submitted key retained.
|
|
93
|
+
Scenarios include no-key setup, real registry names, unknown/empty registry,
|
|
94
|
+
publishing unavailable, stale/fresh-auth/uncertain outcomes and loaded-origin drift.
|
|
95
|
+
Showcase's GeoLocation demo mounts the actual page. Run
|
|
96
|
+
`npm run verify:admin-geolocation` and `npm run verify:admin-geolocation-mounted`;
|
|
97
|
+
JSDOM behavior does not establish native focus or layout. Inspect both apps,
|
|
98
|
+
light/dark, desktop/390px, opened dialogs and error recovery per
|
|
99
|
+
[Admin presentation](admin-presentation.md). The scoped stylesheet is included
|
|
100
|
+
through `portal-mojo/styles.css`.
|
|
@@ -35,6 +35,18 @@ existing system permission gate and conditional queries. Parent, child, member
|
|
|
35
35
|
and user navigation opens native detail modals while keeping the directory
|
|
36
36
|
underneath.
|
|
37
37
|
|
|
38
|
+
The Sub-Groups section carries the "Administrators can create sub-groups"
|
|
39
|
+
switch for `sys.groups | sys.manage_groups` holders only; nobody else sees it.
|
|
40
|
+
It reads `metadata.protected.allow_member_subgroups === true` (anything else
|
|
41
|
+
is off) and changes it only through the django-mojo Group action
|
|
42
|
+
`POST /api/group/<id> {"allow_member_subgroups": true|false}`, which answers
|
|
43
|
+
`{"status": true, "allow_member_subgroups": <bool>}`. Never write
|
|
44
|
+
`metadata.protected` directly: that path refuses `manage_groups` admins. The
|
|
45
|
+
action needs django-mojo with #9126; the server refuses a caller without the
|
|
46
|
+
global grant with 403 and a non-boolean with 400. While on, people who manage
|
|
47
|
+
the group as members can create groups directly under it; the setting is not
|
|
48
|
+
inherited by the new groups, and turning it off leaves existing groups alone.
|
|
49
|
+
|
|
38
50
|
The group model and section code are adapted from the reference portal at
|
|
39
51
|
`v0.2.5` commit `93c7fdfeb3096d33010e72bd4483cf9ca6e3d6f5`. The source hashes
|
|
40
52
|
and corresponding package hashes are recorded in
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Maintenance
|
|
2
|
+
|
|
3
|
+
```tsx
|
|
4
|
+
import { MaintenancePage } from 'portal-mojo/admin/operations';
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
`MaintenancePage` supplies one global Operations destination at `maintenance`.
|
|
8
|
+
It renders Database, Cache and Framework as independent evidence sections.
|
|
9
|
+
Page admission is AWS read (`manage_aws`) **or** framework read
|
|
10
|
+
(`view_platform`, `manage_platform`, `admin`), with literal superuser bypass.
|
|
11
|
+
Each read uses the Fleet exact backend permission helper; group membership,
|
|
12
|
+
the frontend admin wildcard and `comms` do not grant AWS authority.
|
|
13
|
+
|
|
14
|
+
A scan reports offered major upgrades, region, scan time, scheduled-scanning
|
|
15
|
+
state and each warning's exact IAM action. It supplies no complete inventory
|
|
16
|
+
counts. Empty findings mean **No offered major upgrades found in this scan**.
|
|
17
|
+
Partial or unavailable scans never establish support coverage. Standard and
|
|
18
|
+
extended deadlines are separate; an unpublished deadline remains unknown.
|
|
19
|
+
Targets and resource identifiers retain their server spelling. Release notes
|
|
20
|
+
accept credential-free HTTPS links only.
|
|
21
|
+
|
|
22
|
+
Writes additionally require platform management authority and current managed
|
|
23
|
+
infrastructure proof. Bootstrap has its own independent dashboard permission:
|
|
24
|
+
without that grant the page retains authorized inventory but cannot establish
|
|
25
|
+
mode or offer writes. External infrastructure remains readable and explains
|
|
26
|
+
that IaC owns changes. Missing, denied or malformed mode proof blocks writes.
|
|
27
|
+
The backend remains authoritative for interactive, non-key-backed access and
|
|
28
|
+
600-second fresh authentication.
|
|
29
|
+
|
|
30
|
+
The native confirmation names current and target versions, outage/restart
|
|
31
|
+
impact, and snapshot-based recovery. Type the exact case-sensitive resource
|
|
32
|
+
identifier and explicitly choose Immediately or Next maintenance window.
|
|
33
|
+
`apply_immediately` is a real boolean, including `false`. Changing evidence or
|
|
34
|
+
session closes the old confirmation. Confirmation is single-flight; transport
|
|
35
|
+
uses `mojoCall`, AbortSignals and a final session/authority fence without retry,
|
|
36
|
+
`withFreshAuth`, Query mutations or raw fetch.
|
|
37
|
+
|
|
38
|
+
After acceptance the exact resource and target are observed every ten seconds,
|
|
39
|
+
at most 180 times. Completion requires both `settled === true` and
|
|
40
|
+
`upgraded === true`. A target version before settlement, old available version,
|
|
41
|
+
missing resource, denied/malformed read, or mixed cache member versions remains
|
|
42
|
+
unconfirmed. Timeout retains the receipt and offers explicit status refresh.
|
|
43
|
+
|
|
44
|
+
Attempts are scoped by installation and actor in a module registry, surviving
|
|
45
|
+
dialog closure, navigation/remount, timeout, ordinary token renewal and a new
|
|
46
|
+
session for the same actor. Unmount/session changes abort local observations;
|
|
47
|
+
provider work can continue. An attempted/unknown provider outcome never unlocks
|
|
48
|
+
another apply merely because a refreshed report still offers the old version.
|
|
49
|
+
A completed receipt permits a new, different offered target with new consent;
|
|
50
|
+
switching only the timing never bypasses the same-target guard.
|
|
51
|
+
Reconcile the provider operation and maintenance window. A definitive refusal
|
|
52
|
+
before provider work can be cleared only by a deliberate successful Refresh
|
|
53
|
+
Maintenance and a new confirmation. A 440 requests authentication once and
|
|
54
|
+
never replays the write.
|
|
55
|
+
|
|
56
|
+
Framework shows installed/latest versions, check time/source, pin policy,
|
|
57
|
+
update availability and the backend blocker. Held/pinned versions use
|
|
58
|
+
“Resume and update”. The operation clears the pin and
|
|
59
|
+
redeploys the last converged application SHA. Policy clearing and deployment
|
|
60
|
+
acceptance are separate facts: a 503 or lost response can leave automatic policy
|
|
61
|
+
active with unknown deployment acceptance. That attempt remains guarded across
|
|
62
|
+
remount and reauthentication. Refresh Framework and inspect Deployments even
|
|
63
|
+
when no deployment ID was returned. Acceptance points to Deployments and never
|
|
64
|
+
claims fleet completion. The separate Update policy dialog saves Automatic (`""`), Hold (`"hold"`) or an
|
|
65
|
+
exact version through `POST /api/account/admin/advanced/settings` with only
|
|
66
|
+
`framework_pin`. It requires an active literal superuser and fresh authentication;
|
|
67
|
+
this page also keeps external infrastructure read-only. Syntax validation does
|
|
68
|
+
not verify that an exact version is published. Hold resolves the last converged
|
|
69
|
+
framework version. Saving policy never submits a deployment. The framework
|
|
70
|
+
Update action explicitly clears that policy and requests latest; it cannot
|
|
71
|
+
deploy an exact selection while retaining the pin.
|
|
72
|
+
|
|
73
|
+
A successful policy response followed by matching live policy readback completes
|
|
74
|
+
that policy attempt. A lost/uncertain response remains guarded even if the
|
|
75
|
+
desired value is later observed: current value does not prove request ownership
|
|
76
|
+
or that a delayed writer finished. There is no policy revision or durable receipt
|
|
77
|
+
lookup. Reconcile server audit before further policy writes; there is no reset
|
|
78
|
+
button. Generic Settings directs `EDGE_FRAMEWORK_VERSION` to the mounted
|
|
79
|
+
Maintenance owner, rather than submitting through the rejected generic writer.
|
|
80
|
+
|
|
81
|
+
Framework submissions with an acknowledged UUID observe that exact deployment
|
|
82
|
+
and SHA through the bounded platform deployments collector. Only `converged`,
|
|
83
|
+
`failed`, and `superseded` release its submission guard for a different target;
|
|
84
|
+
`verified`, `partial`, `unknown`, absence, and errors do not. Deployment terminal
|
|
85
|
+
status is distinct from requested framework-version proof. That requires a
|
|
86
|
+
nonempty unique frozen runner roster, unique matching proof for each runner,
|
|
87
|
+
exact UUID/full SHA/version, and fresh valid observation timestamps. Missing
|
|
88
|
+
version proof remains explicit even when deployment converges. Lost acceptance
|
|
89
|
+
without a UUID cannot be reconciled from the latest same-SHA row.
|
|
90
|
+
|
|
91
|
+
Submitted operations remain compact rows across categories; View progress opens
|
|
92
|
+
a focused dialog with target, timing, last successful observation, current/pending
|
|
93
|
+
and member versions, or correlated deployment evidence. Manual refresh only reads.
|
|
94
|
+
Aurora settlement proves cluster-level state, not individual database members.
|
|
95
|
+
Module-memory receipts survive navigation and same-actor renewal; a full browser
|
|
96
|
+
reload loses them. Durable reload-safe reconciliation needs backend support.
|
|
97
|
+
|
|
98
|
+
`maintenanceDeploymentsHref(pathname)` preserves an embedded Admin prefix.
|
|
99
|
+
`MaintenancePage` also accepts an explicit `deploymentsHref`, `pollInterval`
|
|
100
|
+
and `pollLimit`; production defaults are ten seconds and 180 observations.
|
|
101
|
+
|
|
102
|
+
Mock integration: call `maintenanceMock(path, method, body, params, context)`
|
|
103
|
+
only for its owned paths. It returns `undefined` for every sibling path.
|
|
104
|
+
`context` contains authenticated user, claim-derived `keyBacked` and `fresh`.
|
|
105
|
+
Use `readMaintenanceBootstrapFacts()` in the **single central bootstrap
|
|
106
|
+
composer**; Maintenance does not claim that endpoint. Preserve its explicit
|
|
107
|
+
`bootstrap` denied/malformed scenario and derive mode and managed capability
|
|
108
|
+
from the same facts. `MAINTENANCE_SCENARIOS` and `setMockMaintenanceScenario`
|
|
109
|
+
exercise partial scans, waiting/settlement, provider uncertainty and Framework
|
|
110
|
+
policy/deployment uncertainty through the actual page.
|
|
111
|
+
|
|
112
|
+
Integration manifest: lazy-load `admin/maintenance/MaintenancePage.tsx`; global
|
|
113
|
+
section id/path `maintenance`, label Maintenance, navigationGroup operations,
|
|
114
|
+
nav union `sys.manage_aws | sys.view_platform | sys.manage_platform | sys.admin`.
|
|
115
|
+
Import `styles/components/admin-maintenance.css`; register `AdminMaintenanceDemo`
|
|
116
|
+
from `apps/showcase/src/pages/components/demos-admin-maintenance.tsx` lazily.
|
|
117
|
+
Register `verify-admin-maintenance.mjs` and `verify-admin-maintenance-mounted.mjs`
|
|
118
|
+
once each; the harness is an imported test adapter, not a command. Public index
|
|
119
|
+
exports are MaintenancePage, maintenanceDeploymentsHref, maintenanceAccess,
|
|
120
|
+
frameworkActionLabel, MAINTENANCE_ENDPOINTS and maintenanceCompleted.
|
|
121
|
+
|
|
122
|
+
Resource rows keep the offered version, provider state and upgrade action visible. Support deadlines, member evidence and recovery notes remain under each row’s disclosure. Dates use compact local presentation and preserve the original wire value in their title. Framework policy uses readable labels; missing or refused evidence remains explicit.
|
|
123
|
+
|
|
124
|
+
### KISS presentation
|
|
125
|
+
|
|
126
|
+
Database, Cache and Django-MOJO use tabs when multiple categories are authorized.
|
|
127
|
+
A reader with only one authorized category sees its panel directly without a tab strip. Scan metadata is collapsed; scan errors, incomplete evidence and scanning-off warnings stay above the tabs. Submitted operations remain visible independently of the selected category. See [visual QA](admin-presentation.md).
|
|
128
|
+
|
|
129
|
+
Standard support deadlines within 30 days or overdue remain visible on resource rows;
|
|
130
|
+
standard and extended support stay separate. Missing support dates are not
|
|
131
|
+
interpreted as supported. Framework status distinguishes current, policy-paused
|
|
132
|
+
published versions, and unavailable/latest-unknown evidence, with source details
|
|
133
|
+
in accessible info popovers.
|
package/docs/admin-modals.md
CHANGED
|
@@ -11,6 +11,20 @@ or rename an action pane to disguise it. Genuine autosave fields remain content.
|
|
|
11
11
|
A nested child may have its own contextual actions. Evidence such as a firewall
|
|
12
12
|
log's Action **column** describes the event and is not an operation section.
|
|
13
13
|
|
|
14
|
+
Serving hostname inspection uses a compact `modal.open` with horizontal task
|
|
15
|
+
tabs instead of a side rail: Overview, conditional Routes and Settings.
|
|
16
|
+
Certificate details and a direct certificate editor are available in Overview.
|
|
17
|
+
Its Hostname/Certificate/Settings editor and Hostname → Certificate → Review
|
|
18
|
+
create flow keep one draft. The launcher guards native dismissal while any write or
|
|
19
|
+
route preflight is pending; focused child editors retain the same owner lifetime.
|
|
20
|
+
This is scoped to Serving and does not change the shared DetailView contract.
|
|
21
|
+
|
|
22
|
+
Deployments likewise uses compact `modal.open` task dialogs: API Overview/Nodes/
|
|
23
|
+
Activity; WebApp Overview/Deployments/Releases/Deploy/Settings. Read-only actors
|
|
24
|
+
omit deployment controls, and attempt viewers get a direct overview when there
|
|
25
|
+
is no admitted node evidence. Workflow, integration, setup identity and profile
|
|
26
|
+
editing use focused child dialogs. No shared DetailView default is changed.
|
|
27
|
+
|
|
14
28
|
Use `modal-pad`, `modal-title`, `modal-message`, grouped fields and `modal-actions`.
|
|
15
29
|
Cancel precedes the primary button. Pending operations disable repeat submission;
|
|
16
30
|
`canDismiss` also protects native Escape/backdrop dismissal during a write.
|
|
@@ -70,7 +84,8 @@ the inventory using `node scripts/verify-admin-modals.mjs --write-inventory`.
|
|
|
70
84
|
| Storage/shortlinks | Bucket, FileManager, File, shortlink; owner/backend/test/CORS/upload/rendition/share | FileManager/shortlink/share active state; no File disable promise; bucket empty only |
|
|
71
85
|
| Email/support | Domain, mailbox, sent message, template, contact; credentials/onboarding/audit/reconcile/test/template/status | Preserve evidence; separate mailbox directions and support status |
|
|
72
86
|
| Phone/Push | Number, SMS, config, device, delivery, template; lookup/test/config editors | Config/template lifecycle; number/SMS/device/delivery evidence retained |
|
|
73
|
-
|
|
|
87
|
+
| Operations | Fleet capacity planning, Maintenance exact resource/window confirmation, GeoLocation local key-removal confirmation, API/WebApp detail and focused onboarding/recovery/upload/credential flows | No generic deployment/release edits or deletion; staged intent, observed receipts and transient secrets remain distinct |
|
|
88
|
+
| Edge | Vhost with nested routes; Hostname → Certificate → Review creation, route editor, upstream declare/retire, blocklist entry editor | Vhost and upstream enabled state; upstreams retire and are never deleted; vhost, route and blocklist deletion are retained operations |
|
|
74
89
|
| Assistant/settings | Conversation, Skill, Setting; feed continuation, scoped memory, typed settings editor | Owner-only continuation; Skill active selection; memory is scoped editing |
|
|
75
90
|
|
|
76
91
|
## Resource lifecycle matrix
|
|
@@ -93,7 +108,7 @@ the inventory using `node scripts/verify-admin-modals.mjs --write-inventory`.
|
|
|
93
108
|
| Push config / template | Existing active selection with separate manage/test grants |
|
|
94
109
|
| Assistant conversation | Retain history; no arbitrary REST save or invented archive |
|
|
95
110
|
| Assistant Skill | Existing `is_active` save requires `sys.view_admin`; authoritative reload after mutation |
|
|
96
|
-
| Edge vhost | Enable/disable
|
|
111
|
+
| Edge vhost | Enable/disable and Edit in the header; Delete in the header menu. Disabling keeps the row and is how a replacement is staged |
|
|
97
112
|
| Edge upstream | `is_enabled` only. Retire (platform administrators) disables and keeps the row; server `CAN_DELETE=False` |
|
|
98
113
|
| Edge blocklist entry | Mode is the lifecycle: `off` parks an entry without losing it. Deletion is a retained operation |
|
|
99
114
|
| Other logs/devices/history | Read-only by default, even where low-level REST supports DELETE |
|
|
@@ -135,3 +150,31 @@ browser interactions for all family bodies, both themes, desktop/narrow,
|
|
|
135
150
|
keyboard navigation and console checks. The lazy Showcase **Admin modal audit**
|
|
136
151
|
demo supplies long-title, rich/zero/dot badges, nested editor, lifecycle-cancel and
|
|
137
152
|
embedded-host cases. Existing ToastHost top-layer visibility work remains separate.
|
|
153
|
+
|
|
154
|
+
## Shared validation confirmations
|
|
155
|
+
|
|
156
|
+
The DNS shared-validation editor freezes the target group/domain, existing
|
|
157
|
+
allocation and session while an operation is pending. Grant additionally freezes
|
|
158
|
+
the imported request, active exact recipient UUID and client reference. Participant
|
|
159
|
+
revoke/cleanup freezes the selected current-page participant independently of any
|
|
160
|
+
request or recipient lookup; cleanup retry leaves the reference revoked.
|
|
161
|
+
Its owner AbortSignal closes only its confirmation on unmount, scope loss or
|
|
162
|
+
auth/session replacement; submitted writes can still persist. Escape/backdrop
|
|
163
|
+
and Close are unavailable while the outer operation is pending.
|
|
164
|
+
|
|
165
|
+
Prepare explains the pause of direct validation/renewal while valid material
|
|
166
|
+
remains available. Grant names the exact project and apex/wildcard issuance
|
|
167
|
+
authority and independent private-key custody. Revoke explains that future
|
|
168
|
+
validation stops, already-issued certificates remain valid and other consumers
|
|
169
|
+
keep working. Revoked references require a fresh, explicitly prepared request.
|
|
170
|
+
No confirmation is inferred from a copied descriptor. Fresh authentication
|
|
171
|
+
prompts without replay; every submitted result reconciles before another write.
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
The protected connection topic separately confirms Publish and Apply, naming
|
|
175
|
+
profile/project and exact revision consequences. The ACME consumer key form
|
|
176
|
+
confirms the current original Group name/UUID and fixed protected purpose before
|
|
177
|
+
issuance; its token display is transient and the existing audited reveal is
|
|
178
|
+
available for recovery. Every owned nested dialog receives the auth-owner abort
|
|
179
|
+
signal. Session replacement, scope loss and unmount close those dialogs; submitted
|
|
180
|
+
writes may still persist and are never replayed after fresh authentication.
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# Operational Fleet
|
|
2
|
+
|
|
3
|
+
`FleetOverview` is the reusable health matrix at the top of the global Dashboard.
|
|
4
|
+
`FleetPage` presents a separate standalone workspace at the mount-relative `/fleet` destination. Its task dialogs and styles are isolated from `FleetOverview`; the Admin Dashboard keeps its existing overview, disclosure, editor and behavior.
|
|
5
|
+
Import both, `backendGlobalCan`, contracts and pure staging helpers from
|
|
6
|
+
`portal-mojo/admin` (or `portal-mojo/admin/infrastructure`). The scale editor loads
|
|
7
|
+
only when opened. Existing Dashboard directory, activity and login panels remain
|
|
8
|
+
below this component.
|
|
9
|
+
|
|
10
|
+
```tsx
|
|
11
|
+
<FleetOverview mount="/product/control" />
|
|
12
|
+
<FleetPage mount="/product/control" />
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Both accept optional `mount`, `links` and `showConfigurationLink` props. The mount
|
|
16
|
+
is inferred from the current dashboard pathname, removing a final `/fleet` on
|
|
17
|
+
that page; pass it explicitly in a custom host. `links` maps source names to
|
|
18
|
+
`{ to: 'relative/registered/route', grants: ['exact_backend_key'], superuser?: true }`
|
|
19
|
+
or `null` to suppress a destination. Hosts with a partial registry must suppress
|
|
20
|
+
or replace unavailable destinations. Built-in links target existing Admin pages
|
|
21
|
+
only; Fleet Configuration remains its separate advanced superuser destination.
|
|
22
|
+
Use `showConfigurationLink={false}` when that destination is not mounted.
|
|
23
|
+
`FleetOverview` also accepts `headingLevel` (`1 | 2`, default `2`); use `1` when
|
|
24
|
+
rendering it as a standalone page. `FleetPage` supplies its own level-one Fleet heading.
|
|
25
|
+
`capacityDetails="modal"` replaces the capacity disclosure with a button and a
|
|
26
|
+
read-only modal. This option applies to `FleetOverview`. The reusable overview defaults to `"inline"` to preserve the current Admin Dashboard. `FleetPage` always uses the standalone tabbed capacity inspector.
|
|
27
|
+
|
|
28
|
+
## Authority and evidence
|
|
29
|
+
|
|
30
|
+
`backendGlobalCan(user, grant | grants)` checks global permissions only. It mirrors
|
|
31
|
+
Python truthiness of JSON values and the finite `helpers/perms.py` categories:
|
|
32
|
+
`users`, `groups`, `security`, `comms`, `jobs`, `metrics`, `files` imply only their
|
|
33
|
+
own `view_`/`manage_` checks. It has no group membership or implicit `admin`
|
|
34
|
+
wildcard. In particular `comms` and `admin` do not imply `manage_aws`.
|
|
35
|
+
|
|
36
|
+
The dashboard request needs `view_admin | manage_users | manage_settings | admin`
|
|
37
|
+
or literal superuser. Capacity reads separately require `manage_aws` or literal
|
|
38
|
+
superuser. Every request and query key is bound to actor plus session revision;
|
|
39
|
+
ordinary token renewal preserves that revision. Each denied read is suppressed.
|
|
40
|
+
Source statuses and server timestamps survive independently. The availability
|
|
41
|
+
headline is the server verdict; attention counts never recompute it. Missing
|
|
42
|
+
jobs/check observations stay unknown. Wholly restricted sections collapse to
|
|
43
|
+
one Restricted row. Unconfigured SMS/email and zero-ticket rows are absent.
|
|
44
|
+
Dashboard data is positively projected before Query storage; arbitrary nested
|
|
45
|
+
provider output and deployment stderr never enter this cache.
|
|
46
|
+
|
|
47
|
+
Load-balancer target health, fixed ingress addresses, and stable node outbound
|
|
48
|
+
addresses are distinct observations. Unknown egress reads say unavailable, never
|
|
49
|
+
an empty allowlist. Serving-process database/Redis reader routing is explicitly
|
|
50
|
+
per process. Database and cache members retain their own lifecycle/status. An Aurora reader absent from filtered instance facts may carry null class/status with unknown lifecycle. That database remains transition-blocked while node/cache evidence and independently supported changes remain available.
|
|
51
|
+
|
|
52
|
+
## Standalone Fleet workspace
|
|
53
|
+
|
|
54
|
+
`FleetPage` lazy-loads `FleetWorkspace`, and each inspection, editing and progress
|
|
55
|
+
body loads only when opened. Its scoped `.fleet-page` and
|
|
56
|
+
`.fleet-standalone-dialog` styles do not change the Dashboard. Infrastructure and Operations task tabs keep
|
|
57
|
+
the backend availability verdict and each source status. Overall observation age
|
|
58
|
+
is visible; each source timestamp stays in its info popover, while stale sources
|
|
59
|
+
also show their age inline. Stale thresholds remain in info popovers; refreshing never relabels
|
|
60
|
+
old evidence as current. Missing sources stay unknown, denied sections stay
|
|
61
|
+
restricted. Authorized, mounted related destinations are direct links on source names;
|
|
62
|
+
unauthorized destinations are omitted. Info popovers contain evidence, not navigation.
|
|
63
|
+
|
|
64
|
+
The primary action is **Change capacity**. **Inspect capacity** opens App nodes,
|
|
65
|
+
Database, Redis and Addresses tabs. Fleet outbound allowlist, fallback attachments,
|
|
66
|
+
reserved addresses and fixed load-balancer ingress appear separately. **Copy
|
|
67
|
+
allowlist** requires every availability proof, an enabled observed policy and no
|
|
68
|
+
pending nodes. Missing evidence never becomes an empty allowlist. Database and
|
|
69
|
+
Redis reader routing explicitly describe the serving process.
|
|
70
|
+
|
|
71
|
+
The standalone editor uses one `CapacityDraft` from `standalone-data.ts` across
|
|
72
|
+
App nodes, Database and Redis tabs. App nodes has Add nodes and Remove nodes tasks.
|
|
73
|
+
Additions require an explicit healthy, registered, running, settled source; its
|
|
74
|
+
size and target groups are shown, and Change subnet opens a focused override dialog.
|
|
75
|
+
Removal retains the existing self-node and healthy-floor checks; the server also
|
|
76
|
+
re-proves each target group's floor and ownership.
|
|
77
|
+
|
|
78
|
+
Every database member shows its exact ID, role and **current** class. Its size
|
|
79
|
+
select and remove checkbox target that ID; there is no automatic reader selection
|
|
80
|
+
or shared existing-reader sizing fan-out. Newly added readers inherit the current
|
|
81
|
+
source class, even when the writer also resizes. Observe their concrete IDs after
|
|
82
|
+
creation and resize separately. For a Redis group, stage size **or** replica
|
|
83
|
+
count in one plan. The other control is locked until the first returns to current
|
|
84
|
+
values; apply, refresh and separately review the second change. The pure compiler
|
|
85
|
+
rejects mixed-dimension intents independently of those controls because the
|
|
86
|
+
current backend cannot quote them cumulatively.
|
|
87
|
+
|
|
88
|
+
The explicit **Review changes (N)** button is the only plan request. It replaces
|
|
89
|
+
the editor with the authoritative server plan, including step order, warnings,
|
|
90
|
+
unknown prices, expiry and exact-plan consent. Review shows only allowlisted
|
|
91
|
+
server parameters for source node, subnet, target size, count and immediate-apply
|
|
92
|
+
mode when the server reports supported scalar values. Draft intent never fills
|
|
93
|
+
in missing plan facts. Source choices include the exact node ID. **Back to changes**
|
|
94
|
+
preserves the draft and invalidates consent. No background/debounced quote is
|
|
95
|
+
requested by the standalone editor. **Refresh and clear changes** explicitly discards the draft
|
|
96
|
+
before reading fresh inventory; there is no silent reset. Initial open also
|
|
97
|
+
requires a fresh observation before staging. Apply uses only `fleetOperations`.
|
|
98
|
+
Both standalone and Dashboard changes require a literal superuser, an interactive
|
|
99
|
+
user credential and backend fresh authentication. A 440 opens fresh authentication,
|
|
100
|
+
spends consent and requires an explicit refreshed review; planning and applying
|
|
101
|
+
are never automatically replayed.
|
|
102
|
+
|
|
103
|
+
**View capacity progress** is independently available when an in-session operation
|
|
104
|
+
record is retained with a non-idle status and the account has capacity-read
|
|
105
|
+
authority, including external infrastructure, unavailable inventories and non-superuser
|
|
106
|
+
readers. It uses the same in-session operation record as Dashboard. It never
|
|
107
|
+
hydrates an operation from storage or creates another coordinator. When an apply
|
|
108
|
+
reply is lost, the exact batch ID can be entered for read-only reconciliation of
|
|
109
|
+
the retained plan. Matching terminal evidence is required before another change.
|
|
110
|
+
Keep the current document open while reconciling: a full document reload loses
|
|
111
|
+
the in-memory operation record. Batch-ID entry reconciles a retained plan and
|
|
112
|
+
does not import an arbitrary operation after reload. Actor/session changes and
|
|
113
|
+
permission loss fence requests and close owned dialogs;
|
|
114
|
+
Escape/backdrop and explicit close are locked while requests are pending.
|
|
115
|
+
|
|
116
|
+
The Showcase demo uses `FleetPage` and a focused Demo controls dialog. Scenario
|
|
117
|
+
switching is disabled during unresolved operations. Read-only mock batch IDs are
|
|
118
|
+
available through Refresh mock evidence so lost replies can be reconciled without
|
|
119
|
+
clearing the browser's guard.
|
|
120
|
+
|
|
121
|
+
## Dashboard reviewed scaling
|
|
122
|
+
|
|
123
|
+
Scaling requires a literal superuser with capacity authority and a browser user
|
|
124
|
+
session. External infrastructure remains read-only. The backend enforces its
|
|
125
|
+
credential provenance and 600-second freshness requirement. A 440 opens the
|
|
126
|
+
existing fresh-auth handler, spends consent, and requires explicit refreshed
|
|
127
|
+
review. Neither planning nor applying is automatically replayed.
|
|
128
|
+
|
|
129
|
+
The existing Dashboard focused native dialog refreshes inventory before staging. Local intent is
|
|
130
|
+
compiled into at most 20 steps, then debounced about 400ms into
|
|
131
|
+
`POST /api/aws/capacity/plan {steps}`. Displayed order, descriptions, warnings,
|
|
132
|
+
prices and expiry come from that stored plan. Null prices are unknown. Editing,
|
|
133
|
+
refreshing, expiry, permission loss or session replacement invalidates consent.
|
|
134
|
+
A synchronous guard protects submission, including duplicate activation.
|
|
135
|
+
`POST /api/aws/capacity/plan/apply` sends only `{plan_id}`.
|
|
136
|
+
|
|
137
|
+
Node removal stages drain then terminate, excludes this serving node, requires
|
|
138
|
+
identified self and complete inventory, and retains one currently healthy target.
|
|
139
|
+
Unproven additions never satisfy the healthy floor. A freshly observed owned,
|
|
140
|
+
unregistered, settled node gets a separate Terminate drained node recovery path;
|
|
141
|
+
AWS ownership and drain completion are re-proved by the server. App size remains
|
|
142
|
+
informational. Add-node placement omits empty fields and locally validates subnet
|
|
143
|
+
shape; AWS proves the source, VPC, availability zone and address suitability.
|
|
144
|
+
|
|
145
|
+
Database writer and existing-reader sizes are independent curated keys. Reader
|
|
146
|
+
resizing fans out over surviving concrete reader IDs with different current
|
|
147
|
+
classes; staged removals are excluded. New readers inherit the **current** source
|
|
148
|
+
class, even when the writer also resizes in the plan. Refresh their concrete IDs
|
|
149
|
+
after creation and separately review resizing them. Writer resizing causes
|
|
150
|
+
minutes offline. Redis sizing applies to the whole group; replica counts retain
|
|
151
|
+
the server minimum and the editor explains rolling or downtime impact before
|
|
152
|
+
review. All count/cache/database resize steps explicitly send
|
|
153
|
+
`apply_immediately: true`.
|
|
154
|
+
|
|
155
|
+
## Observation and uncertain outcomes
|
|
156
|
+
|
|
157
|
+
`fleetOperations` lives outside component/dialog state. Its records contain safe
|
|
158
|
+
IDs and observed batch facts, keyed by installation and actor. Unresolved state
|
|
159
|
+
survives dialog closure, Dashboard/Fleet navigation, and same-actor reauthentication;
|
|
160
|
+
it does not survive a full document reload. Keep the current document open when
|
|
161
|
+
reconciling an uncertain submission. New sends and read replies are still fenced
|
|
162
|
+
to the exact session revision. A
|
|
163
|
+
different actor sees no previous actor record. No credentials or mutation drafts
|
|
164
|
+
are stored locally. The coordinator never replays a mutation. Expiry or session refusal at the final transport boundary is provably unsent: refresh inventory and review again. A transport failure after that boundary remains unknown and retains the reconciliation guard.
|
|
165
|
+
|
|
166
|
+
Running batches are observed about every ten seconds, with a backstop covering
|
|
167
|
+
90 minutes per step. Completed steps remain visible on failure; nothing rolls
|
|
168
|
+
back. `stalled` directs the operator to the jobs runner/cleanup channel. Poll
|
|
169
|
+
failures and exhausted budgets say progress unknown and offer explicit observation
|
|
170
|
+
refresh. A duplicate apply receipt follows its existing batch. Stale/expired plans
|
|
171
|
+
require another review.
|
|
172
|
+
|
|
173
|
+
A lost apply reply retains the submitted plan ID and blocks new mutations, even
|
|
174
|
+
when no batch ID was acknowledged. Closing, refreshing inventory, signing in
|
|
175
|
+
again as the same actor, and selecting a mock scenario do not clear this block.
|
|
176
|
+
Inspect capacity server logs and AWS state, obtain the exact plan's batch ID, and
|
|
177
|
+
enter it for read-only observation. Only matching terminal evidence resolves the
|
|
178
|
+
block; an unrelated batch is refused. Ambiguous provider outcomes remain unknown.
|
|
179
|
+
|
|
180
|
+
## Mock and executable verification
|
|
181
|
+
|
|
182
|
+
`client/operational-fleet-mock.ts` is mock-only and exports:
|
|
183
|
+
|
|
184
|
+
- `handleOperationalFleetMock(path, method, body, params, actor, authTime)` → an
|
|
185
|
+
envelope, `undefined` for unowned routes, or an intentional lost-response error.
|
|
186
|
+
The central mock supplies its validated actor/global grants and bearer auth time;
|
|
187
|
+
optional `actor.credential_kind` identifies a confirmed confined credential.
|
|
188
|
+
- `mockOperationalFleetScenarios`, `setMockOperationalFleetScenario`,
|
|
189
|
+
`getMockOperationalFleetScenario`, and read-only `getMockOperationalFleetBatchIds`.
|
|
190
|
+
|
|
191
|
+
The default fixture includes asymmetric reader classes. Scenarios cover external,
|
|
192
|
+
restricted, partial, transitioning/drained nodes, missing evidence, unknown prices,
|
|
193
|
+
stale/expired/duplicate plans, partial failures, stalled progress and lost replies.
|
|
194
|
+
Changing scenario resets the simulated server, not the browser operation record.
|
|
195
|
+
|
|
196
|
+
Run `npm run verify:admin-fleet-workspace` for standalone compiler and mounted coverage, plus `node scripts/verify-admin-operational-fleet.mjs` and
|
|
197
|
+
`node scripts/verify-admin-operational-fleet-mounted.mjs`. The mounted verifier uses
|
|
198
|
+
an isolated injected transport and rejects every real host. It exercises actual
|
|
199
|
+
React components in StrictMode, custom embedded mounts, denied request suppression,
|
|
200
|
+
cancellation, stale responses, single-flight, fresh-auth without replay, cross-page
|
|
201
|
+
progress and unknown-outcome reconciliation. Browser light/dark, narrow layout,
|
|
202
|
+
native focus and console proof belong to the integrated closing run.
|
|
203
|
+
|
|
204
|
+
### KISS presentation
|
|
205
|
+
|
|
206
|
+
The Dashboard overview uses its existing compact service/status rows and modal Details. The separate Fleet workspace uses compact evidence cards and info popovers. Both editors retain a single draft across App nodes, Database and Redis tabs; the standalone editor enters review only through Review changes and discards consent on Back. All staged changes appear in one exact server-plan review. See [visual QA](admin-presentation.md).
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Admin presentation and visual QA
|
|
2
|
+
|
|
3
|
+
Use intuitive, simple screens with clean spacing. Keep only important data and
|
|
4
|
+
short action-oriented copy on the primary surface. Use tabs, modals and help
|
|
5
|
+
popovers only when they improve the task. Tabs separate
|
|
6
|
+
distinct jobs; do not split a few related fields across tiny panels or render
|
|
7
|
+
a one-item tab strip. Use focused modals for substantial inspection/confirmation
|
|
8
|
+
and keyboard-accessible info popovers for secondary explanations. Keep navigation
|
|
9
|
+
directly discoverable rather than hiding destination links inside help. On pages
|
|
10
|
+
that already scroll, use modals/popovers rather
|
|
11
|
+
than collapsible detail sections. Compact disclosures such as Maintenance are
|
|
12
|
+
fine; this is contextual. Preserve Admin Dashboard as-is unless Ian explicitly
|
|
13
|
+
requests a change; separate Fleet work must not alter it. Keep action-specific errors, unknown outcomes and concrete
|
|
14
|
+
interruptions visible where the operator needs them. Permission/consent/session
|
|
15
|
+
and no-replay checks are behavioral requirements, not prose to remove.
|
|
16
|
+
|
|
17
|
+
Both applications import `portal-mojo/styles.css`. Never add app-local copies of
|
|
18
|
+
package component CSS: unlayered stale copies override the canonical layer.
|
|
19
|
+
Showcase owns only tokens, chrome and demo-only styling. Test fixture controls
|
|
20
|
+
are demo-only, separate from the product's UI.
|
|
21
|
+
|
|
22
|
+
## Required acceptance
|
|
23
|
+
|
|
24
|
+
1. Run `npm run verify:admin-presentation`. It compiles each app's real theme
|
|
25
|
+
through Vite and checks the six operations layouts, plus the shared style
|
|
26
|
+
entrypoint. A CSS file existing on disk does not prove it is loaded.
|
|
27
|
+
2. Wait for actual loaded data and controls, not just a heading, spinner or
|
|
28
|
+
skeleton. Inspect initial-viewport screenshots of **all six** screens
|
|
29
|
+
(GeoLocation, Fleet, Maintenance, Deployments, Domains, Serving) in light and
|
|
30
|
+
dark at desktop and 390px. Revisit each image; producing one is not review.
|
|
31
|
+
3. Check computed page/row display, padding/gap and heading size. Check field
|
|
32
|
+
separation, alignment, readable contrast, wrapping and no page overflow.
|
|
33
|
+
Tables may scroll inside their own container. Inspect internal scroll areas
|
|
34
|
+
and sticky actions, not just document width.
|
|
35
|
+
4. Open help, tabs, details and dialogs. Verify popovers inside a native dialog,
|
|
36
|
+
Escape/outside dismissal, readable fields and reachable actions at narrow
|
|
37
|
+
width. Inspect every changed surface, including errors and unknown outcomes.
|
|
38
|
+
5. Exercise mock workflows: provider test/save, a combined scaling draft retained
|
|
39
|
+
across tabs and exact plan review, maintenance outage/resource confirmation,
|
|
40
|
+
API/WebApp tabs and recovery/setup, Domain actions/details, Serving wizard.
|
|
41
|
+
Cancel billable/destructive actions unless a test explicitly owns the mock.
|
|
42
|
+
6. Repeat a smoke check in the actual Admin shell and built Showcase output.
|
|
43
|
+
Check the browser console and run focused behavior contracts plus typecheck.
|
|
44
|
+
DOM-only tests verify behavior; they cannot certify layout or visual quality.
|
|
45
|
+
At mobile width, verify navigation starts collapsed, expands over the page,
|
|
46
|
+
closes with Escape/outside activation or navigation, and preserves the saved
|
|
47
|
+
desktop preference when returning to a wider viewport.
|
|
48
|
+
|
|
49
|
+
Keep screenshot evidence and the screen/theme/viewport/interaction results on
|
|
50
|
+
the Maestro item. State whether evidence is mock or live. A preview link must
|
|
51
|
+
work when handed over; the development server's lifetime is part of that check.
|
package/docs/admin-signin.md
CHANGED
|
@@ -12,9 +12,11 @@ The page has two parts:
|
|
|
12
12
|
layout/appearance/accent color, hero panel, sign-in heading/copy/methods,
|
|
13
13
|
registration, custom CSS. It edits the same keys a group admin edits in the
|
|
14
14
|
group **Configure Auth** dialog; a group's own settings still override these.
|
|
15
|
-
- **Providers** — one card
|
|
15
|
+
- **Providers** — one card per provider the server lists (Google, Apple,
|
|
16
|
+
GitHub and, from django-mojo's Microsoft sign-in, Microsoft): an Enabled
|
|
16
17
|
switch, a read-only callback URL with a Copy button, the credential fields,
|
|
17
|
-
a Ready / Needs setup badge, and a link to the
|
|
18
|
+
a Ready / Needs setup badge, any server notices, and a link to the
|
|
19
|
+
provider's console.
|
|
18
20
|
|
|
19
21
|
KISS by design: trusted admins, no step-up auth, no confirmation beyond a
|
|
20
22
|
browser `confirm()` before clearing a stored value.
|
|
@@ -38,6 +40,14 @@ One endpoint, both methods, django-mojo envelope.
|
|
|
38
40
|
multiline, configured, source, value, hint}`. `source` is `admin`,
|
|
39
41
|
`deployment` (shown as "Set in server config") or `none`. Secret fields
|
|
40
42
|
never carry `value`; `hint` (e.g. `…a1b2`) is shown when present.
|
|
43
|
+
- Optional `notices[]` on a provider: `{tone, text}`, `tone` one of `info`,
|
|
44
|
+
`warning` or `danger` (for example a Microsoft client secret nearing or past
|
|
45
|
+
its recorded expiry). Each renders as its own `role="status"` note under
|
|
46
|
+
the Needs setup note, in order; any other tone renders as `info`. An absent
|
|
47
|
+
or empty list renders nothing, so older backends are unaffected.
|
|
48
|
+
- Provider `name` tokens with a built-in label and icon: `google`, `apple`,
|
|
49
|
+
`github`, `microsoft` (`bi-microsoft`). Any other name falls back to the
|
|
50
|
+
server's `label` and a key icon.
|
|
41
51
|
|
|
42
52
|
`POST /api/account/admin/signin` returns the same full payload, which the page
|
|
43
53
|
writes straight into its query cache (`SIGNIN_QUERY_KEY`).
|