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
|
@@ -1 +1,125 @@
|
|
|
1
|
-
.edge-
|
|
1
|
+
.edge-form-grid { display: grid; gap: 14px; }
|
|
2
|
+
.edge-server-name { display: grid; gap: 3px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 8px; background: var(--surface2); }
|
|
3
|
+
.edge-server-name span, .edge-review dt { font-size: 11px; color: var(--mute); text-transform: uppercase; letter-spacing: .06em; }
|
|
4
|
+
.edge-server-name code { font-size: 15px; overflow-wrap: anywhere; }
|
|
5
|
+
.edge-path-list, .edge-route-list { display: grid; gap: 8px; }
|
|
6
|
+
.edge-path-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; align-items: center; }
|
|
7
|
+
.edge-route-row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr) auto; gap: 8px; align-items: center; }
|
|
8
|
+
.edge-warning { display: flex; gap: 8px; align-items: baseline; padding: 10px 12px; border: 1px solid var(--warn); border-radius: 8px; color: var(--ink); background: var(--surface2); }
|
|
9
|
+
.edge-warning i { color: var(--warn); }
|
|
10
|
+
.edge-note { display: grid; gap: 3px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 8px; background: var(--surface2); }
|
|
11
|
+
.edge-note span { color: var(--mute); font-size: 13px; }
|
|
12
|
+
.edge-review { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 8px 16px; margin: 0; }
|
|
13
|
+
.edge-review dd { margin: 0; overflow-wrap: anywhere; }
|
|
14
|
+
.edge-routes { display: grid; gap: 10px; }
|
|
15
|
+
.edge-route-actions, .edge-row-actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
|
|
16
|
+
.edge-blocklist-editor .form-grid, .edge-upstream-dialog .form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
17
|
+
.edge-blocklist-editor .edge-mode-field, .edge-upstream-dialog .form-grid > .collection-select { grid-column: 1/-1; }
|
|
18
|
+
.edge-mode-control { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
19
|
+
.edge-mode-option { display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border: 1px solid var(--line); border-radius: 999px; cursor: pointer; }
|
|
20
|
+
.edge-mode-option.is-selected { border-color: var(--accent); background: var(--accent-soft); }
|
|
21
|
+
.edge-mode-option:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
22
|
+
.edge-mode-option input { position: absolute; opacity: 0; pointer-events: none; }
|
|
23
|
+
@media (max-width: 700px) {
|
|
24
|
+
.edge-blocklist-editor .form-grid, .edge-upstream-dialog .form-grid { grid-template-columns: 1fr; }
|
|
25
|
+
.edge-route-row { grid-template-columns: minmax(0, 1fr) auto; }
|
|
26
|
+
.edge-route-row > :first-child { grid-column: 1/-1; }
|
|
27
|
+
.edge-review { grid-template-columns: 1fr; gap: 2px 0; }
|
|
28
|
+
.edge-review dd { margin-bottom: 8px; }
|
|
29
|
+
}
|
|
30
|
+
.edge-serving-page { display: grid; grid-template-columns: minmax(0, 1fr); gap: 24px; min-width: 0; }
|
|
31
|
+
.edge-serving-page .page-header h1, .edge-serving-page .page-header h2 { font-size: 26px; font-weight: 650; letter-spacing: -.025em; line-height: 1.2; }
|
|
32
|
+
.edge-serving-heading { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
|
|
33
|
+
.edge-serving-evidence p { margin: 8px 0; overflow-wrap: anywhere; }
|
|
34
|
+
.edge-serving-check { padding: 12px 0; border-top: 1px solid var(--line); overflow-wrap: anywhere; }
|
|
35
|
+
@media (max-width: 700px) {
|
|
36
|
+
.edge-serving-heading { align-items: flex-start; }
|
|
37
|
+
.edge-serving-page .page-header h1, .edge-serving-page .page-header h2 { font-size: 23px; }
|
|
38
|
+
}
|
|
39
|
+
.edge-serving-page > * { min-width: 0; }
|
|
40
|
+
.edge-vhost-wizard > .modal-title { flex-shrink: 0; margin-bottom: 16px; }
|
|
41
|
+
/* Serving task surfaces are deliberately scoped; shared DetailView is unchanged. */
|
|
42
|
+
.edge-vhost-wizard { display: flex; flex-direction: column; padding: 24px; max-height: calc(100dvh - 32px); }
|
|
43
|
+
.edge-vhost-editor { display: flex; flex-direction: column; min-height: 0; gap: 16px; }
|
|
44
|
+
.edge-vhost-editor > .mojo-tabs { display: flex; flex-direction: column; min-height: 0; }
|
|
45
|
+
.edge-vhost-editor .mojo-tab-panels, .edge-vhost-editor .mojo-tab-panel { min-height: 0; }
|
|
46
|
+
.edge-editor-panel { overflow: auto; min-height: 0; max-height: calc(100dvh - 260px); padding: 18px 2px 4px; }
|
|
47
|
+
.edge-vhost-editor .mojo-tabs { overflow: visible; }
|
|
48
|
+
.edge-editor-actions { flex-shrink: 0; margin-top: 0; padding-top: 16px; border-top: 1px solid var(--line); background: var(--surface); gap: 8px; flex-wrap: wrap; }
|
|
49
|
+
.edge-vhost-wizard .edge-form-grid { gap: 20px; }
|
|
50
|
+
.edge-kind-picker { border: 0; padding: 0; margin: 0; min-width: 0; }
|
|
51
|
+
.edge-kind-picker legend { margin-bottom: 10px; }
|
|
52
|
+
.edge-kind-options { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
|
|
53
|
+
.edge-kind-option { display: flex; align-items: center; gap: 8px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 8px; cursor: pointer; font-size: 14px; }
|
|
54
|
+
.edge-kind-option.is-selected { border-color: var(--accent); background: var(--accent-soft); }
|
|
55
|
+
.edge-kind-option input { margin: 0; accent-color: var(--accent); }
|
|
56
|
+
.edge-kind-option:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
57
|
+
.edge-kind-option i { color: var(--accent); }
|
|
58
|
+
.edge-create-progress { display: flex; list-style: none; padding: 0; margin: 0; gap: 16px; flex-wrap: wrap; font-size: 13px; color: var(--mute); }
|
|
59
|
+
.edge-create-progress li { display: flex; align-items: center; gap: 6px; }
|
|
60
|
+
.edge-create-progress li > span { display: grid; place-items: center; width: 22px; height: 22px; border: 1px solid var(--line); border-radius: 50%; font-size: 12px; }
|
|
61
|
+
.edge-create-progress li[aria-current="step"] { color: var(--accent); font-weight: 600; }
|
|
62
|
+
.edge-create-progress li[aria-current="step"] > span { background: var(--accent-soft); border-color: var(--accent); }
|
|
63
|
+
.edge-help { display: inline-flex; vertical-align: middle; }
|
|
64
|
+
.edge-help > .btn-icon { width: 26px; height: 26px; min-width: 26px; color: var(--mute); }
|
|
65
|
+
.edge-help-popover { width: min(320px, calc(100vw - 32px)); max-width: calc(100vw - 32px); padding: 14px 16px; font-size: 13px; line-height: 1.5; white-space: normal; overflow-wrap: anywhere; }
|
|
66
|
+
.edge-help-popover p { margin: 0; }
|
|
67
|
+
.edge-hostname-detail { padding: 24px; display: flex; flex-direction: column; min-height: 0; max-height: calc(100dvh - 32px); }
|
|
68
|
+
.edge-detail-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; padding-bottom: 20px; }
|
|
69
|
+
.edge-detail-identity { min-width: 0; }
|
|
70
|
+
.edge-detail-identity .modal-title { margin: 0 0 8px; overflow-wrap: anywhere; }
|
|
71
|
+
.edge-detail-subtitle { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; color: var(--mute); font-size: 14px; }
|
|
72
|
+
.edge-detail-actions { display: flex; flex-shrink: 0; align-items: center; gap: 8px; }
|
|
73
|
+
.edge-enabled-switch { display: flex; gap: 6px; align-items: center; font-size: 13px; color: var(--mute); }
|
|
74
|
+
.edge-enabled-switch input { appearance: none; width: 34px; height: 20px; border-radius: 12px; border: 1px solid var(--line); background: var(--surface2); cursor: pointer; position: relative; }
|
|
75
|
+
.edge-enabled-switch input:before { content: ''; position: absolute; width: 14px; height: 14px; left: 2px; top: 2px; border-radius: 50%; background: var(--mute); }
|
|
76
|
+
.edge-enabled-switch input:checked { background: var(--accent); border-color: var(--accent); }
|
|
77
|
+
.edge-enabled-switch input:checked:before { left: 16px; background: var(--surface); }
|
|
78
|
+
.edge-enabled-switch input:disabled { opacity: .55; cursor: default; }
|
|
79
|
+
.edge-enabled-switch input:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
|
|
80
|
+
.edge-hostname-detail > .mojo-tabs { min-height: 0; overflow: auto; }
|
|
81
|
+
.edge-detail-panel { padding: 16px 2px 4px; min-height: 0; overflow-wrap: anywhere; }
|
|
82
|
+
.edge-detail-panel > p { margin: 16px 0; }
|
|
83
|
+
.edge-detail-panel .flat-row { min-width: 0; }
|
|
84
|
+
.edge-detail-panel .flat-row code { overflow-wrap: anywhere; }
|
|
85
|
+
.edge-detail-panel > div:last-child > .btn { margin-top: 16px; }
|
|
86
|
+
.edge-hostname-detail .form-alert { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-bottom: 16px; }
|
|
87
|
+
.edge-action-menu { padding: 8px; }
|
|
88
|
+
.edge-route-dialog .edge-form-grid { margin-top: 20px; }
|
|
89
|
+
.edge-check-summary { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
|
|
90
|
+
.edge-check-status { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
|
|
91
|
+
.edge-check-status > .bi { color: var(--accent); }
|
|
92
|
+
.edge-serving-evidence { min-width: 0; margin-top: 12px; display: grid; gap: 4px; font-size: 13px; }
|
|
93
|
+
.edge-serving-evidence > small { font-size: 12px; }
|
|
94
|
+
.edge-check-dialog { max-height: calc(100dvh - 32px); display: flex; flex-direction: column; }
|
|
95
|
+
.edge-check-body { overflow: auto; min-height: 0; }
|
|
96
|
+
.edge-check-dialog .modal-actions { flex-shrink: 0; }
|
|
97
|
+
.edge-domain-filter { width: min(320px, 100%); }
|
|
98
|
+
.edge-domain-filter .field-label { font-size: 13px; }
|
|
99
|
+
.edge-settings-button { justify-self: start; }
|
|
100
|
+
@media (max-width: 700px) {
|
|
101
|
+
.edge-vhost-wizard, .edge-hostname-detail { padding: 20px 16px; }
|
|
102
|
+
.edge-detail-header { flex-wrap: wrap; gap: 12px; }
|
|
103
|
+
.edge-detail-actions { width: 100%; justify-content: flex-end; }
|
|
104
|
+
.edge-detail-actions > .edge-enabled-switch { margin-right: auto; }
|
|
105
|
+
.edge-create-progress { gap: 8px 12px; font-size: 12px; }
|
|
106
|
+
.edge-create-progress li > span { width: 20px; height: 20px; }
|
|
107
|
+
.edge-editor-panel { max-height: calc(100dvh - 285px); }
|
|
108
|
+
.edge-route-row > .collection-select { min-width: 0; }
|
|
109
|
+
.edge-check-summary { align-items: flex-start; }
|
|
110
|
+
.edge-serving-evidence { width: 100%; }
|
|
111
|
+
}
|
|
112
|
+
@media (max-width: 700px) {
|
|
113
|
+
.edge-vhost-editor .mojo-tab, .edge-hostname-detail .mojo-tab { font-size: 13px; padding-left: 8px; padding-right: 8px; }
|
|
114
|
+
}
|
|
115
|
+
.edge-vhost-editor .edge-route-row { align-items: end; }
|
|
116
|
+
.edge-hostname-detail .edge-route-actions .btn { white-space: nowrap; }
|
|
117
|
+
|
|
118
|
+
.edge-serving-heading.page-header { align-items: flex-start; }
|
|
119
|
+
.edge-serving-heading.page-header > div { min-width: 0; }
|
|
120
|
+
.edge-serving-evidence .edge-row-actions { align-items: center; gap: 6px; }
|
|
121
|
+
.edge-serving-evidence .btn-compact { font-size: 12px; padding: 4px 8px; }
|
|
122
|
+
.edge-serving-evidence .btn-icon { width: 28px; height: 28px; }
|
|
123
|
+
|
|
124
|
+
.edge-certificate-summary { display: grid; gap: 8px; min-width: 0; }
|
|
125
|
+
.edge-certificate-summary > .btn { justify-self: start; }
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
.geo-admin { display: grid; max-width: 880px; margin-inline: auto; gap: 20px; min-width: 0; overflow-wrap: anywhere; container-type: inline-size; }
|
|
2
|
+
.geo-admin .page-header { display: flex; justify-content: space-between; margin: 0; align-items: start; flex-wrap: wrap; gap: 12px; }
|
|
3
|
+
.geo-admin h1 { font-size: 26px; font-weight: 750; line-height: 1.2; letter-spacing: -.025em; color: var(--ink-strong); margin: 4px 0 8px; }
|
|
4
|
+
.geo-admin h2 { font-size: 16px; font-weight: 700; line-height: 1.35; color: var(--ink-strong); margin: 0; }
|
|
5
|
+
.geo-admin-setup, .geo-admin-status { min-width: 0; }
|
|
6
|
+
.geo-admin-form { padding: 24px; }
|
|
7
|
+
.geo-admin-provider-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; }
|
|
8
|
+
.geo-admin-fields { border: 0; padding: 0; margin: 0; min-width: 0; display: grid; gap: 22px; }
|
|
9
|
+
.geo-admin .field { display: grid; gap: 8px; min-width: 0; }
|
|
10
|
+
.geo-admin .field-label, .geo-admin-key-heading, .geo-admin-sharing { display: flex; gap: 8px; align-items: center; }
|
|
11
|
+
.geo-admin .input { width: 100%; box-sizing: border-box; min-width: 0; }
|
|
12
|
+
.geo-admin [hidden] { display: none !important; }
|
|
13
|
+
.geo-admin-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
|
|
14
|
+
.geo-admin-actions .btn { white-space: normal; }
|
|
15
|
+
.geo-admin-key { display: grid; gap: 12px; padding: 16px; background: var(--surface2); border: 1px solid var(--line); border-radius: 8px; min-width: 0; }
|
|
16
|
+
.geo-admin-key p, .geo-admin-result p, .geo-admin-status p, .geo-admin-notice p { margin: 0; }
|
|
17
|
+
.geo-admin-provider-list { padding: 0; margin: 0; list-style: none; display: grid; gap: 8px; }
|
|
18
|
+
.geo-admin-provider-list li { display: flex; justify-content: space-between; align-items: center; gap: 8px; border: 1px solid var(--line); border-radius: 6px; padding: 8px 10px; }
|
|
19
|
+
.geo-admin-provider-list small { display: block; }
|
|
20
|
+
.geo-admin-provider-list .btn { padding: 5px 8px; }
|
|
21
|
+
.geo-admin-context, .geo-admin-result { margin: 0 24px 20px; }
|
|
22
|
+
.geo-admin-result { display: grid; gap: 8px; }
|
|
23
|
+
.geo-admin-footer { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; padding: 16px 24px; border-top: 1px solid var(--line); }
|
|
24
|
+
.geo-admin-status { padding: 18px 24px; display: grid; gap: 10px; }
|
|
25
|
+
.geo-admin-status-heading, .geo-admin-activation { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px; }
|
|
26
|
+
.geo-admin-status-heading .btn { font-size: 12px; padding: 5px 8px; }
|
|
27
|
+
.geo-admin-notice { border: 1px solid var(--line); background: var(--accent-soft); border-radius: 8px; padding: 12px; margin: 0; display: grid; gap: 6px; }
|
|
28
|
+
.geo-admin-dialog dl { display: grid; gap: 14px; }
|
|
29
|
+
.geo-admin-dialog dt { color: var(--mute); font-size: 12px; margin-bottom: 4px; }
|
|
30
|
+
.geo-admin-dialog dd { margin: 0; overflow-wrap: anywhere; }
|
|
31
|
+
@container (max-width: 420px) {
|
|
32
|
+
.geo-admin-provider-fields { grid-template-columns: 1fr; }
|
|
33
|
+
.geo-admin-form, .geo-admin-status { padding: 18px; }
|
|
34
|
+
.geo-admin-key { padding: 12px; }
|
|
35
|
+
.geo-admin-provider-list li { flex-wrap: wrap; }
|
|
36
|
+
.geo-admin-actions { gap: 6px; }
|
|
37
|
+
.geo-admin-footer { padding: 16px 18px; }
|
|
38
|
+
.geo-admin-context, .geo-admin-result { margin-inline: 18px; }
|
|
39
|
+
.geo-admin-sharing { align-items: start; }
|
|
40
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
.admin-maintenance {
|
|
2
|
+
display: grid;
|
|
3
|
+
gap: 1.25rem;
|
|
4
|
+
max-width: 80rem;
|
|
5
|
+
margin: auto;
|
|
6
|
+
padding: 0;
|
|
7
|
+
overflow-wrap: anywhere;
|
|
8
|
+
}
|
|
9
|
+
.admin-maintenance header,
|
|
10
|
+
.maintenance-resource {
|
|
11
|
+
display: flex;
|
|
12
|
+
align-items: flex-start;
|
|
13
|
+
justify-content: space-between;
|
|
14
|
+
gap: 1rem;
|
|
15
|
+
}
|
|
16
|
+
.admin-maintenance section {
|
|
17
|
+
background: var(--surface);
|
|
18
|
+
border: 1px solid var(--line);
|
|
19
|
+
border-radius: var(--radius-lg, 0.75rem);
|
|
20
|
+
padding: 1.25rem;
|
|
21
|
+
min-width: 0;
|
|
22
|
+
}
|
|
23
|
+
.admin-maintenance h1,
|
|
24
|
+
.admin-maintenance h2,
|
|
25
|
+
.admin-maintenance h3 {
|
|
26
|
+
margin: 0 0 0.5rem;
|
|
27
|
+
}
|
|
28
|
+
.maintenance-resource {
|
|
29
|
+
padding: 1rem 0;
|
|
30
|
+
border-bottom: 1px solid var(--line);
|
|
31
|
+
}
|
|
32
|
+
.maintenance-resource:last-child {
|
|
33
|
+
border-bottom: 0;
|
|
34
|
+
}
|
|
35
|
+
.admin-maintenance p {
|
|
36
|
+
margin: 0.5rem 0;
|
|
37
|
+
}
|
|
38
|
+
.admin-maintenance dl {
|
|
39
|
+
display: grid;
|
|
40
|
+
grid-template-columns: minmax(7rem, auto) 1fr;
|
|
41
|
+
gap: 0.5rem 1rem;
|
|
42
|
+
}
|
|
43
|
+
.admin-maintenance dd {
|
|
44
|
+
margin: 0;
|
|
45
|
+
}
|
|
46
|
+
.maintenance-warning {
|
|
47
|
+
color: var(--warn);
|
|
48
|
+
}
|
|
49
|
+
.maintenance-mode {
|
|
50
|
+
color: var(--mute);
|
|
51
|
+
}
|
|
52
|
+
.maintenance-dialog {
|
|
53
|
+
color: var(--ink);
|
|
54
|
+
background: var(--surface);
|
|
55
|
+
border: 1px solid var(--line);
|
|
56
|
+
border-radius: var(--radius-lg, 0.75rem);
|
|
57
|
+
max-width: min(38rem, calc(100vw - 2rem));
|
|
58
|
+
max-height: calc(100vh - 2rem);
|
|
59
|
+
overflow: auto;
|
|
60
|
+
}
|
|
61
|
+
.maintenance-dialog::backdrop {
|
|
62
|
+
background: rgb(0 0 0 / 0.6);
|
|
63
|
+
}
|
|
64
|
+
.maintenance-dialog-body {
|
|
65
|
+
padding: 1.25rem;
|
|
66
|
+
display: grid;
|
|
67
|
+
gap: 1rem;
|
|
68
|
+
}
|
|
69
|
+
.maintenance-dialog h2,
|
|
70
|
+
.maintenance-dialog p {
|
|
71
|
+
margin: 0;
|
|
72
|
+
}
|
|
73
|
+
.maintenance-dialog fieldset {
|
|
74
|
+
display: grid;
|
|
75
|
+
gap: 0.75rem;
|
|
76
|
+
}
|
|
77
|
+
.maintenance-confirm-label {
|
|
78
|
+
display: grid;
|
|
79
|
+
gap: 0.5rem;
|
|
80
|
+
}
|
|
81
|
+
.maintenance-confirm-label input {
|
|
82
|
+
width: 100%;
|
|
83
|
+
min-width: 0;
|
|
84
|
+
background: var(--field-bg, var(--surface));
|
|
85
|
+
color: var(--ink);
|
|
86
|
+
border: 1px solid var(--line);
|
|
87
|
+
padding: 0.65rem;
|
|
88
|
+
border-radius: 0.35rem;
|
|
89
|
+
}
|
|
90
|
+
.maintenance-actions {
|
|
91
|
+
display: flex;
|
|
92
|
+
justify-content: flex-end;
|
|
93
|
+
gap: 0.75rem;
|
|
94
|
+
}
|
|
95
|
+
@media (max-width: 600px) {
|
|
96
|
+
.admin-maintenance {
|
|
97
|
+
padding: 0;
|
|
98
|
+
}
|
|
99
|
+
.admin-maintenance header,
|
|
100
|
+
.maintenance-resource {
|
|
101
|
+
flex-direction: column;
|
|
102
|
+
}
|
|
103
|
+
.admin-maintenance section {
|
|
104
|
+
padding: 0.8rem;
|
|
105
|
+
}
|
|
106
|
+
.maintenance-actions {
|
|
107
|
+
flex-wrap: wrap;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.admin-maintenance h1{font-size:26px;font-weight:750;line-height:1.2;letter-spacing:-.025em;color:var(--ink-strong)}.admin-maintenance h2,.maintenance-dialog h2{font-size:18px;font-weight:700;line-height:1.35;color:var(--ink-strong)}.admin-maintenance h3{font-size:16px;font-weight:650;line-height:1.4;color:var(--ink-strong)}
|
|
112
|
+
|
|
113
|
+
.maintenance-resource>div{min-width:0}.maintenance-resource>button{flex-shrink:0}.maintenance-resource-status{color:var(--mute)}.maintenance-details{margin-block:.65rem}.maintenance-details>summary{font-size:13px;font-weight:600;cursor:pointer;color:var(--mute)}.maintenance-details[open]>summary{margin-bottom:.65rem}.admin-maintenance .maintenance-framework-summary{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1rem}.maintenance-framework-summary>div{min-width:0}.maintenance-framework-summary dt{font-size:12px;color:var(--mute);margin-bottom:4px}.maintenance-framework-summary dd{font-size:16px;font-weight:600;overflow-wrap:anywhere}.admin-maintenance .maintenance-resource h3{margin-bottom:.25rem}.admin-maintenance .maintenance-resource p{margin:.25rem 0}.admin-maintenance .maintenance-details p{margin:.5rem 0}@media(max-width:600px){.admin-maintenance .maintenance-framework-summary{grid-template-columns:1fr}.maintenance-resource>button{align-self:flex-start}}
|
|
114
|
+
|
|
115
|
+
.admin-maintenance { gap: 24px; }
|
|
116
|
+
.admin-maintenance header > div > p:last-child { color: var(--mute); }
|
|
117
|
+
.admin-maintenance section.maintenance-scan { padding: 0; background: transparent; border: 0; }
|
|
118
|
+
.maintenance-scan .ops-details > summary { padding: 0; }
|
|
119
|
+
.maintenance-dialog { margin: auto; padding: 0; width: min(38rem, calc(100vw - 2rem)); }
|
|
120
|
+
.maintenance-dialog fieldset { border: 1px solid var(--line); border-radius: 8px; padding: 12px 16px; }
|
|
121
|
+
.maintenance-dialog legend { padding-inline: 4px; font-weight: 600; }
|
|
122
|
+
.maintenance-dialog-body { padding: 24px; gap: 20px; }
|
|
123
|
+
|
|
124
|
+
.maintenance-dialog input[type="radio"] { margin-right: 6px; }
|
|
125
|
+
|
|
126
|
+
/* Maintenance-only dialogs and compact progress. No shared Dashboard rules. */
|
|
127
|
+
.maintenance-dialog-body{max-height:calc(100dvh - 2rem);display:flex;flex-direction:column;overflow:hidden;box-sizing:border-box}.maintenance-dialog-scroll{min-height:0;overflow:auto;display:grid;gap:16px;padding:2px}.maintenance-dialog .maintenance-actions{flex-shrink:0;padding-top:12px;align-items:center}.maintenance-dialog .maintenance-progress-facts{display:grid;grid-template-columns:auto minmax(0,1fr);gap:8px 16px;margin:0}.maintenance-progress-facts dt{color:var(--mute)}.maintenance-progress-facts dd{margin:0;overflow-wrap:anywhere}.maintenance-attempt-row{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:12px 0;border-bottom:1px solid var(--line)}.maintenance-attempt-row:last-of-type{border-bottom:0}.admin-maintenance .maintenance-actions{justify-content:flex-start;margin-top:16px;flex-wrap:wrap}.maintenance-dialog .maintenance-dialog-scroll>p{margin:0}.maintenance-dialog .maintenance-dialog-scroll fieldset{margin:0}.maintenance-dialog .maintenance-dialog-scroll .field{margin:0}.maintenance-attempt-row>div{min-width:0}@media(max-width:600px){.maintenance-dialog-body{padding:20px;gap:16px}.maintenance-attempt-row{align-items:flex-start;flex-direction:column}.maintenance-dialog .maintenance-actions{gap:8px}.maintenance-dialog .maintenance-actions .btn{max-width:100%;white-space:normal}}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
.operational-fleet{display:grid;gap:16px;min-width:0;container-type:inline-size;overflow-wrap:anywhere}.fleet-heading,.fleet-buttons{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.fleet-heading h2{margin:0}.fleet-heading p{margin:4px 0 0}.fleet-evidence-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}.fleet-evidence{min-width:0;overflow:hidden}.fleet-evidence h3{padding:14px 16px;margin:0;border-bottom:1px solid var(--line)}.fleet-evidence-row{display:grid;gap:6px;padding:12px 16px;border-bottom:1px solid var(--line);min-width:0}.fleet-evidence-row:last-child{border-bottom:0}.fleet-evidence-row>div:first-child{display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:wrap}.fleet-evidence-row p{margin:2px 0 5px}.fleet-source-status{font-size:11px;letter-spacing:.03em;text-transform:uppercase;color:var(--mute)}.fleet-status-healthy{color:var(--ok)}.fleet-status-unhealthy{color:var(--bad)}.fleet-status-degraded,.fleet-status-stale{color:var(--warn)}.fleet-availability{border-left:3px solid var(--mute)}.fleet-availability-ok{border-left-color:var(--ok)}.fleet-availability-down{border-left-color:var(--bad)}.fleet-capacity-facts summary{cursor:pointer;font-weight:600}.fleet-fact-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:20px}.fleet-member{display:block;margin:4px 0;color:var(--mute)}.fleet-scale{display:flex;flex-direction:column;max-height:calc(100dvh - 80px);min-height:0;overflow-wrap:anywhere}.fleet-scale-body{overflow:auto;min-height:0;padding-right:4px}.fleet-scale h3{margin:20px 0 8px}.fleet-scale-fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.fleet-scale-fields .field{min-width:0}.fleet-node{display:flex;gap:12px;justify-content:space-between;align-items:center;padding:10px 0;border-bottom:1px solid var(--line)}.fleet-node small{display:block}.fleet-plan-steps{padding-left:24px}.fleet-plan-steps li{margin-bottom:14px}.fleet-progress-step{padding:10px 0;border-bottom:1px solid var(--line)}.fleet-scale .modal-actions{flex-shrink:0}.fleet-scale fieldset{border:0;margin:0;padding:0;min-width:0}@container (max-width:850px){.fleet-evidence-grid{grid-template-columns:1fr}.fleet-fact-grid{grid-template-columns:1fr}}@media(max-width:560px){.fleet-scale-fields{grid-template-columns:1fr}.fleet-node{align-items:flex-start;flex-direction:column}.fleet-scale{max-height:calc(100dvh - 48px)}}
|
|
2
|
+
|
|
3
|
+
.fleet-page>.page-header{display:flex;justify-content:space-between;align-items:start;margin-bottom:18px}.fleet-page h1{font-size:26px;font-weight:750;line-height:1.2;letter-spacing:-.025em;color:var(--ink-strong);margin:0}.fleet-heading h2{font-size:20px;font-weight:700;line-height:1.3;color:var(--ink-strong)}.fleet-evidence h3{font-size:16px;font-weight:700;color:var(--ink-strong)}.fleet-availability>strong{font-size:18px;line-height:1.35;font-weight:700;color:var(--ink-strong)}.fleet-scale h3{font-size:17px;font-weight:700;color:var(--ink-strong)}.fleet-scale h4,.fleet-fact-grid h4{font-size:15px;font-weight:650;color:var(--ink-strong)}.fleet-scale .fleet-scale-disclosure{border-top:1px solid var(--line);padding:12px 0}.fleet-scale-disclosure>summary{font-size:15px;font-weight:650;cursor:pointer;color:var(--ink-strong)}.fleet-scale-disclosure[open]>summary{margin-bottom:14px}.fleet-scale fieldset>h3:first-child{margin-top:12px}.fleet-scale fieldset>p{margin-bottom:12px}.fleet-scale fieldset>.fleet-scale-fields{margin-bottom:14px}
|
|
4
|
+
|
|
5
|
+
.fleet-evidence-grid { grid-template-columns: minmax(0, 1fr); gap: 24px; }
|
|
6
|
+
.fleet-evidence { border: 0; border-radius: 0; box-shadow: none; background: transparent; }
|
|
7
|
+
.fleet-evidence h3 { padding: 0 0 10px; font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--mute); }
|
|
8
|
+
.fleet-evidence-row { grid-template-columns: minmax(130px, .7fr) minmax(0, 2fr) auto 62px; align-items: center; gap: 16px; padding: 17px 0; }
|
|
9
|
+
.fleet-row-value { min-width: 0; color: var(--mute); }
|
|
10
|
+
.fleet-detail-button { border: 0; padding: 4px 0; background: transparent; color: var(--accent); cursor: pointer; text-align: right; }
|
|
11
|
+
.fleet-source-detail > p { margin: 14px 0; }
|
|
12
|
+
.operational-fleet { gap: 24px; }
|
|
13
|
+
@container (max-width: 600px) { .fleet-evidence-row { grid-template-columns: minmax(0, 1fr) auto; gap: 6px 12px; } .fleet-row-value { grid-row: 2; } .fleet-source-status { grid-column: 2; grid-row: 1; } .fleet-detail-button { grid-column: 2; grid-row: 2; } }
|
|
14
|
+
|
|
15
|
+
.fleet-capacity-tab { padding-top: 4px; }
|
|
16
|
+
.fleet-scale-body .fleet-buttons { margin-block: 10px 18px; }
|
|
17
|
+
.fleet-scale-body > fieldset { margin-block: 12px 20px; }
|
|
18
|
+
.fleet-scale-body > section { margin-block: 16px; }
|
|
19
|
+
.fleet-scale .modal-actions { padding-top: 16px; border-top: 1px solid var(--line); }
|
|
20
|
+
.fleet-scale .input { width: 100%; min-width: 0; }
|
|
21
|
+
|
|
22
|
+
.fleet-evidence.panel { padding: 0; border: 0; border-radius: 0; box-shadow: none; background: transparent; }
|
|
23
|
+
.fleet-evidence-row { padding-block: 14px; }
|
|
24
|
+
|
|
25
|
+
.fleet-heading h2 { font-size: 26px; letter-spacing: -.025em; }
|
|
26
|
+
|
|
27
|
+
.fleet-heading h1 { margin: 0; font-size: 26px; line-height: 1.3; font-weight: 700; letter-spacing: -.025em; color: var(--ink-strong); }
|
|
28
|
+
|
|
29
|
+
.fleet-capacity-tab .panel > p { margin: 8px 0 16px; }
|
|
30
|
+
.fleet-scale-fields .field { gap: 8px; }
|
|
31
|
+
|
|
32
|
+
.fleet-capacity-dialog { display: flex; flex-direction: column; max-height: calc(100dvh - 64px); min-height: 0; overflow-wrap: anywhere; }
|
|
33
|
+
.fleet-capacity-body { overflow: auto; min-height: 0; }
|
|
34
|
+
.fleet-capacity-body p { margin: 8px 0; line-height: 1.5; }
|
|
35
|
+
.fleet-capacity-body h4 { margin: 0 0 8px; }
|
|
36
|
+
.fleet-capacity-body > .dim { margin: 0 0 18px; }
|
|
37
|
+
.fleet-capacity-dialog .modal-actions { flex: none; padding-top: 16px; border-top: 1px solid var(--line); }
|
|
38
|
+
@media (max-width: 560px) { .fleet-capacity-dialog .fleet-fact-grid { grid-template-columns: minmax(0, 1fr); } }
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
.ops-help { display: inline-flex; align-items: center; justify-content: center; padding: 3px; border: 0; background: transparent; color: var(--mute); cursor: pointer; vertical-align: middle; font-size: 14px; line-height: 1; border-radius: 4px; }
|
|
2
|
+
.ops-help:hover, .ops-help[aria-expanded="true"] { color: var(--accent); background: var(--accent-soft); }
|
|
3
|
+
.ops-help-content { width: min(340px, calc(100vw - 32px)); padding: 14px 16px; font-size: 13px; line-height: 1.6; color: var(--ink); overflow-wrap: anywhere; }
|
|
4
|
+
.ops-help-content p { margin: 0 0 8px; }
|
|
5
|
+
.ops-help-content p:last-child { margin-bottom: 0; }
|
|
6
|
+
.ops-details > summary { cursor: pointer; font-size: 13px; font-weight: 600; color: var(--mute); padding-block: 6px; }
|
|
7
|
+
.ops-details[open] > summary { margin-bottom: 10px; }
|
|
8
|
+
.ops-cell { display: grid; gap: 3px; min-width: 0; }
|
|
9
|
+
.ops-cell small { color: var(--mute); font-size: 12px; }
|
|
@@ -52,6 +52,8 @@ textarea.signin-code { resize: vertical; }
|
|
|
52
52
|
.signin-note i { flex: none; color: var(--accent); }
|
|
53
53
|
.signin-note.is-warning { border-color: color-mix(in srgb, var(--warn) 35%, var(--line)); background: var(--warn-soft); }
|
|
54
54
|
.signin-note.is-warning i { color: var(--warn); }
|
|
55
|
+
.signin-note.is-danger { border-color: color-mix(in srgb, var(--bad) 35%, var(--line)); background: var(--bad-soft); }
|
|
56
|
+
.signin-note.is-danger i { color: var(--bad); }
|
|
55
57
|
.signin-provider-actions { display: flex; justify-content: flex-end; gap: 8px; padding-top: 12px; border-top: 1px solid var(--line); }
|
|
56
58
|
|
|
57
59
|
@media (max-width: 1100px) { .signin-groups { grid-template-columns: 1fr; } }
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/* ComboBox — styles for portal-mojo <ComboBox> (packages/portal-mojo/src/ui/ComboBox.tsx).
|
|
2
2
|
Tokens only; reads correctly under data-theme="light" AND "dark".
|
|
3
|
-
|
|
4
|
-
to theme.css at merge. */
|
|
3
|
+
*/
|
|
5
4
|
|
|
6
5
|
.combo { position: relative; width: 100%; }
|
|
7
6
|
.combo-input-wrap { position: relative; }
|
|
@@ -30,6 +29,8 @@
|
|
|
30
29
|
/* Keyboard highlight (.combo-hot) and hover share one look — there is only
|
|
31
30
|
one "pointed at" state. */
|
|
32
31
|
.combo-option:hover, .combo-option.combo-hot { background: var(--surface2); color: var(--ink-strong); }
|
|
32
|
+
.combo-option[aria-disabled="true"] { opacity: .5; cursor: not-allowed; background: transparent; }
|
|
33
|
+
.combo-input[aria-invalid="true"] { border-color: var(--bad); }
|
|
33
34
|
.combo-option-main { flex: 1; min-width: 0; }
|
|
34
35
|
.combo-option-label { font-weight: 550; }
|
|
35
36
|
.combo-option-desc { font-size: 12px; color: var(--mute); margin-top: 1px; }
|
|
@@ -40,3 +41,12 @@
|
|
|
40
41
|
/* The <mark> around the matched substring — override the UA's yellow/black
|
|
41
42
|
so it stays legible on both themes. */
|
|
42
43
|
.combo-mark { background: var(--warn-soft); color: inherit; border-radius: 3px; padding: 0 1px; }
|
|
44
|
+
|
|
45
|
+
.page-size .combo { width: 78px; }
|
|
46
|
+
.combo { min-width: 0; }
|
|
47
|
+
.combo-input { width: 100%; min-width: 0; }
|
|
48
|
+
.combo-pop { max-height: min(300px, calc(100dvh - 16px)); min-width: min(260px, calc(100vw - 16px)); }
|
|
49
|
+
|
|
50
|
+
.page-size .combo-input { min-height: 30px; padding: 5px 30px 5px 9px; font-size: 12px; }
|
|
51
|
+
.combo.gran-select { width: 110px; }
|
|
52
|
+
.gran-select .combo-input { min-height: 30px; padding: 5px 30px 5px 9px; font-size: 12px; }
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/* Standalone Fleet only. Dashboard FleetOverview retains its own presentation. */
|
|
2
|
+
.fleet-page .fp-workspace{display:flex;flex-direction:column;gap:20px;min-width:0}.fleet-page .fp-header{display:flex;align-items:center;justify-content:space-between;gap:24px}.fleet-page .fp-header h1{margin:3px 0 4px}.fleet-page .fp-header p{margin:0}.fleet-page .fp-actions{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px}.fleet-page .fp-health{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:20px 24px;border-left:3px solid var(--ok)}.fleet-page .fp-health-down{border-left-color:var(--bad)}.fleet-page .fp-health-unknown{border-left-color:var(--warn)}.fleet-page .fp-health p{margin:6px 0 0}.fleet-page .fp-evidence-grid{display:grid;grid-template-columns:1fr 1fr;align-items:start;gap:0}.fleet-page .fp-section{overflow:hidden;padding:8px 18px}.fleet-page .fp-section .mojo-tab-panel{padding:4px 0}.fleet-page .fp-section .mojo-tab-list{margin:0 2px}.fleet-page .fp-section h2{font-size:14px;margin:0;padding:18px 20px;border-bottom:1px solid var(--line)}.fleet-page .fp-source{padding:14px 12px;border-bottom:1px solid var(--line);min-width:0}.fleet-page .fp-source:nth-last-child(-n+2){border-bottom:0}.fleet-page .fp-source:last-child{border-bottom:0}.fleet-page .fp-source p{margin:5px 0 3px}.fleet-page .fp-row,.fleet-standalone-dialog .fp-row{display:flex;align-items:center;justify-content:space-between;gap:12px}.fleet-page .fp-source-meta{font-size:11px;color:var(--mute);gap:8px;flex-wrap:wrap}.fleet-page .fp-state,.fleet-standalone-dialog .fp-state{font-size:12px;font-weight:600;text-transform:capitalize}.fleet-page .fp-capacity-strip{display:grid;grid-template-columns:repeat(3,1fr) 1.6fr;padding:18px 24px;gap:18px}.fleet-page .fp-capacity-strip>div{display:flex;flex-direction:column;gap:4px}.fleet-page .fp-capacity-strip strong{font-size:23px;line-height:1.3}.fleet-page .fp-capacity-context{justify-content:center;align-items:flex-end}.fleet-page .fp-operation{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:18px 24px}.fleet-page .fp-operation p{margin:6px 0 0}.fleet-page .fp-restricted{padding:16px 20px;margin:0}.fleet-page .fp-access-note{font-size:12px;margin:0}.fleet-standalone-dialog{display:flex;flex-direction:column;max-height:min(850px,calc(100dvh - 60px));min-width:0}.fleet-standalone-dialog .fleet-standalone-body{overflow:auto;min-height:0;overscroll-behavior:contain;padding:2px 2px 12px}.fleet-standalone-dialog .modal-message{flex-shrink:0}.fleet-standalone-dialog .modal-actions{flex-shrink:0}.fleet-standalone-dialog fieldset{min-width:0;border:0;padding:0;margin:0}.fleet-standalone-dialog .fp-stack{display:flex;flex-direction:column;gap:16px}.fleet-standalone-dialog .fp-stack>p,.fleet-standalone-dialog .fp-resource p,.fleet-standalone-dialog .fp-resource h3{margin:0}.fleet-standalone-dialog .mojo-tab-panel{padding-top:20px}.fleet-standalone-dialog .fp-resource{border:1px solid var(--line);border-radius:10px;padding:18px;overflow-wrap:anywhere}.fleet-standalone-dialog .fp-resource>p+small,.fleet-standalone-dialog .fp-resource>p+p{display:block;margin-top:8px}.fleet-standalone-dialog .fp-resource h3{font-size:14px}.fleet-standalone-dialog .fp-member{display:flex;flex-direction:column;gap:6px;padding:14px 0;border-bottom:1px solid var(--line)}.fleet-standalone-dialog .fp-member:last-child{border-bottom:0}.fleet-standalone-dialog .fp-fields{display:grid;grid-template-columns:1fr 1fr;gap:16px;align-items:start}.fleet-standalone-dialog .fp-check{display:flex;align-items:flex-start;gap:9px;font-size:13px;line-height:1.6}.fleet-standalone-dialog .fp-check input{flex:none;margin-top:4px}.fleet-standalone-dialog .fp-toolbar{margin:0 0 18px;flex-wrap:wrap}.fleet-standalone-dialog .fp-empty{margin:20px 0 4px}.fleet-standalone-dialog .fp-plan{display:flex;flex-direction:column;gap:14px;padding-left:24px;margin:0}.fleet-standalone-dialog .fp-plan p{margin:6px 0 0}.fleet-standalone-dialog pre{white-space:pre-wrap;font-family:var(--font-mono,monospace);font-size:12px}.fleet-standalone-dialog .field-help{line-height:1.6}.fleet-standalone-dialog .input{width:100%;min-width:0}.fleet-standalone-dialog .modal-title{overflow-wrap:anywhere}.fleet-standalone-dialog .fp-member .fp-fields{margin-top:8px}
|
|
3
|
+
@media(max-width:700px){.fleet-page .fp-header{align-items:flex-start;flex-direction:column;gap:16px}.fleet-page .fp-actions{justify-content:flex-start}.fleet-page .fp-evidence-grid{grid-template-columns:1fr}.fleet-page .fp-capacity-strip{grid-template-columns:repeat(3,1fr);padding:16px;gap:16px}.fleet-page .fp-capacity-context{grid-column:1/-1;align-items:flex-start}.fleet-page .fp-health,.fleet-page .fp-operation{padding:18px;align-items:flex-start}.fleet-page .fp-operation{flex-direction:column}.fleet-standalone-dialog{max-height:calc(100dvh - 32px)}.fleet-standalone-dialog .fp-fields{grid-template-columns:1fr}.fleet-standalone-dialog .fp-resource>.fp-row{align-items:flex-start;flex-wrap:wrap}.fleet-standalone-dialog .fp-resource{padding:14px}.fleet-page .fp-source{padding:12px 4px}.fleet-page .fp-source:nth-last-child(2){border-bottom:1px solid var(--line)}.fleet-page .fp-section{padding:8px 14px}}
|
|
4
|
+
/* Keep every inspection tab visible within a narrow native dialog. */
|
|
5
|
+
@media(max-width:700px){.fleet-standalone-dialog .mojo-tab-list{flex-wrap:wrap;overflow:visible}}
|
|
6
|
+
|
|
7
|
+
/* Destination names are actions; keep evidence-only labels visually distinct. */
|
|
8
|
+
.fleet-page .fp-source strong a{color:var(--accent);text-decoration:underline;text-underline-offset:3px}
|
|
9
|
+
.fleet-page .fp-source strong a:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:2px}
|
package/src/styles/index.css
CHANGED
|
@@ -24,6 +24,13 @@
|
|
|
24
24
|
@import "./components/admin-assistant.css" layer(portal-mojo);
|
|
25
25
|
@import "./components/admin-security.css" layer(portal-mojo);
|
|
26
26
|
@import "./components/admin-dashboard.css" layer(portal-mojo);
|
|
27
|
+
@import "./components/admin-operational-fleet.css" layer(portal-mojo);
|
|
28
|
+
@import "./components/fleet-page.css" layer(portal-mojo);
|
|
29
|
+
@import "./components/admin-maintenance.css" layer(portal-mojo);
|
|
30
|
+
@import "./components/admin-deployments.css" layer(portal-mojo);
|
|
31
|
+
@import "./components/admin-domains.css" layer(portal-mojo);
|
|
32
|
+
@import "./components/admin-operations.css" layer(portal-mojo);
|
|
33
|
+
@import "./components/admin-geolocation.css" layer(portal-mojo);
|
|
27
34
|
@import "./components/admin-cloudwatch.css" layer(portal-mojo);
|
|
28
35
|
@import "./components/admin-monitoring.css" layer(portal-mojo);
|
|
29
36
|
@import "./components/admin-bouncer.css" layer(portal-mojo);
|
|
@@ -35,15 +35,24 @@
|
|
|
35
35
|
// · "Start typing to search…" is actually reachable — in the source it
|
|
36
36
|
// was dead code (its showNoResults guard required hasSearched).
|
|
37
37
|
import { useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
38
|
-
import { useQueryClient, type QueryClient } from '@tanstack/react-query';
|
|
39
|
-
import {
|
|
38
|
+
import { keepPreviousData, useQuery, useQueryClient, type QueryClient } from '@tanstack/react-query';
|
|
39
|
+
import { mojoGet, mojoList } from '../client/client';
|
|
40
|
+
import { getAuthSessionRevision } from '../client/auth';
|
|
40
41
|
import type { ModelDef } from '../client/model';
|
|
41
42
|
import type { Params } from '../client/types';
|
|
43
|
+
import { useAuthSnapshot } from '../client/me';
|
|
42
44
|
import { GroupContext } from '../client/group-context';
|
|
43
45
|
import { Popover } from './Popover';
|
|
44
46
|
|
|
45
47
|
/** Every id comparison in this component goes through here — string and
|
|
46
48
|
* number ids (and mixes of the two) work by construction. */
|
|
49
|
+
const sanitizerIds = new WeakMap<Function, number>();
|
|
50
|
+
let nextSanitizerId = 1;
|
|
51
|
+
function sanitizerId(fn: Function): number {
|
|
52
|
+
if (!sanitizerIds.has(fn)) sanitizerIds.set(fn, nextSanitizerId++);
|
|
53
|
+
return sanitizerIds.get(fn)!;
|
|
54
|
+
}
|
|
55
|
+
|
|
47
56
|
const keyOf = (v: string | number): string => String(v);
|
|
48
57
|
|
|
49
58
|
/** MOJOUtils.getNestedValue heritage: dot-notation nested access. */
|
|
@@ -76,8 +85,8 @@ const coerceFetchId = (id: string | number): string | number =>
|
|
|
76
85
|
* root for the row (ModelTable pages, other pickers, this picker's own
|
|
77
86
|
* fetches all share the [endpoint, params] keys). Non-reactive by design:
|
|
78
87
|
* a miss falls through to the reactive one-record fetch. */
|
|
79
|
-
function findRowInListCaches(qc: QueryClient, endpoint: string, key: string, valueField: string): unknown {
|
|
80
|
-
for (const [, data] of qc.getQueriesData<unknown>({ queryKey: [endpoint] })) {
|
|
88
|
+
function findRowInListCaches(qc: QueryClient, endpoint: string, key: string, valueField: string, safeRoot?: readonly unknown[]): unknown {
|
|
89
|
+
for (const [, data] of qc.getQueriesData<unknown>({ queryKey: safeRoot ?? [endpoint] })) {
|
|
81
90
|
if (data == null || typeof data !== 'object') continue;
|
|
82
91
|
const rows = (data as { rows?: unknown }).rows;
|
|
83
92
|
if (!Array.isArray(rows)) continue; // skips [endpoint,'one',id] entries
|
|
@@ -109,6 +118,8 @@ export type CollectionSelectValue = string | number | Record<string, unknown> |
|
|
|
109
118
|
export interface CollectionSelectProps<T extends { id: number | string }> {
|
|
110
119
|
/** A defineModel definition — supplies the endpoint (and the row type). */
|
|
111
120
|
model?: ModelDef<T>;
|
|
121
|
+
/** Optional ingress projection. Uses an auth-scoped isolated cache; raw caches are never read. */
|
|
122
|
+
sanitizeRow?: (row: T) => T;
|
|
112
123
|
/** Bare endpoint, for lists without a model definition. */
|
|
113
124
|
endpoint?: string;
|
|
114
125
|
/** Selected id — CONTROLLED. Accepts id | null | row-object (see CollectionSelectValue). */
|
|
@@ -156,7 +167,7 @@ export interface CollectionSelectProps<T extends { id: number | string }> {
|
|
|
156
167
|
}
|
|
157
168
|
|
|
158
169
|
export function CollectionSelect<T extends { id: number | string }>({
|
|
159
|
-
model, endpoint, value, onChange,
|
|
170
|
+
model, endpoint, value, onChange, sanitizeRow,
|
|
160
171
|
labelField = 'name', valueField = 'id',
|
|
161
172
|
maxItems = 10, placeholder = 'Search…', debounceMs = 400,
|
|
162
173
|
emptyFetch = true, defaultParams, requiresActiveGroup = false,
|
|
@@ -167,6 +178,8 @@ export function CollectionSelect<T extends { id: number | string }>({
|
|
|
167
178
|
if (!resolvedEndpoint) throw new Error('CollectionSelect: pass `model` or `endpoint`');
|
|
168
179
|
|
|
169
180
|
const qc = useQueryClient();
|
|
181
|
+
const auth = useAuthSnapshot();
|
|
182
|
+
const safeRoot = sanitizeRow ? [resolvedEndpoint, 'safe-select', sanitizerId(sanitizeRow), auth.uid, getAuthSessionRevision()] as const : undefined;
|
|
170
183
|
const uid = useId();
|
|
171
184
|
const inputDomId = `colsel-input-${uid}`;
|
|
172
185
|
const listboxId = `colsel-list-${uid}`;
|
|
@@ -239,7 +252,12 @@ export function CollectionSelect<T extends { id: number | string }>({
|
|
|
239
252
|
// Fetch only while the dropdown is open (the source fetched on focus);
|
|
240
253
|
// with emptyFetch off, additionally only once there is a search term.
|
|
241
254
|
const listEnabled = open && !waitingForGroup && (emptyFetch || term !== '');
|
|
242
|
-
const query =
|
|
255
|
+
const query = useQuery({
|
|
256
|
+
queryKey: safeRoot ? [...safeRoot, wire] : [resolvedEndpoint, wire],
|
|
257
|
+
queryFn: async () => { const page = await mojoList<T>(resolvedEndpoint, wire); return sanitizeRow ? { ...page, rows: page.rows.map(sanitizeRow) } : page; },
|
|
258
|
+
placeholderData: sanitizeRow ? undefined : keepPreviousData,
|
|
259
|
+
enabled: listEnabled && (!sanitizeRow || auth.authenticated),
|
|
260
|
+
});
|
|
243
261
|
// A held query (emptyFetch=false with no term, or no active group) must
|
|
244
262
|
// show its empty state — keepPreviousData would otherwise keep serving
|
|
245
263
|
// the previous key's rows through the placeholder.
|
|
@@ -275,7 +293,7 @@ export function CollectionSelect<T extends { id: number | string }>({
|
|
|
275
293
|
const pickedLabel = selKey != null && picked?.key === selKey ? picked.label : null;
|
|
276
294
|
let scanLabel: string | null = null;
|
|
277
295
|
if (selKey != null && seedLabel == null && pickedLabel == null) {
|
|
278
|
-
const row = findRowInListCaches(qc, resolvedEndpoint, selKey, valueField);
|
|
296
|
+
const row = findRowInListCaches(qc, resolvedEndpoint, selKey, valueField, safeRoot);
|
|
279
297
|
if (row != null) {
|
|
280
298
|
const raw = getPath(row, labelField);
|
|
281
299
|
// A row without the label field stays unresolved — the one-record
|
|
@@ -284,7 +302,11 @@ export function CollectionSelect<T extends { id: number | string }>({
|
|
|
284
302
|
}
|
|
285
303
|
}
|
|
286
304
|
const needFetch = selKey != null && seedLabel == null && pickedLabel == null && scanLabel == null;
|
|
287
|
-
const oneQuery =
|
|
305
|
+
const oneQuery = useQuery({
|
|
306
|
+
queryKey: safeRoot ? [...safeRoot, 'one', coerceFetchId(selId ?? '')] : [resolvedEndpoint, 'one', needFetch && selId != null ? coerceFetchId(selId) : null],
|
|
307
|
+
queryFn: async () => { const row = await mojoGet<T>(resolvedEndpoint, coerceFetchId(selId!), { unscoped: true }); return sanitizeRow ? sanitizeRow(row) : row; },
|
|
308
|
+
enabled: needFetch && selId != null && (!sanitizeRow || auth.authenticated),
|
|
309
|
+
});
|
|
288
310
|
let oneLabel: string | null = null;
|
|
289
311
|
if (needFetch && oneQuery.data != null) {
|
|
290
312
|
const raw = getPath(oneQuery.data, labelField);
|