save checkpoint
This commit is contained in:
@@ -54,8 +54,8 @@
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "12kb",
|
||||
"maximumError": "20kb"
|
||||
"maximumWarning": "20kb",
|
||||
"maximumError": "30kb"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all",
|
||||
@@ -101,13 +101,13 @@
|
||||
"setupFiles": ["src/test-setup.ts"],
|
||||
"exclude": [
|
||||
"**/*.e2e.spec.ts",
|
||||
"src/app/core/api/vex-hub.client.spec.ts",
|
||||
"src/app/core/services/*.spec.ts",
|
||||
"src/app/features/**/*.spec.ts",
|
||||
"src/app/shared/components/**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"src/app/core/api/vex-hub.client.spec.ts",
|
||||
"src/app/core/services/*.spec.ts",
|
||||
"src/app/features/**/*.spec.ts",
|
||||
"src/app/shared/components/**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"storybook": {
|
||||
"builder": "@storybook/angular:start-storybook",
|
||||
"options": {
|
||||
|
||||
@@ -1,114 +1,114 @@
|
||||
{
|
||||
"/envsettings.json": {
|
||||
"target": "https://localhost:10010",
|
||||
"target": "http://127.1.0.3:80",
|
||||
"secure": false
|
||||
},
|
||||
"/platform": {
|
||||
"target": "https://localhost:10010",
|
||||
"target": "http://127.1.0.3:80",
|
||||
"secure": false
|
||||
},
|
||||
"/api": {
|
||||
"target": "https://localhost:10010",
|
||||
"target": "http://127.1.0.3:80",
|
||||
"secure": false
|
||||
},
|
||||
"/authority": {
|
||||
"target": "https://localhost:10020",
|
||||
"target": "http://127.1.0.4:80",
|
||||
"secure": false
|
||||
},
|
||||
"/console": {
|
||||
"target": "https://localhost:10020",
|
||||
"target": "http://127.1.0.4:80",
|
||||
"secure": false
|
||||
},
|
||||
"/connect": {
|
||||
"target": "https://localhost:10020",
|
||||
"target": "http://127.1.0.4:80",
|
||||
"secure": false
|
||||
},
|
||||
"/.well-known": {
|
||||
"target": "https://localhost:10020",
|
||||
"target": "http://127.1.0.4:80",
|
||||
"secure": false
|
||||
},
|
||||
"/jwks": {
|
||||
"target": "https://localhost:10020",
|
||||
"target": "http://127.1.0.4:80",
|
||||
"secure": false
|
||||
},
|
||||
"/scanner": {
|
||||
"target": "https://localhost:10080",
|
||||
"target": "http://127.1.0.8:80",
|
||||
"secure": false
|
||||
},
|
||||
"/policyGateway": {
|
||||
"target": "https://localhost:10140",
|
||||
"target": "http://127.1.0.14:80",
|
||||
"secure": false
|
||||
},
|
||||
"/policyEngine": {
|
||||
"target": "https://localhost:10140",
|
||||
"target": "http://127.1.0.14:80",
|
||||
"secure": false
|
||||
},
|
||||
"/concelier": {
|
||||
"target": "https://localhost:10090",
|
||||
"target": "http://127.1.0.9:80",
|
||||
"secure": false
|
||||
},
|
||||
"/attestor": {
|
||||
"target": "https://localhost:10040",
|
||||
"target": "http://127.1.0.13:80",
|
||||
"secure": false
|
||||
},
|
||||
"/gateway": {
|
||||
"target": "https://localhost:10030",
|
||||
"target": "http://127.1.0.5:80",
|
||||
"secure": false
|
||||
},
|
||||
"/notify": {
|
||||
"target": "https://localhost:10280",
|
||||
"target": "http://127.1.0.29:80",
|
||||
"secure": false
|
||||
},
|
||||
"/scheduler": {
|
||||
"target": "https://localhost:10190",
|
||||
"target": "http://127.1.0.19:80",
|
||||
"secure": false
|
||||
},
|
||||
"/signals": {
|
||||
"target": "https://localhost:10430",
|
||||
"target": "http://127.1.0.43:80",
|
||||
"secure": false
|
||||
},
|
||||
"/excititor": {
|
||||
"target": "https://localhost:10310",
|
||||
"target": "http://127.1.0.9:80",
|
||||
"secure": false
|
||||
},
|
||||
"/findingsLedger": {
|
||||
"target": "https://localhost:10320",
|
||||
"target": "http://127.1.0.9:80",
|
||||
"secure": false
|
||||
},
|
||||
"/vexhub": {
|
||||
"target": "https://localhost:10330",
|
||||
"target": "http://127.1.0.11:80",
|
||||
"secure": false
|
||||
},
|
||||
"/vexlens": {
|
||||
"target": "https://localhost:10340",
|
||||
"target": "http://127.1.0.12:80",
|
||||
"secure": false
|
||||
},
|
||||
"/orchestrator": {
|
||||
"target": "https://localhost:10200",
|
||||
"target": "http://127.1.0.17:80",
|
||||
"secure": false
|
||||
},
|
||||
"/graph": {
|
||||
"target": "https://localhost:10350",
|
||||
"target": "http://127.1.0.20:80",
|
||||
"secure": false
|
||||
},
|
||||
"/doctor": {
|
||||
"target": "https://localhost:10360",
|
||||
"target": "http://127.1.0.26:80",
|
||||
"secure": false
|
||||
},
|
||||
"/integrations": {
|
||||
"target": "https://localhost:10400",
|
||||
"target": "http://127.1.0.42:80",
|
||||
"secure": false
|
||||
},
|
||||
"/replay": {
|
||||
"target": "https://localhost:10410",
|
||||
"target": "http://127.1.0.41:80",
|
||||
"secure": false
|
||||
},
|
||||
"/exportcenter": {
|
||||
"target": "https://localhost:10420",
|
||||
"target": "http://127.1.0.40:80",
|
||||
"secure": false
|
||||
},
|
||||
"/healthz": {
|
||||
"target": "https://localhost:10010",
|
||||
"target": "http://127.1.0.3:80",
|
||||
"secure": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,330 +197,442 @@ import type {
|
||||
</div>
|
||||
`,
|
||||
styles: [`
|
||||
:host {
|
||||
--so-brand: #F5A623;
|
||||
--so-brand-hover: #E09115;
|
||||
--so-accent: #D4920A;
|
||||
--so-accent-muted: #C4820A;
|
||||
--so-brand-soft: #FEF3E2;
|
||||
--so-surface: #FFFCF5;
|
||||
--so-surface-elevated: #fff;
|
||||
--so-base: #FFF9ED;
|
||||
--so-heading: #1C1200;
|
||||
--so-text: #3D2E0A;
|
||||
--so-text-secondary: #6B5A2E;
|
||||
--so-mute: #D4C9A8;
|
||||
--so-border-light: hsla(45,34%,75%,.3);
|
||||
--so-border-medium: hsla(45,34%,75%,.5);
|
||||
--so-border-emphasis: rgba(245,166,35,.4);
|
||||
--so-success: #059669;
|
||||
--so-success-soft: #D1FAE5;
|
||||
--so-warning: #D97706;
|
||||
--so-warning-soft: rgba(217,119,6,.08);
|
||||
--so-error: #DC2626;
|
||||
--so-error-soft: rgba(220,38,38,.08);
|
||||
--so-info: #2563EB;
|
||||
--so-info-soft: rgba(37,99,235,.08);
|
||||
--so-shadow-brand: rgba(245,166,35,.15);
|
||||
--so-shadow-dark: rgba(28,18,0,.08);
|
||||
--so-shadow-ambient: rgba(61,46,10,.04);
|
||||
--so-gradient-cta: linear-gradient(135deg, var(--so-brand) 0%, var(--so-accent) 100%);
|
||||
--so-shadow-sm: 0 2px 4px var(--so-shadow-dark), 0 1px 2px var(--so-shadow-ambient);
|
||||
--so-shadow-md: 0 4px 8px var(--so-shadow-dark), 0 2px 4px var(--so-shadow-ambient);
|
||||
--so-shadow-lg: 0 8px 24px var(--so-shadow-dark), 0 4px 8px var(--so-shadow-ambient);
|
||||
--so-shadow-brand-md: 0 4px 16px var(--so-shadow-brand);
|
||||
--so-ease-out: cubic-bezier(0, 0, 0.2, 1);
|
||||
--so-ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dashboard {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
animation: dash-in 500ms var(--so-ease-out) both;
|
||||
}
|
||||
|
||||
@keyframes dash-in {
|
||||
from { opacity: 0; transform: translateY(12px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.dashboard__header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
gap: var(--space-4);
|
||||
margin-bottom: var(--space-6);
|
||||
gap: 16px;
|
||||
margin-bottom: 28px;
|
||||
padding: 28px 32px;
|
||||
background: var(--so-surface-elevated);
|
||||
border: 1px solid var(--so-border-light);
|
||||
border-radius: 16px;
|
||||
box-shadow: var(--so-shadow-sm);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.dashboard__header::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 3px;
|
||||
background: var(--so-gradient-cta);
|
||||
}
|
||||
|
||||
.dashboard__title {
|
||||
margin: 0 0 var(--space-1);
|
||||
font-size: var(--font-size-2xl);
|
||||
font-weight: var(--font-weight-bold);
|
||||
color: var(--color-text-heading);
|
||||
margin: 0 0 6px;
|
||||
font-size: 26px;
|
||||
font-weight: 800;
|
||||
color: var(--so-heading);
|
||||
letter-spacing: -0.035em;
|
||||
}
|
||||
|
||||
.dashboard__subtitle {
|
||||
margin: 0;
|
||||
color: var(--color-text-secondary);
|
||||
font-size: var(--font-size-base);
|
||||
color: var(--so-text-secondary);
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.dashboard__actions {
|
||||
display: flex;
|
||||
gap: var(--space-2);
|
||||
gap: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Sections */
|
||||
.dashboard__section {
|
||||
margin-bottom: var(--space-6);
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
|
||||
.dashboard__section-title {
|
||||
margin: 0 0 var(--space-3);
|
||||
font-size: var(--font-size-lg);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--color-text-heading);
|
||||
margin: 0 0 14px;
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
color: var(--so-heading);
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.dashboard__grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: var(--space-4);
|
||||
margin-bottom: var(--space-6);
|
||||
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
||||
gap: 20px;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
|
||||
/* Loading */
|
||||
.dashboard__loading {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 300px;
|
||||
gap: var(--space-3);
|
||||
color: var(--color-text-secondary);
|
||||
gap: 16px;
|
||||
color: var(--so-text-secondary);
|
||||
}
|
||||
|
||||
.dashboard__spinner {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 3px solid var(--color-border-default, rgba(212, 201, 168, 0.3));
|
||||
border-top-color: var(--color-brand-primary);
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border: 3px solid var(--so-border-light);
|
||||
border-top-color: var(--so-brand);
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
/* Error */
|
||||
.dashboard__error {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 200px;
|
||||
gap: var(--space-2);
|
||||
padding: var(--space-6);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-status-error-text, #c44);
|
||||
border-radius: var(--radius-lg);
|
||||
gap: 10px;
|
||||
padding: 40px;
|
||||
background: var(--so-surface-elevated);
|
||||
border: 1px solid rgba(220,38,38,.2);
|
||||
border-radius: 16px;
|
||||
text-align: center;
|
||||
box-shadow: var(--so-shadow-sm);
|
||||
}
|
||||
|
||||
.dashboard__error-title {
|
||||
margin: 0;
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--color-text-heading);
|
||||
font-weight: 700;
|
||||
color: var(--so-heading);
|
||||
}
|
||||
|
||||
.dashboard__error-message {
|
||||
margin: 0;
|
||||
color: var(--color-text-secondary);
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--so-text-secondary);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.dashboard__empty {
|
||||
padding: var(--space-6);
|
||||
padding: 40px;
|
||||
text-align: center;
|
||||
color: var(--color-text-muted);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px dashed var(--color-border-default, rgba(212, 201, 168, 0.3));
|
||||
border-radius: var(--radius-lg);
|
||||
color: var(--so-text-secondary);
|
||||
background: var(--so-surface-elevated);
|
||||
border: 2px dashed var(--so-mute);
|
||||
border-radius: 16px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* Pipeline */
|
||||
.pipeline {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: var(--space-4);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-default, rgba(212, 201, 168, 0.3));
|
||||
border-radius: var(--radius-lg);
|
||||
gap: 10px;
|
||||
padding: 20px 24px;
|
||||
background: var(--so-surface-elevated);
|
||||
border: 1px solid var(--so-border-light);
|
||||
border-radius: 16px;
|
||||
box-shadow: var(--so-shadow-sm);
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.pipeline__stage {
|
||||
flex: 1;
|
||||
min-width: 140px;
|
||||
padding: var(--space-3);
|
||||
background: var(--color-surface-tertiary);
|
||||
border: 1px solid var(--color-border-default, rgba(212, 201, 168, 0.3));
|
||||
border-radius: var(--radius-md);
|
||||
min-width: 150px;
|
||||
padding: 16px;
|
||||
background: var(--so-surface);
|
||||
border: 1px solid var(--so-border-light);
|
||||
border-radius: 12px;
|
||||
text-align: center;
|
||||
transition: all 220ms var(--so-ease-out);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.pipeline__stage:hover {
|
||||
box-shadow: var(--so-shadow-md);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.pipeline__stage--degraded {
|
||||
border-color: var(--color-status-warning-text);
|
||||
border-color: rgba(217,119,6,.35);
|
||||
background: var(--so-warning-soft);
|
||||
}
|
||||
|
||||
.pipeline__stage--unhealthy {
|
||||
border-color: var(--color-status-error-text, #c44);
|
||||
border-color: rgba(220,38,38,.35);
|
||||
background: var(--so-error-soft);
|
||||
}
|
||||
|
||||
.pipeline__stage-header {
|
||||
margin-bottom: var(--space-2);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.pipeline__stage-name {
|
||||
display: block;
|
||||
font-weight: var(--font-weight-semibold);
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--color-text-heading);
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
color: var(--so-heading);
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.pipeline__stage-count {
|
||||
font-size: var(--font-size-xs);
|
||||
color: var(--color-text-muted);
|
||||
font-size: 12px;
|
||||
color: var(--so-text-secondary);
|
||||
margin-top: 2px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.pipeline__health-badge {
|
||||
display: inline-block;
|
||||
padding: 2px var(--space-2);
|
||||
font-size: var(--font-size-xs);
|
||||
font-weight: var(--font-weight-medium);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 3px 10px;
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
border-radius: 6px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
.pipeline__health-badge--healthy {
|
||||
background: var(--color-status-success-bg);
|
||||
color: var(--color-status-success-text);
|
||||
background: var(--so-success-soft);
|
||||
color: var(--so-success);
|
||||
border: 1px solid rgba(5,150,105,.2);
|
||||
}
|
||||
|
||||
.pipeline__health-badge--degraded {
|
||||
background: var(--color-status-warning-bg);
|
||||
color: var(--color-status-warning-text);
|
||||
background: var(--so-warning-soft);
|
||||
color: var(--so-warning);
|
||||
border: 1px solid rgba(217,119,6,.2);
|
||||
}
|
||||
|
||||
.pipeline__health-badge--unhealthy {
|
||||
background: var(--color-status-error-bg);
|
||||
color: var(--color-status-error-text);
|
||||
background: var(--so-error-soft);
|
||||
color: var(--so-error);
|
||||
border: 1px solid rgba(220,38,38,.2);
|
||||
}
|
||||
|
||||
.pipeline__health-badge--unknown {
|
||||
background: var(--color-surface-secondary);
|
||||
color: var(--color-text-muted);
|
||||
background: var(--so-surface);
|
||||
color: var(--so-mute);
|
||||
border: 1px solid var(--so-border-light);
|
||||
}
|
||||
|
||||
.pipeline__pending-count {
|
||||
display: block;
|
||||
margin-top: var(--space-1);
|
||||
font-size: var(--font-size-xs);
|
||||
color: var(--color-status-warning-text);
|
||||
margin-top: 6px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: var(--so-warning);
|
||||
}
|
||||
|
||||
.pipeline__arrow {
|
||||
flex-shrink: 0;
|
||||
color: var(--color-text-muted);
|
||||
color: var(--so-mute);
|
||||
opacity: .6;
|
||||
}
|
||||
|
||||
/* Cards */
|
||||
.card {
|
||||
padding: var(--space-4);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-default, rgba(212, 201, 168, 0.3));
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 24px;
|
||||
background: var(--so-surface-elevated);
|
||||
border: 1px solid var(--so-border-light);
|
||||
border-radius: 16px;
|
||||
box-shadow: var(--so-shadow-sm);
|
||||
transition: box-shadow 220ms var(--so-ease-out), transform 220ms var(--so-ease-out);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
box-shadow: var(--so-shadow-md);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.card__title {
|
||||
margin: 0 0 var(--space-0-5);
|
||||
font-size: var(--font-size-base);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--color-text-heading);
|
||||
margin: 0 0 4px;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: var(--so-heading);
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.card__subtitle {
|
||||
margin: 0 0 var(--space-3);
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--color-text-muted);
|
||||
margin: 0 0 16px;
|
||||
font-size: 13px;
|
||||
color: var(--so-text-secondary);
|
||||
}
|
||||
|
||||
.card__empty {
|
||||
margin: 0 0 var(--space-3);
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--color-text-muted);
|
||||
margin: 0 0 16px;
|
||||
font-size: 13px;
|
||||
color: var(--so-text-secondary);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.card__list {
|
||||
margin: 0 0 var(--space-3);
|
||||
margin: 0 0 16px;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.card__item {
|
||||
padding: var(--space-2) 0;
|
||||
border-bottom: 1px solid var(--color-border-default, rgba(212, 201, 168, 0.15));
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px solid var(--so-border-light);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.card__item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.card__item-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.card__item-link {
|
||||
font-weight: var(--font-weight-medium);
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--color-brand-primary);
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
color: var(--so-accent);
|
||||
text-decoration: none;
|
||||
transition: color 150ms var(--so-ease-out);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.card__item-link:hover {
|
||||
color: var(--so-brand-hover);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.card__item-detail {
|
||||
display: block;
|
||||
font-size: var(--font-size-xs);
|
||||
color: var(--color-text-muted);
|
||||
margin-top: var(--space-0-5);
|
||||
font-size: 12px;
|
||||
color: var(--so-text-secondary);
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.card__urgency {
|
||||
font-size: var(--font-size-xs);
|
||||
font-weight: var(--font-weight-medium);
|
||||
padding: 1px var(--space-2);
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
padding: 2px 8px;
|
||||
border-radius: 6px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.card__urgency--high,
|
||||
.card__urgency--critical {
|
||||
background: var(--color-status-error-bg);
|
||||
color: var(--color-status-error-text);
|
||||
background: var(--so-error-soft);
|
||||
color: var(--so-error);
|
||||
border: 1px solid rgba(220,38,38,.2);
|
||||
}
|
||||
|
||||
.card__urgency--normal {
|
||||
background: var(--color-surface-secondary);
|
||||
color: var(--color-text-secondary);
|
||||
background: var(--so-surface);
|
||||
color: var(--so-text-secondary);
|
||||
border: 1px solid var(--so-border-light);
|
||||
}
|
||||
|
||||
.card__urgency--low {
|
||||
background: var(--color-surface-tertiary);
|
||||
color: var(--color-text-muted);
|
||||
background: var(--so-surface);
|
||||
color: var(--so-mute);
|
||||
border: 1px solid var(--so-border-light);
|
||||
}
|
||||
|
||||
.card__dep-status {
|
||||
font-size: var(--font-size-xs);
|
||||
font-weight: var(--font-weight-medium);
|
||||
padding: 1px var(--space-2);
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
padding: 2px 8px;
|
||||
border-radius: 6px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.card__dep-status--running {
|
||||
background: var(--color-status-info-bg);
|
||||
color: var(--color-status-info-text);
|
||||
background: var(--so-info-soft);
|
||||
color: var(--so-info);
|
||||
border: 1px solid rgba(37,99,235,.2);
|
||||
}
|
||||
|
||||
.card__dep-status--paused,
|
||||
.card__dep-status--waiting {
|
||||
background: var(--color-status-warning-bg);
|
||||
color: var(--color-status-warning-text);
|
||||
background: var(--so-warning-soft);
|
||||
color: var(--so-warning);
|
||||
border: 1px solid rgba(217,119,6,.2);
|
||||
}
|
||||
|
||||
.card__progress {
|
||||
height: 4px;
|
||||
background: var(--color-surface-tertiary);
|
||||
border-radius: 2px;
|
||||
margin: var(--space-1) 0;
|
||||
height: 5px;
|
||||
background: var(--so-border-light);
|
||||
border-radius: 3px;
|
||||
margin: 6px 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card__progress-bar {
|
||||
height: 100%;
|
||||
background: var(--color-brand-primary);
|
||||
border-radius: 2px;
|
||||
transition: width var(--motion-duration-sm) var(--motion-ease-standard);
|
||||
background: var(--so-gradient-cta);
|
||||
border-radius: 3px;
|
||||
transition: width 400ms var(--so-ease-out);
|
||||
}
|
||||
|
||||
.card__actions {
|
||||
display: flex;
|
||||
gap: var(--space-2);
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* Table */
|
||||
.table-container {
|
||||
overflow-x: auto;
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-default, rgba(212, 201, 168, 0.3));
|
||||
border-radius: var(--radius-lg);
|
||||
background: var(--so-surface-elevated);
|
||||
border: 1px solid var(--so-border-light);
|
||||
border-radius: 16px;
|
||||
box-shadow: var(--so-shadow-sm);
|
||||
}
|
||||
|
||||
.table {
|
||||
@@ -530,107 +642,137 @@ import type {
|
||||
|
||||
.table th,
|
||||
.table td {
|
||||
padding: var(--space-2) var(--space-3);
|
||||
padding: 12px 18px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--color-border-default, rgba(212, 201, 168, 0.15));
|
||||
border-bottom: 1px solid var(--so-border-light);
|
||||
}
|
||||
|
||||
.table th {
|
||||
font-size: var(--font-size-xs);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--color-text-muted);
|
||||
background: var(--color-surface-tertiary);
|
||||
letter-spacing: 0.06em;
|
||||
color: var(--so-text-secondary);
|
||||
background: var(--so-surface);
|
||||
}
|
||||
|
||||
.table th:first-child { border-radius: 16px 0 0 0; }
|
||||
.table th:last-child { border-radius: 0 16px 0 0; }
|
||||
|
||||
.table td {
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--color-text-primary);
|
||||
font-size: 13px;
|
||||
color: var(--so-text);
|
||||
}
|
||||
|
||||
.table tbody tr {
|
||||
transition: background 150ms var(--so-ease-out);
|
||||
}
|
||||
|
||||
.table tbody tr:hover {
|
||||
background: var(--so-surface);
|
||||
}
|
||||
|
||||
.table tbody tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.table a {
|
||||
color: var(--color-brand-primary);
|
||||
color: var(--so-accent);
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.table a:hover {
|
||||
color: var(--so-brand-hover);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Badges */
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 2px var(--space-2);
|
||||
font-size: var(--font-size-xs);
|
||||
font-weight: var(--font-weight-medium);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 3px 10px;
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
border-radius: 6px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.badge--deployed {
|
||||
background: var(--color-status-success-bg);
|
||||
color: var(--color-status-success-text);
|
||||
background: var(--so-success-soft);
|
||||
color: var(--so-success);
|
||||
border: 1px solid rgba(5,150,105,.2);
|
||||
}
|
||||
|
||||
.badge--ready,
|
||||
.badge--promoting {
|
||||
background: var(--color-status-warning-bg);
|
||||
color: var(--color-status-warning-text);
|
||||
background: var(--so-warning-soft);
|
||||
color: var(--so-warning);
|
||||
border: 1px solid rgba(217,119,6,.2);
|
||||
}
|
||||
|
||||
.badge--draft {
|
||||
background: var(--color-surface-secondary);
|
||||
color: var(--color-text-muted);
|
||||
background: var(--so-surface);
|
||||
color: var(--so-text-secondary);
|
||||
border: 1px solid var(--so-border-light);
|
||||
}
|
||||
|
||||
.badge--failed,
|
||||
.badge--rolled_back {
|
||||
background: var(--color-status-error-bg);
|
||||
color: var(--color-status-error-text);
|
||||
background: var(--so-error-soft);
|
||||
color: var(--so-error);
|
||||
border: 1px solid rgba(220,38,38,.2);
|
||||
}
|
||||
|
||||
.badge--deprecated {
|
||||
background: var(--color-surface-tertiary);
|
||||
color: var(--color-text-muted);
|
||||
background: var(--so-surface);
|
||||
color: var(--so-mute);
|
||||
border: 1px solid var(--so-border-light);
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-1);
|
||||
padding: var(--space-2) var(--space-4);
|
||||
gap: 6px;
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: var(--font-weight-medium);
|
||||
border-radius: 10px;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
transition: background-color var(--motion-duration-sm) var(--motion-ease-standard);
|
||||
transition: all 200ms var(--so-ease-out);
|
||||
}
|
||||
|
||||
.btn--primary {
|
||||
background: var(--color-brand-primary);
|
||||
color: #fff;
|
||||
background: var(--so-gradient-cta);
|
||||
color: var(--so-heading);
|
||||
box-shadow: var(--so-shadow-sm), var(--so-shadow-brand-md),
|
||||
inset 0 1px 0 rgba(255,255,255,.2);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: var(--color-brand-primary-hover, #c47f0f);
|
||||
}
|
||||
.btn--primary:hover {
|
||||
background: linear-gradient(135deg, var(--so-brand-hover) 0%, var(--so-accent-muted) 100%);
|
||||
box-shadow: var(--so-shadow-md), 0 6px 20px var(--so-shadow-brand);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn--secondary {
|
||||
background: var(--color-surface-tertiary);
|
||||
color: var(--color-text-primary);
|
||||
border: 1px solid var(--color-border-default, rgba(212, 201, 168, 0.3));
|
||||
background: var(--so-surface-elevated);
|
||||
color: var(--so-text);
|
||||
border: 1px solid var(--so-border-medium);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: var(--color-surface-secondary);
|
||||
}
|
||||
.btn--secondary:hover {
|
||||
background: var(--so-surface);
|
||||
border-color: var(--so-brand);
|
||||
}
|
||||
|
||||
.btn--small {
|
||||
padding: var(--space-1) var(--space-2);
|
||||
font-size: var(--font-size-xs);
|
||||
padding: 5px 12px;
|
||||
font-size: 12px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
@@ -638,27 +780,21 @@ import type {
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.dashboard__spinner {
|
||||
animation: none;
|
||||
border-top-color: transparent;
|
||||
}
|
||||
|
||||
.btn {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.card__progress-bar {
|
||||
transition: none;
|
||||
}
|
||||
.dashboard__spinner { animation: none; border-top-color: transparent; }
|
||||
.btn, .card, .pipeline__stage, .table tbody tr { transition: none; }
|
||||
.card__progress-bar { transition: none; }
|
||||
.dashboard { animation: none; }
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.dashboard__header {
|
||||
flex-direction: column;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.pipeline {
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.pipeline__arrow {
|
||||
|
||||
@@ -1,8 +1,41 @@
|
||||
// Home Dashboard Styles
|
||||
// Security-focused landing page with aggregated metrics
|
||||
// Security-focused landing page — Stella Ops warm amber design language
|
||||
|
||||
@use 'tokens/breakpoints' as *;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Entrance animation
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@keyframes dash-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(12px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@keyframes skeleton-shimmer {
|
||||
0% { background-position: 200% 0; }
|
||||
100% { background-position: -200% 0; }
|
||||
}
|
||||
|
||||
@keyframes score-draw {
|
||||
from { stroke-dashoffset: 283; }
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Container
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
.dashboard {
|
||||
max-width: var(--container-xl);
|
||||
margin: 0 auto;
|
||||
@@ -20,13 +53,15 @@
|
||||
margin-bottom: var(--space-6);
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-4);
|
||||
animation: dash-in 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
|
||||
}
|
||||
|
||||
.dashboard__title {
|
||||
margin: 0;
|
||||
font-size: var(--font-size-2xl);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--color-text-primary);
|
||||
font-size: 26px;
|
||||
font-weight: 800;
|
||||
color: var(--color-text-heading);
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.dashboard__actions {
|
||||
@@ -38,6 +73,7 @@
|
||||
.dashboard__updated {
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--color-text-muted);
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
|
||||
.dashboard__refresh {
|
||||
@@ -46,18 +82,19 @@
|
||||
gap: var(--space-1-5);
|
||||
padding: var(--space-2) var(--space-3-5);
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--color-text-primary);
|
||||
background-color: var(--color-surface-tertiary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
font-weight: 600;
|
||||
color: var(--color-text-heading);
|
||||
background: linear-gradient(135deg, #FEF3E2, #FFFCF5);
|
||||
border: 1px solid hsla(45, 34%, 75%, 0.5);
|
||||
border-radius: var(--radius-md);
|
||||
cursor: pointer;
|
||||
transition: background-color var(--motion-duration-fast) var(--motion-ease-default),
|
||||
border-color var(--motion-duration-fast) var(--motion-ease-default);
|
||||
transition: all 0.2s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
background-color: var(--color-surface-secondary);
|
||||
border-color: var(--color-border-secondary);
|
||||
background: linear-gradient(135deg, #FDE8C8, #FEF3E2);
|
||||
border-color: rgba(245, 166, 35, 0.4);
|
||||
box-shadow: 0 2px 8px rgba(245, 166, 35, 0.15);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
@@ -70,26 +107,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Errors
|
||||
// =============================================================================
|
||||
|
||||
.dashboard__errors {
|
||||
margin-bottom: var(--space-4);
|
||||
animation: dash-in 0.5s 0.1s cubic-bezier(0.22, 1, 0.36, 1) both;
|
||||
}
|
||||
|
||||
.dashboard__error {
|
||||
padding: var(--space-3) var(--space-4);
|
||||
font-size: var(--font-size-base);
|
||||
color: var(--color-severity-high);
|
||||
background-color: var(--color-status-warning-bg);
|
||||
border: 1px solid var(--color-status-warning-border);
|
||||
border-radius: var(--radius-md);
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: #8B5E14;
|
||||
background-color: #FFF5E6;
|
||||
border: 1px solid #F5A623;
|
||||
border-radius: 10px;
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
@@ -113,20 +147,42 @@
|
||||
// =============================================================================
|
||||
|
||||
.card {
|
||||
background-color: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-lg);
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
border: 1px solid hsla(45, 34%, 75%, 0.3);
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
transition:
|
||||
transform var(--motion-duration-normal) var(--motion-ease-default),
|
||||
box-shadow var(--motion-duration-normal) var(--motion-ease-default),
|
||||
border-color var(--motion-duration-normal) var(--motion-ease-default);
|
||||
transition: all 0.3s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
animation: dash-in 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
|
||||
|
||||
// Gradient accent bar at top
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, #F5A623, #D4920A);
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--shadow-lg);
|
||||
border-color: var(--color-border-secondary);
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 8px 24px rgba(212, 146, 10, 0.1), 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||
border-color: hsla(45, 34%, 75%, 0.5);
|
||||
|
||||
&::before {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Stagger animation for each card
|
||||
&:nth-child(1) { animation-delay: 0.1s; }
|
||||
&:nth-child(2) { animation-delay: 0.2s; }
|
||||
&:nth-child(3) { animation-delay: 0.3s; }
|
||||
&:nth-child(4) { animation-delay: 0.4s; }
|
||||
}
|
||||
|
||||
.card__header {
|
||||
@@ -134,26 +190,29 @@
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: var(--space-4) var(--space-5);
|
||||
border-bottom: 1px solid var(--color-border-primary);
|
||||
border-bottom: 1px solid hsla(45, 34%, 75%, 0.2);
|
||||
background: linear-gradient(135deg, rgba(254, 243, 226, 0.3), transparent);
|
||||
}
|
||||
|
||||
.card__title {
|
||||
margin: 0;
|
||||
font-size: var(--font-size-base);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--color-text-primary);
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: var(--color-text-heading);
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.card__link {
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--color-brand-primary);
|
||||
font-weight: 600;
|
||||
color: #D4920A;
|
||||
text-decoration: none;
|
||||
transition: color var(--motion-duration-fast) var(--motion-ease-default);
|
||||
transition: all 0.2s ease;
|
||||
letter-spacing: 0.01em;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
color: var(--color-brand-primary-hover);
|
||||
color: #F5A623;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,20 +255,22 @@
|
||||
align-items: center;
|
||||
margin-top: var(--space-4);
|
||||
padding-top: var(--space-4);
|
||||
border-top: 1px solid var(--color-border-primary);
|
||||
border-top: 1px solid hsla(45, 34%, 75%, 0.2);
|
||||
}
|
||||
|
||||
.card__stat-value {
|
||||
font-size: var(--font-size-3xl);
|
||||
font-weight: var(--font-weight-bold);
|
||||
color: var(--color-text-primary);
|
||||
font-size: 32px;
|
||||
font-weight: 800;
|
||||
color: var(--color-text-heading);
|
||||
}
|
||||
|
||||
.card__stat-label {
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--color-text-muted);
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: #6B5A2E;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
letter-spacing: 0.08em;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -219,13 +280,13 @@
|
||||
.skeleton {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
var(--color-surface-tertiary) 25%,
|
||||
var(--color-surface-secondary) 50%,
|
||||
var(--color-surface-tertiary) 75%
|
||||
hsla(45, 34%, 75%, 0.15) 25%,
|
||||
hsla(45, 34%, 75%, 0.05) 50%,
|
||||
hsla(45, 34%, 75%, 0.15) 75%
|
||||
);
|
||||
background-size: 200% 100%;
|
||||
animation: skeleton-shimmer 1.5s ease-in-out infinite;
|
||||
border-radius: var(--radius-sm);
|
||||
border-radius: 8px;
|
||||
|
||||
&--bar {
|
||||
height: var(--space-6);
|
||||
@@ -245,11 +306,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes skeleton-shimmer {
|
||||
0% { background-position: 200% 0; }
|
||||
100% { background-position: -200% 0; }
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Severity Bars
|
||||
// =============================================================================
|
||||
@@ -257,7 +313,7 @@
|
||||
.severity-bars {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-2-5);
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.severity-bar {
|
||||
@@ -268,33 +324,41 @@
|
||||
}
|
||||
|
||||
.severity-bar__label {
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #6B5A2E;
|
||||
}
|
||||
|
||||
.severity-bar__track {
|
||||
height: 8px;
|
||||
background-color: var(--color-surface-tertiary);
|
||||
border-radius: var(--radius-sm);
|
||||
height: 10px;
|
||||
background-color: hsla(45, 34%, 75%, 0.15);
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.severity-bar__fill {
|
||||
height: 100%;
|
||||
border-radius: var(--radius-sm);
|
||||
transition: width 300ms ease;
|
||||
border-radius: 5px;
|
||||
transition: width 600ms cubic-bezier(0.22, 1, 0.36, 1);
|
||||
}
|
||||
|
||||
.severity-bar--critical .severity-bar__fill { background-color: var(--color-severity-critical); }
|
||||
.severity-bar--high .severity-bar__fill { background-color: var(--color-severity-high); }
|
||||
.severity-bar--medium .severity-bar__fill { background-color: var(--color-severity-medium); }
|
||||
.severity-bar--low .severity-bar__fill { background-color: var(--color-severity-low); }
|
||||
.severity-bar--critical .severity-bar__fill {
|
||||
background: linear-gradient(90deg, var(--color-severity-critical), #ff6b6b);
|
||||
}
|
||||
.severity-bar--high .severity-bar__fill {
|
||||
background: linear-gradient(90deg, #D4920A, #F5A623);
|
||||
}
|
||||
.severity-bar--medium .severity-bar__fill {
|
||||
background: linear-gradient(90deg, var(--color-severity-medium), #fbbf24);
|
||||
}
|
||||
.severity-bar--low .severity-bar__fill {
|
||||
background: linear-gradient(90deg, var(--color-severity-low), #6ee7b7);
|
||||
}
|
||||
|
||||
.severity-bar__count {
|
||||
font-size: var(--font-size-base);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--color-text-primary);
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: var(--color-text-heading);
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@@ -311,8 +375,8 @@
|
||||
|
||||
.risk-score__circle {
|
||||
position: relative;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
width: 130px;
|
||||
height: 130px;
|
||||
|
||||
svg {
|
||||
transform: rotate(-90deg);
|
||||
@@ -321,7 +385,7 @@
|
||||
|
||||
.risk-score__bg {
|
||||
fill: none;
|
||||
stroke: var(--color-surface-tertiary);
|
||||
stroke: hsla(45, 34%, 75%, 0.2);
|
||||
stroke-width: 8;
|
||||
}
|
||||
|
||||
@@ -330,7 +394,9 @@
|
||||
stroke-width: 8;
|
||||
stroke-linecap: round;
|
||||
stroke-dasharray: 283;
|
||||
transition: stroke-dashoffset 500ms ease;
|
||||
transition: stroke-dashoffset 800ms cubic-bezier(0.22, 1, 0.36, 1);
|
||||
animation: score-draw 1s cubic-bezier(0.22, 1, 0.36, 1) both;
|
||||
filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.1));
|
||||
}
|
||||
|
||||
.risk-score__value {
|
||||
@@ -339,30 +405,31 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: var(--font-size-3xl);
|
||||
font-weight: var(--font-weight-bold);
|
||||
color: var(--color-text-primary);
|
||||
font-size: 30px;
|
||||
font-weight: 800;
|
||||
color: var(--color-text-heading);
|
||||
}
|
||||
|
||||
.risk-score__trend {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-1);
|
||||
padding: var(--space-1) var(--space-2-5);
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
padding: 4px 12px;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
border-radius: var(--radius-full);
|
||||
background-color: var(--color-surface-tertiary);
|
||||
color: var(--color-text-secondary);
|
||||
background-color: hsla(45, 34%, 75%, 0.15);
|
||||
color: #6B5A2E;
|
||||
letter-spacing: 0.02em;
|
||||
|
||||
&--improving {
|
||||
background-color: var(--color-status-success-bg);
|
||||
color: var(--color-severity-low);
|
||||
background-color: #D1FAE5;
|
||||
color: #059669;
|
||||
}
|
||||
|
||||
&--worsening {
|
||||
background-color: var(--color-status-warning-bg);
|
||||
color: var(--color-severity-high);
|
||||
background-color: #FFF5E6;
|
||||
color: #D4920A;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,31 +438,31 @@
|
||||
gap: var(--space-6);
|
||||
margin-top: var(--space-4);
|
||||
padding-top: var(--space-4);
|
||||
border-top: 1px solid var(--color-border-primary);
|
||||
border-top: 1px solid hsla(45, 34%, 75%, 0.2);
|
||||
}
|
||||
|
||||
.risk-count {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: var(--space-0-5);
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.risk-count__value {
|
||||
font-size: var(--font-size-xl);
|
||||
font-weight: var(--font-weight-bold);
|
||||
font-size: 20px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.risk-count__label {
|
||||
font-size: var(--font-size-xs);
|
||||
font-weight: var(--font-weight-medium);
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--color-text-muted);
|
||||
letter-spacing: 0.08em;
|
||||
color: #6B5A2E;
|
||||
}
|
||||
|
||||
.risk-count--critical .risk-count__value { color: var(--color-severity-critical); }
|
||||
.risk-count--high .risk-count__value { color: var(--color-severity-high); }
|
||||
.risk-count--high .risk-count__value { color: #D4920A; }
|
||||
.risk-count--medium .risk-count__value { color: var(--color-severity-medium); }
|
||||
|
||||
// =============================================================================
|
||||
@@ -415,24 +482,26 @@
|
||||
|
||||
.reachability-donut__bg {
|
||||
fill: none;
|
||||
stroke: var(--color-surface-tertiary);
|
||||
stroke: hsla(45, 34%, 75%, 0.15);
|
||||
stroke-width: 12;
|
||||
}
|
||||
|
||||
.reachability-donut__reachable {
|
||||
fill: none;
|
||||
stroke: var(--color-severity-high);
|
||||
stroke: #D4920A;
|
||||
stroke-width: 12;
|
||||
stroke-linecap: round;
|
||||
transition: stroke-dasharray 500ms ease;
|
||||
transition: stroke-dasharray 600ms cubic-bezier(0.22, 1, 0.36, 1);
|
||||
filter: drop-shadow(0 1px 2px rgba(212, 146, 10, 0.3));
|
||||
}
|
||||
|
||||
.reachability-donut__unreachable {
|
||||
fill: none;
|
||||
stroke: var(--color-severity-low);
|
||||
stroke: #059669;
|
||||
stroke-width: 12;
|
||||
stroke-linecap: round;
|
||||
transition: stroke-dasharray 500ms ease, stroke-dashoffset 500ms ease;
|
||||
transition: stroke-dasharray 600ms cubic-bezier(0.22, 1, 0.36, 1),
|
||||
stroke-dashoffset 600ms cubic-bezier(0.22, 1, 0.36, 1);
|
||||
}
|
||||
|
||||
.reachability-donut__center {
|
||||
@@ -445,23 +514,23 @@
|
||||
}
|
||||
|
||||
.reachability-donut__value {
|
||||
font-size: var(--font-size-2xl);
|
||||
font-weight: var(--font-weight-bold);
|
||||
color: var(--color-text-primary);
|
||||
font-size: 26px;
|
||||
font-weight: 800;
|
||||
color: var(--color-text-heading);
|
||||
}
|
||||
|
||||
.reachability-donut__label {
|
||||
font-size: var(--font-size-xs);
|
||||
font-weight: var(--font-weight-medium);
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--color-text-muted);
|
||||
letter-spacing: 0.08em;
|
||||
color: #6B5A2E;
|
||||
}
|
||||
|
||||
.reachability-legend {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-2);
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.reachability-legend__item {
|
||||
@@ -474,22 +543,33 @@
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.reachability-legend__item--reachable .reachability-legend__dot { background-color: var(--color-severity-high); }
|
||||
.reachability-legend__item--unreachable .reachability-legend__dot { background-color: var(--color-severity-low); }
|
||||
.reachability-legend__item--uncertain .reachability-legend__dot { background-color: var(--color-text-muted); }
|
||||
.reachability-legend__item--reachable .reachability-legend__dot {
|
||||
background-color: #D4920A;
|
||||
box-shadow: 0 0 0 2px rgba(212, 146, 10, 0.2);
|
||||
}
|
||||
.reachability-legend__item--unreachable .reachability-legend__dot {
|
||||
background-color: #059669;
|
||||
box-shadow: 0 0 0 2px rgba(5, 150, 105, 0.2);
|
||||
}
|
||||
.reachability-legend__item--uncertain .reachability-legend__dot {
|
||||
background-color: #6B5A2E;
|
||||
box-shadow: 0 0 0 2px rgba(107, 90, 46, 0.15);
|
||||
}
|
||||
|
||||
.reachability-legend__label {
|
||||
flex: 1;
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #6B5A2E;
|
||||
}
|
||||
|
||||
.reachability-legend__value {
|
||||
font-size: var(--font-size-base);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--color-text-primary);
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: var(--color-text-heading);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -508,27 +588,38 @@
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
padding: 12px 8px;
|
||||
border-radius: 12px;
|
||||
background: linear-gradient(135deg, rgba(254, 243, 226, 0.3), transparent);
|
||||
border: 1px solid hsla(45, 34%, 75%, 0.15);
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(135deg, rgba(254, 243, 226, 0.5), transparent);
|
||||
border-color: hsla(45, 34%, 75%, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.vex-stat__value {
|
||||
font-size: var(--font-size-2xl);
|
||||
font-weight: var(--font-weight-bold);
|
||||
font-size: 24px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.vex-stat--suppressed .vex-stat__value { color: var(--color-severity-low); }
|
||||
.vex-stat--active .vex-stat__value { color: var(--color-severity-high); }
|
||||
.vex-stat--suppressed .vex-stat__value { color: #059669; }
|
||||
.vex-stat--active .vex-stat__value { color: #D4920A; }
|
||||
.vex-stat--investigating .vex-stat__value { color: var(--color-severity-medium); }
|
||||
|
||||
.vex-stat__label {
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--color-text-primary);
|
||||
margin-top: var(--space-1);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: var(--color-text-heading);
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.vex-stat__sublabel {
|
||||
font-size: var(--font-size-xs);
|
||||
color: var(--color-text-muted);
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
color: #6B5A2E;
|
||||
}
|
||||
|
||||
.vex-impact {
|
||||
@@ -536,20 +627,24 @@
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding-top: var(--space-4);
|
||||
border-top: 1px solid var(--color-border-primary);
|
||||
border-top: 1px solid hsla(45, 34%, 75%, 0.2);
|
||||
}
|
||||
|
||||
.vex-impact__percent {
|
||||
font-size: var(--font-size-3xl);
|
||||
font-weight: var(--font-weight-bold);
|
||||
color: var(--color-severity-low);
|
||||
font-size: 32px;
|
||||
font-weight: 800;
|
||||
background: linear-gradient(135deg, #059669, #34d399);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
.vex-impact__label {
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--color-text-muted);
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: #6B5A2E;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -558,13 +653,15 @@
|
||||
|
||||
.quick-actions {
|
||||
margin-bottom: var(--space-8);
|
||||
animation: dash-in 0.5s 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
|
||||
}
|
||||
|
||||
.quick-actions__title {
|
||||
font-size: var(--font-size-md);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--color-text-primary);
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--color-text-heading);
|
||||
margin: 0 0 var(--space-4);
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.quick-actions__grid {
|
||||
@@ -588,24 +685,30 @@
|
||||
gap: var(--space-3);
|
||||
padding: var(--space-5);
|
||||
text-decoration: none;
|
||||
background-color: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-lg);
|
||||
color: var(--color-text-secondary);
|
||||
transition: background-color var(--motion-duration-fast) var(--motion-ease-default),
|
||||
border-color var(--motion-duration-fast) var(--motion-ease-default),
|
||||
color var(--motion-duration-fast) var(--motion-ease-default),
|
||||
transform var(--motion-duration-fast) var(--motion-ease-default);
|
||||
background: #fff;
|
||||
border: 1px solid hsla(45, 34%, 75%, 0.3);
|
||||
border-radius: 14px;
|
||||
color: #6B5A2E;
|
||||
transition: all 0.25s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-surface-secondary);
|
||||
border-color: var(--color-brand-primary);
|
||||
color: var(--color-brand-primary);
|
||||
transform: translateY(-2px);
|
||||
background: linear-gradient(135deg, #FEF3E2, #FFFCF5);
|
||||
border-color: rgba(245, 166, 35, 0.4);
|
||||
color: #D4920A;
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 6px 20px rgba(212, 146, 10, 0.12), 0 2px 6px rgba(0, 0, 0, 0.03);
|
||||
}
|
||||
|
||||
svg {
|
||||
transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
}
|
||||
|
||||
&:hover svg {
|
||||
transform: scale(1.15);
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: var(--font-size-base);
|
||||
font-weight: var(--font-weight-medium);
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,7 @@
|
||||
|
||||
/** Setup wizard step identifiers */
|
||||
export type SetupStepId =
|
||||
| 'welcome'
|
||||
| 'database'
|
||||
| 'cache'
|
||||
| 'migrations'
|
||||
@@ -25,6 +26,7 @@ export type SetupStepId =
|
||||
|
||||
/** Setup step categories */
|
||||
export type SetupCategory =
|
||||
| 'Welcome'
|
||||
| 'Infrastructure'
|
||||
| 'Security'
|
||||
| 'Integration'
|
||||
@@ -981,6 +983,19 @@ export const SOURCES_PROVIDERS: ProviderInfo[] = [
|
||||
|
||||
/** Default step definitions - Infrastructure-First order for CLI/UI parity */
|
||||
export const DEFAULT_SETUP_STEPS: SetupStep[] = [
|
||||
// Phase 0: Welcome
|
||||
{
|
||||
id: 'welcome',
|
||||
name: 'Welcome',
|
||||
description: 'Welcome to Stella Ops — let\u2019s get your platform configured.',
|
||||
category: 'Welcome',
|
||||
order: 0,
|
||||
isRequired: false,
|
||||
isSkippable: false,
|
||||
dependencies: [],
|
||||
validationChecks: [],
|
||||
status: 'pending',
|
||||
},
|
||||
// Phase 1: Core Infrastructure (Required)
|
||||
{
|
||||
id: 'database',
|
||||
@@ -1063,7 +1078,7 @@ export const DEFAULT_SETUP_STEPS: SetupStep[] = [
|
||||
name: 'Secrets Vault',
|
||||
description: 'Configure a secrets vault for secure credential storage (HashiCorp Vault, Azure Key Vault, AWS Secrets Manager, or GCP Secret Manager).',
|
||||
category: 'Integration',
|
||||
order: 60,
|
||||
order: 125,
|
||||
isRequired: false,
|
||||
isSkippable: true,
|
||||
dependencies: [],
|
||||
@@ -1107,9 +1122,9 @@ export const DEFAULT_SETUP_STEPS: SetupStep[] = [
|
||||
{
|
||||
id: 'sources',
|
||||
name: 'Advisory Data Sources',
|
||||
description: 'Configure CVE/VEX advisory feeds (NVD, GHSA, OSV, distribution-specific feeds) for vulnerability data.',
|
||||
description: 'Choose Stella Ops Mirror for pre-aggregated feeds or configure custom advisory sources for CVE/VEX vulnerability data.',
|
||||
category: 'Release Control Plane',
|
||||
order: 90,
|
||||
order: 65,
|
||||
isRequired: false,
|
||||
isSkippable: true,
|
||||
dependencies: [],
|
||||
|
||||
@@ -293,10 +293,11 @@ export class SetupWizardStateService {
|
||||
return;
|
||||
}
|
||||
|
||||
// Can only go forward if all previous steps are completed/skipped
|
||||
// Can only go forward if all previous required steps are completed/skipped
|
||||
// (optional/skippable steps in pending state do not block forward navigation)
|
||||
const canNavigate = this.orderedSteps()
|
||||
.slice(0, stepIndex)
|
||||
.every(s => s.status === 'completed' || s.status === 'skipped');
|
||||
.every(s => s.status === 'completed' || s.status === 'skipped' || s.isSkippable);
|
||||
|
||||
if (canNavigate) {
|
||||
this.currentStepId.set(stepId);
|
||||
@@ -316,14 +317,21 @@ export class SetupWizardStateService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to previous step
|
||||
* Navigate to previous step (skips the welcome step)
|
||||
*/
|
||||
goToPreviousStep(): void {
|
||||
const ordered = this.orderedSteps();
|
||||
const currentIndex = this.currentStepIndex();
|
||||
|
||||
if (currentIndex > 0) {
|
||||
this.currentStepId.set(ordered[currentIndex - 1].id);
|
||||
// Skip back past the welcome step — don't return to it
|
||||
let targetIndex = currentIndex - 1;
|
||||
if (ordered[targetIndex]?.id === 'welcome') {
|
||||
targetIndex--;
|
||||
}
|
||||
if (targetIndex >= 0) {
|
||||
this.currentStepId.set(ordered[targetIndex].id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,7 +565,7 @@ export class SetupWizardStateService {
|
||||
const step = this.currentStep();
|
||||
if (!step) return false;
|
||||
|
||||
// Can proceed if step is completed or skipped
|
||||
return step.status === 'completed' || step.status === 'skipped';
|
||||
// Can proceed if step is completed, skipped, or optional (skippable) and still pending
|
||||
return step.status === 'completed' || step.status === 'skipped' || step.isSkippable;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ import { OverlayHostComponent } from '../overlay-host/overlay-host.component';
|
||||
grid-template-columns: var(--sidebar-width, 200px) 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
min-height: 100vh;
|
||||
background: var(--color-surface-secondary);
|
||||
background: #FFF9ED;
|
||||
}
|
||||
|
||||
.shell--sidebar-collapsed {
|
||||
|
||||
Reference in New Issue
Block a user