Refine failover channel status layout
This commit is contained in:
@@ -8,6 +8,7 @@ data/
|
|||||||
|
|
||||||
# Local roadmap and task workspace
|
# Local roadmap and task workspace
|
||||||
/workpack/
|
/workpack/
|
||||||
|
/design-qa.md
|
||||||
|
|
||||||
# Node/Vite
|
# Node/Vite
|
||||||
node_modules/
|
node_modules/
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export const HARBOR_VERSIONS = Object.freeze({
|
export const HARBOR_VERSIONS = Object.freeze({
|
||||||
macClient: '0.35.0',
|
macClient: '0.35.1',
|
||||||
gatewayClient: '0.37.0',
|
gatewayClient: '0.37.1',
|
||||||
gatewayBackend: '0.37.0',
|
gatewayBackend: '0.37.0',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -482,6 +482,9 @@ export function FailoverPanel({
|
|||||||
const selectedId = channelOptions.find(({ target }) => (
|
const selectedId = channelOptions.find(({ target }) => (
|
||||||
target.profileId === draft[channel].profileId && target.serverId === draft[channel].serverId
|
target.profileId === draft[channel].profileId && target.serverId === draft[channel].serverId
|
||||||
))?.id || '';
|
))?.id || '';
|
||||||
|
const failureProgress = !checking && channel === 'primary' && snapshot.reason === 'failure-window'
|
||||||
|
? `${seconds(Math.max(0, Date.now() - Date.parse(snapshot.primary.stateSince || new Date().toISOString())))} / ${seconds(draft.failureWindowMs)} с`
|
||||||
|
: '';
|
||||||
const healthLabel = missing
|
const healthLabel = missing
|
||||||
? 'Сервер не найден'
|
? 'Сервер не найден'
|
||||||
: !draft.enabled
|
: !draft.enabled
|
||||||
@@ -490,15 +493,20 @@ export function FailoverPanel({
|
|||||||
? 'VPN выключен'
|
? 'VPN выключен'
|
||||||
: snapshot.activation === 'pending'
|
: snapshot.activation === 'pending'
|
||||||
? 'Проверим после запуска VPN'
|
? 'Проверим после запуска VPN'
|
||||||
: channel === 'primary' && snapshot.reason === 'failure-window'
|
: checking
|
||||||
? `Проверяем основной канал · ${seconds(Math.max(0, Date.now() - Date.parse(snapshot.primary.stateSince || new Date().toISOString())))} из ${seconds(draft.failureWindowMs)} с`
|
? `Проверяем ${channel === 'primary' ? 'основной' : 'резервный'} канал`
|
||||||
|
: failureProgress
|
||||||
|
? 'Проверяем основной канал'
|
||||||
: channel === 'primary' && snapshot.currentRole === 'reserve' && health === 'healthy' && snapshot.reason === 'recovery-hold'
|
: channel === 'primary' && snapshot.currentRole === 'reserve' && health === 'healthy' && snapshot.reason === 'recovery-hold'
|
||||||
? 'Проверяем восстановление'
|
? 'Проверяем восстановление'
|
||||||
: health === 'healthy' ? 'Работает' : health === 'unhealthy' ? 'Недоступен' : health === 'not-monitoring' ? 'Проверка выключена' : 'Ждёт проверки';
|
: health === 'healthy' ? 'Работает' : health === 'unhealthy' ? 'Недоступен' : health === 'not-monitoring' ? 'Проверка выключена' : 'Ждёт проверки';
|
||||||
return <div className="client-failover-channel-slot" key={channel}><article className="client-failover-channel" data-channel={channel}>
|
return <div className="client-failover-channel-slot" key={channel}><article className="client-failover-channel" data-channel={channel}>
|
||||||
<div className="client-failover-channel-title">
|
<div className="client-failover-channel-title">
|
||||||
<h3>{channel === 'primary' ? 'Основной' : 'Резервный'}</h3>
|
<h3>{channel === 'primary' ? 'Основной' : 'Резервный'}</h3>
|
||||||
<strong className={health === 'healthy' ? 'is-healthy' : health === 'unhealthy' || missing ? 'is-unhealthy' : ''}>{healthLabel}</strong>
|
</div>
|
||||||
|
<div className="client-failover-channel-status">
|
||||||
|
<strong className={healthLabel === 'Работает' ? 'is-healthy' : healthLabel === 'Недоступен' || missing ? 'is-unhealthy' : ''}>{healthLabel}</strong>
|
||||||
|
<span className="client-failover-channel-progress">{failureProgress}</span>
|
||||||
</div>
|
</div>
|
||||||
<FailoverPicker
|
<FailoverPicker
|
||||||
id={`client-failover-${channel}-options`}
|
id={`client-failover-${channel}-options`}
|
||||||
@@ -510,9 +518,6 @@ export function FailoverPanel({
|
|||||||
onOpenChange={(open) => setOpenPicker(open ? channel : '')}
|
onOpenChange={(open) => setOpenPicker(open ? channel : '')}
|
||||||
onChange={(optionId) => updateTarget(channel, optionId)}
|
onChange={(optionId) => updateTarget(channel, optionId)}
|
||||||
/>
|
/>
|
||||||
<span className={`client-failover-channel-checking${checking ? ' is-visible' : ''}`} aria-hidden="true">
|
|
||||||
Проверяем {channel === 'primary' ? 'основной' : 'резервный'} канал
|
|
||||||
</span>
|
|
||||||
</article>{channel === 'primary' && <div className="client-failover-channel-actions" aria-label="Действия с каналами">
|
</article>{channel === 'primary' && <div className="client-failover-channel-actions" aria-label="Действия с каналами">
|
||||||
<button
|
<button
|
||||||
className={`client-failover-check-action client-tooltip-anchor${checking ? ' is-running' : ''}`}
|
className={`client-failover-check-action client-tooltip-anchor${checking ? ' is-running' : ''}`}
|
||||||
|
|||||||
@@ -20,16 +20,16 @@
|
|||||||
.client-failover-channels { display: grid; grid-template-columns: minmax(0, 1fr) 52px minmax(0, 1fr); gap: 12px; }
|
.client-failover-channels { display: grid; grid-template-columns: minmax(0, 1fr) 52px minmax(0, 1fr); gap: 12px; }
|
||||||
.client-failover-channel-slot { display: contents; }
|
.client-failover-channel-slot { display: contents; }
|
||||||
.client-failover-channel { position: relative; display: grid; align-content: start; gap: 7px; min-width: 0; }
|
.client-failover-channel { position: relative; display: grid; align-content: start; gap: 7px; min-width: 0; }
|
||||||
.client-failover-channel-title { min-height: 24px; display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
|
.client-failover-channel-title { min-height: 24px; }
|
||||||
.client-failover-channel-title h3 { margin: 0; font: var(--type-data); font-variant-numeric: var(--numeric-tabular); letter-spacing: var(--type-data-tracking); text-transform: var(--type-data-transform); }
|
.client-failover-channel-title h3 { margin: 0; font: var(--type-data); font-variant-numeric: var(--numeric-tabular); letter-spacing: var(--type-data-tracking); text-transform: var(--type-data-transform); }
|
||||||
.client-failover-channel[data-channel='primary'] .client-failover-channel-title h3 { color: var(--harbor-connect); text-shadow: 0 0 9px color-mix(in oklch, var(--harbor-connect) 30%, transparent); }
|
.client-failover-channel[data-channel='primary'] .client-failover-channel-title h3 { color: var(--harbor-connect); text-shadow: 0 0 9px color-mix(in oklch, var(--harbor-connect) 30%, transparent); }
|
||||||
.client-failover-channel[data-channel='reserve'] .client-failover-channel-title h3 { color: var(--harbor-gateway); text-shadow: 0 0 9px color-mix(in oklch, var(--harbor-gateway) 30%, transparent); }
|
.client-failover-channel[data-channel='reserve'] .client-failover-channel-title h3 { color: var(--harbor-gateway); text-shadow: 0 0 9px color-mix(in oklch, var(--harbor-gateway) 30%, transparent); }
|
||||||
.client-failover-channel-title strong { min-width: 0; color: var(--client-muted); font: var(--type-control); letter-spacing: var(--type-control-tracking); text-transform: var(--type-control-transform); text-align: right; white-space: nowrap; transition: color 600ms ease, filter 600ms ease; }
|
.client-failover-channel-status { min-height: 32px; display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: repeat(2, minmax(0, 1fr)); align-items: baseline; color: var(--client-muted); font: var(--type-control); letter-spacing: var(--type-control-tracking); text-transform: var(--type-control-transform); }
|
||||||
.client-failover-channel-title strong.is-healthy { color: var(--client-accent); }
|
.client-failover-channel-status strong { min-width: 0; white-space: nowrap; transition: color 600ms ease, filter 600ms ease; }
|
||||||
.client-failover-channel-title strong.is-unhealthy { color: oklch(0.68 0.15 28); }
|
.client-failover-channel-status strong.is-healthy { color: var(--client-accent); }
|
||||||
|
.client-failover-channel-status strong.is-unhealthy { color: oklch(0.68 0.15 28); }
|
||||||
|
.client-failover-channel-progress { min-width: 0; font-variant-numeric: var(--numeric-tabular); text-align: left; white-space: nowrap; }
|
||||||
.client-failover-picker { position: relative; min-width: 0; z-index: 1; }
|
.client-failover-picker { position: relative; min-width: 0; z-index: 1; }
|
||||||
.client-failover-channel-checking { min-height: 16px; color: var(--client-muted); font: var(--type-control); letter-spacing: var(--type-control-tracking); text-transform: var(--type-control-transform); opacity: 0; visibility: hidden; transition: opacity 180ms ease; }
|
|
||||||
.client-failover-channel-checking.is-visible { opacity: 1; visibility: visible; }
|
|
||||||
.client-failover-channel-actions { grid-column: 2; grid-row: 1; min-height: 66px; display: grid; place-content: center; gap: 2px; }
|
.client-failover-channel-actions { grid-column: 2; grid-row: 1; min-height: 66px; display: grid; place-content: center; gap: 2px; }
|
||||||
.client-failover-check-action, .client-failover-direction-action { width: 44px; height: 44px; display: grid; place-items: center; padding: 0; border: 0; background: transparent; color: var(--client-accent); cursor: pointer; }
|
.client-failover-check-action, .client-failover-direction-action { width: 44px; height: 44px; display: grid; place-items: center; padding: 0; border: 0; background: transparent; color: var(--client-accent); cursor: pointer; }
|
||||||
.client-failover-direction-action.is-primary { color: var(--harbor-connect); }
|
.client-failover-direction-action.is-primary { color: var(--harbor-connect); }
|
||||||
@@ -101,5 +101,6 @@
|
|||||||
.client-failover-number-input:focus-visible { outline: 0; color: var(--client-accent); text-shadow: 0 0 9px color-mix(in oklch, var(--client-accent) 38%, transparent); }
|
.client-failover-number-input:focus-visible { outline: 0; color: var(--client-accent); text-shadow: 0 0 9px color-mix(in oklch, var(--client-accent) 38%, transparent); }
|
||||||
@keyframes failover-service-in { from { opacity: 0; filter: blur(5px); transform: translateY(-4px); } to { opacity: 1; filter: blur(0); transform: translateY(0); } }
|
@keyframes failover-service-in { from { opacity: 0; filter: blur(5px); transform: translateY(-4px); } to { opacity: 1; filter: blur(0); transform: translateY(0); } }
|
||||||
@keyframes failover-service-out { from { opacity: 1; filter: blur(0); transform: translateX(0) scale(1); } to { opacity: 0; filter: blur(6px); transform: translateX(16px) scale(.96); } }
|
@keyframes failover-service-out { from { opacity: 1; filter: blur(0); transform: translateX(0) scale(1); } to { opacity: 0; filter: blur(6px); transform: translateX(16px) scale(.96); } }
|
||||||
@media (max-width: 560px) { .client-failover-heading { align-items: flex-start; flex-wrap: wrap; } .client-failover-heading > h2 { min-width: 0; flex: 1 1 auto; } .client-failover-header-actions { flex: 1 1 100%; justify-content: flex-start; gap: 4px 10px; } .client-failover-channels { grid-template-columns: minmax(0, 1fr); gap: 12px; } .client-failover-channel-actions { grid-column: 1; grid-row: auto; min-height: 44px; display: flex; justify-content: center; gap: 8px; } .client-failover-service { grid-template-columns: minmax(0, 1fr) 32px; gap: 6px 10px; } .client-failover-service > .client-failover-number-setting { grid-column: 1; grid-row: 2; } .client-failover-remove-service { grid-column: 2; grid-row: 1 / span 2; } .client-failover-service-editor { grid-template-columns: 1fr; gap: 2px; } }
|
@media (max-width: 680px) { .client-failover-channels { grid-template-columns: minmax(0, 1fr); gap: 12px; } .client-failover-channel-actions { grid-column: 1; grid-row: auto; min-height: 44px; display: flex; justify-content: center; gap: 8px; } }
|
||||||
@media (prefers-reduced-motion: reduce) { .client-failover-channel-title strong, .client-failover-channel-checking, .client-failover-switch::before, .client-failover-switch > span, .client-failover-picker-trigger, .client-failover-picker-trigger::before, .client-failover-picker-trigger svg, .client-failover-picker-list, .client-failover-picker-list button, .client-failover-number-steps, .client-failover-number-control:hover .client-failover-number-steps, .client-failover-number-control:focus-within .client-failover-number-steps, .client-failover-remove-service, .client-failover-remove-lid, .client-failover-direction-action svg { transition: none; } .client-failover-check-action.is-running svg { animation: none; } .client-failover-service, .client-failover-service-editor { animation: none; } }
|
@media (max-width: 560px) { .client-failover-heading { align-items: flex-start; flex-wrap: wrap; } .client-failover-heading > h2 { min-width: 0; flex: 1 1 auto; } .client-failover-header-actions { flex: 1 1 100%; justify-content: flex-start; gap: 4px 10px; } .client-failover-service { grid-template-columns: minmax(0, 1fr) 32px; gap: 6px 10px; } .client-failover-service > .client-failover-number-setting { grid-column: 1; grid-row: 2; } .client-failover-remove-service { grid-column: 2; grid-row: 1 / span 2; } .client-failover-service-editor { grid-template-columns: 1fr; gap: 2px; } }
|
||||||
|
@media (prefers-reduced-motion: reduce) { .client-failover-channel-status strong, .client-failover-switch::before, .client-failover-switch > span, .client-failover-picker-trigger, .client-failover-picker-trigger::before, .client-failover-picker-trigger svg, .client-failover-picker-list, .client-failover-picker-list button, .client-failover-number-steps, .client-failover-number-control:hover .client-failover-number-steps, .client-failover-number-control:focus-within .client-failover-number-steps, .client-failover-remove-service, .client-failover-remove-lid, .client-failover-direction-action svg { transition: none; } .client-failover-check-action.is-running svg { animation: none; } .client-failover-service, .client-failover-service-editor { animation: none; } }
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ test('failover settings use Harbor switches, a two-column channel table and plai
|
|||||||
assert.match(feature, /\['primary', 'reserve'\][\s\S]*client-failover-\$\{channel\}-options[\s\S]*updateTarget\(channel, optionId\)/);
|
assert.match(feature, /\['primary', 'reserve'\][\s\S]*client-failover-\$\{channel\}-options[\s\S]*updateTarget\(channel, optionId\)/);
|
||||||
assert.match(feature, /channelLabel[\s\S]*profile\.trim\(\) === server\.trim\(\)[\s\S]*`\$\{profile} · \$\{server}`/);
|
assert.match(feature, /channelLabel[\s\S]*profile\.trim\(\) === server\.trim\(\)[\s\S]*`\$\{profile} · \$\{server}`/);
|
||||||
assert.match(feature, /client-failover-channels[\s\S]*<article className="client-failover-channel"[\s\S]*<h3>\{channel === 'primary' \? 'Основной' : 'Резервный'}/);
|
assert.match(feature, /client-failover-channels[\s\S]*<article className="client-failover-channel"[\s\S]*<h3>\{channel === 'primary' \? 'Основной' : 'Резервный'}/);
|
||||||
assert.match(feature, /client-failover-channel-checking[\s\S]*Проверяем \{channel === 'primary' \? 'основной' : 'резервный'} канал/);
|
assert.match(feature, /client-failover-channel-status[\s\S]*client-failover-channel-progress/);
|
||||||
|
assert.match(feature, /checking[\s\S]*`Проверяем \$\{channel === 'primary' \? 'основной' : 'резервный'\} канал`/);
|
||||||
assert.match(feature, /client-live-region[\s\S]*Проверяем основной и резервный каналы/);
|
assert.match(feature, /client-live-region[\s\S]*Проверяем основной и резервный каналы/);
|
||||||
assert.match(feature, /ArrowDown[\s\S]*Home[\s\S]*End[\s\S]*Escape/);
|
assert.match(feature, /ArrowDown[\s\S]*Home[\s\S]*End[\s\S]*Escape/);
|
||||||
assert.match(feature, /role="listbox"[\s\S]*role="option"/);
|
assert.match(feature, /role="listbox"[\s\S]*role="option"/);
|
||||||
@@ -76,7 +77,7 @@ test('failover settings use Harbor switches, a two-column channel table and plai
|
|||||||
assert.match(styles, /\.client-failover-channels \{[^}]*grid-template-columns:\s*minmax\(0, 1fr\) 52px minmax\(0, 1fr\)/);
|
assert.match(styles, /\.client-failover-channels \{[^}]*grid-template-columns:\s*minmax\(0, 1fr\) 52px minmax\(0, 1fr\)/);
|
||||||
assert.match(styles, /\.client-failover-channel-actions \{[^}]*grid-column:\s*2[^}]*grid-row:\s*1/);
|
assert.match(styles, /\.client-failover-channel-actions \{[^}]*grid-column:\s*2[^}]*grid-row:\s*1/);
|
||||||
assert.match(styles, /\.client-failover-check-action, \.client-failover-direction-action \{[^}]*width:\s*44px[^}]*height:\s*44px/);
|
assert.match(styles, /\.client-failover-check-action, \.client-failover-direction-action \{[^}]*width:\s*44px[^}]*height:\s*44px/);
|
||||||
assert.match(styles, /@media \(max-width: 560px\)[\s\S]*\.client-failover-channels \{ grid-template-columns:\s*minmax\(0, 1fr\)/);
|
assert.match(styles, /@media \(max-width: 680px\)[\s\S]*\.client-failover-channels \{ grid-template-columns:\s*minmax\(0, 1fr\)/);
|
||||||
assert.match(styles, /\.client-failover-picker-list[\s\S]*opacity:\s*0[\s\S]*\.client-failover-picker\.is-open[\s\S]*opacity:\s*1/);
|
assert.match(styles, /\.client-failover-picker-list[\s\S]*opacity:\s*0[\s\S]*\.client-failover-picker\.is-open[\s\S]*opacity:\s*1/);
|
||||||
assert.match(styles, /failover-service-out 300ms[\s\S]*@media \(prefers-reduced-motion: reduce\)/);
|
assert.match(styles, /failover-service-out 300ms[\s\S]*@media \(prefers-reduced-motion: reduce\)/);
|
||||||
assert.match(styles, /\.client-failover-number-setting \{[^}]*display:\s*flex[^}]*flex-wrap:\s*wrap/);
|
assert.match(styles, /\.client-failover-number-setting \{[^}]*display:\s*flex[^}]*flex-wrap:\s*wrap/);
|
||||||
@@ -92,13 +93,15 @@ test('failover settings use Harbor switches, a two-column channel table and plai
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('active channel and checks stay attached to their channel columns without a duplicate runtime block', () => {
|
test('active channel and checks stay attached to their channel columns without a duplicate runtime block', () => {
|
||||||
assert.match(feature, /Проверяем основной канал ·/);
|
assert.match(feature, /failureProgress[\s\S]*`\$\{seconds\([\s\S]*\)} \/ \$\{seconds\(draft\.failureWindowMs\)} с`/);
|
||||||
|
assert.match(feature, /failureProgress[\s\S]*'Проверяем основной канал'/);
|
||||||
assert.match(feature, /client-failover-direction-action[\s\S]*disabled=\{blocked \|\| !snapshot.enabled \|\| snapshot.activation !== 'active' \|\| !switchRole\}/);
|
assert.match(feature, /client-failover-direction-action[\s\S]*disabled=\{blocked \|\| !snapshot.enabled \|\| snapshot.activation !== 'active' \|\| !switchRole\}/);
|
||||||
assert.match(feature, /className=\{`client-failover-direction-action client-tooltip-anchor\$\{role === 'primary'[\s\S]*role === 'reserve'/);
|
assert.match(feature, /className=\{`client-failover-direction-action client-tooltip-anchor\$\{role === 'primary'[\s\S]*role === 'reserve'/);
|
||||||
assert.match(feature, /<svg className=\{role === 'primary' \? 'is-primary' : role === 'reserve' \? 'is-reserve' : undefined\}/);
|
assert.match(feature, /<svg className=\{role === 'primary' \? 'is-primary' : role === 'reserve' \? 'is-reserve' : undefined\}/);
|
||||||
assert.doesNotMatch(feature, /client-failover-runtime|Сейчас используется|Новые подключения:/);
|
assert.doesNotMatch(feature, /client-failover-runtime|Сейчас используется|Новые подключения:/);
|
||||||
|
assert.doesNotMatch(feature, /client-failover-channel-checking/);
|
||||||
assert.doesNotMatch(styles, /\.client-failover-runtime/);
|
assert.doesNotMatch(styles, /\.client-failover-runtime/);
|
||||||
assert.match(styles, /\.client-failover-channel-checking \{[^}]*min-height:\s*16px[^}]*opacity:\s*0[^}]*visibility:\s*hidden/);
|
assert.match(styles, /\.client-failover-channel-status \{[^}]*min-height:\s*32px[^}]*grid-template-columns:\s*minmax\(0, 1fr\)[^}]*grid-template-rows:\s*repeat\(2, minmax\(0, 1fr\)\)/);
|
||||||
assert.match(styles, /\.client-failover-channel-checking\.is-visible \{[^}]*opacity:\s*1[^}]*visibility:\s*visible/);
|
assert.match(styles, /\.client-failover-channel-progress \{[^}]*min-width:\s*0[^}]*text-align:\s*left/);
|
||||||
assert.match(styles, /@media \(prefers-reduced-motion: reduce\)[^{]*\{[^}]*\.client-failover-number-control:hover \.client-failover-number-steps[^}]*transition:\s*none/);
|
assert.match(styles, /@media \(prefers-reduced-motion: reduce\)[^{]*\{[^}]*\.client-failover-number-control:hover \.client-failover-number-steps[^}]*transition:\s*none/);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -104,7 +104,8 @@ test('tablet and mobile regions use normal flow with viewport-safe widths', () =
|
|||||||
assert.match(mobile, /\.client-secondary-menu \{[\s\S]*right:\s*8px/);
|
assert.match(mobile, /\.client-secondary-menu \{[\s\S]*right:\s*8px/);
|
||||||
assert.match(mobile, /\.client-power-control > \.harbor-brand \{[\s\S]*scale\(1\.35\)/);
|
assert.match(mobile, /\.client-power-control > \.harbor-brand \{[\s\S]*scale\(1\.35\)/);
|
||||||
assert.match(mobile, /\.client-server-check \{[\s\S]*width:\s*44px/);
|
assert.match(mobile, /\.client-server-check \{[\s\S]*width:\s*44px/);
|
||||||
assert.match(styles, /@media \(max-width: 560px\)[\s\S]*\.client-failover-heading \{[\s\S]*flex-wrap:\s*wrap[\s\S]*\.client-failover-channel-actions \{[\s\S]*grid-column:\s*1[\s\S]*grid-row:\s*auto[\s\S]*display:\s*flex[\s\S]*justify-content:\s*center/);
|
assert.match(styles, /@media \(max-width: 560px\)[\s\S]*\.client-failover-heading \{[\s\S]*flex-wrap:\s*wrap/);
|
||||||
|
assert.match(styles, /@media \(max-width: 680px\)[\s\S]*\.client-failover-channel-actions \{[\s\S]*grid-column:\s*1[\s\S]*grid-row:\s*auto[\s\S]*display:\s*flex[\s\S]*justify-content:\s*center/);
|
||||||
assert.match(styles, /\.client-failover-channel-actions \{[^}]*grid-column:\s*2[^}]*display:\s*grid/);
|
assert.match(styles, /\.client-failover-channel-actions \{[^}]*grid-column:\s*2[^}]*display:\s*grid/);
|
||||||
assert.match(rule('.client-drawer'), /width:\s*min\(580px, 100vw\)/);
|
assert.match(rule('.client-drawer'), /width:\s*min\(580px, 100vw\)/);
|
||||||
assert.match(styles, /\.client-confirmation-dialog\s*\{[\s\S]*width:\s*min\(430px, calc\(100vw - 48px\)\)/);
|
assert.match(styles, /\.client-confirmation-dialog\s*\{[\s\S]*width:\s*min\(430px, calc\(100vw - 48px\)\)/);
|
||||||
|
|||||||
@@ -40,26 +40,26 @@ const expectedImports = [
|
|||||||
const sha256 = (value) => crypto.createHash('sha256').update(value).digest('hex');
|
const sha256 = (value) => crypto.createHash('sha256').update(value).digest('hex');
|
||||||
const acceptedLedger = {
|
const acceptedLedger = {
|
||||||
counts: {
|
counts: {
|
||||||
cascadeEdges: 1164,
|
cascadeEdges: 1163,
|
||||||
customProperties: 115,
|
customProperties: 115,
|
||||||
declarations: 4752,
|
declarations: 4746,
|
||||||
important: 0,
|
important: 0,
|
||||||
keyframes: 55,
|
keyframes: 55,
|
||||||
media: 22,
|
media: 23,
|
||||||
rules: 1288,
|
rules: 1288,
|
||||||
variableReferences: 1240,
|
variableReferences: 1237,
|
||||||
},
|
},
|
||||||
hashes: {
|
hashes: {
|
||||||
cascadeEdges: 'e71264f527a1a7ec77ce9c382cc8b99e7363a379d258b5feb418ec591901b0aa',
|
cascadeEdges: 'c1b3eaa3d0ad08e3393cf90878f90e17a5401d79eed9072d06f39b7841d8bbfd',
|
||||||
customProperties: '81d1e70737ae5a8e4b20d4c1be1b24685975a404863444da4a8821be1f0d5097',
|
customProperties: '81d1e70737ae5a8e4b20d4c1be1b24685975a404863444da4a8821be1f0d5097',
|
||||||
declarations: 'bb96f5466d6717eb2e54ef620a275f510ac41a99c3dc282b221fabac5e96e2fb',
|
declarations: 'e668191e548093c02463e57b81eb6c12b826991a5e10f5191d87b73e682cd852',
|
||||||
duplicateKeyframes: '4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945',
|
duplicateKeyframes: '4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945',
|
||||||
duplicateSelectors: '8982145dba05b33bf1c93b2d54cfbe76305b276ff3c657aa020144016ada5848',
|
duplicateSelectors: '8982145dba05b33bf1c93b2d54cfbe76305b276ff3c657aa020144016ada5848',
|
||||||
keyframes: 'b9b0bf3fad92e69b93ec0c24f01da15e78bbe89a095597d64ce4f7ef5e272fdd',
|
keyframes: 'b9b0bf3fad92e69b93ec0c24f01da15e78bbe89a095597d64ce4f7ef5e272fdd',
|
||||||
ruleDeclarationSequences: 'f55ebc3544ddae34b1ed9aaba85fd4336d0e0722c7b986f6a42aafeb0f9abe3c',
|
ruleDeclarationSequences: '2cc97550fecd8bbf46217dc378cc490fd41d977abcdcc4c93a18c7593ba42f53',
|
||||||
selectors: '5be446ae824d5d9adfe912fdefe3220c0bc1b26ad6faa2306d399a9f416a03e4',
|
selectors: 'c7f4752d81bbeb04612eb6c79a42bcde875c762d81591b2cdf2fb2bbd7399ea2',
|
||||||
variableReferences: 'f8e1ec8c81d9890880a177a283b04222c34132719e0d954d3e1944a50ebcdb2e',
|
variableReferences: '69c03c059f9ce107bc8be0397cff90e1b8b3749b8e37ba8e231e2d6cdcd61e46',
|
||||||
witnesses: '783115d6bfe4955d195d2fa8fdc5dc602903a19fdf666f89fe4938bd47bb208a',
|
witnesses: '99713805eb7a5c67427ace32775f0cc503b3b2ac63240db717e71b36d09ddd68',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -212,7 +212,7 @@ test('client typography uses the shared semantic scale outside the token owner',
|
|||||||
|
|
||||||
test('accepted stylesheet has pinned declaration, selector, keyframe, variable, and cascade ledgers', () => {
|
test('accepted stylesheet has pinned declaration, selector, keyframe, variable, and cascade ledgers', () => {
|
||||||
const witnesses = readStyleWitnesses(root);
|
const witnesses = readStyleWitnesses(root);
|
||||||
assert.equal(witnesses.length, 1311);
|
assert.equal(witnesses.length, 1312);
|
||||||
assert.equal(witnesses.filter((witness) => witness.unknown || witness.ancestorUnknown).length, 0);
|
assert.equal(witnesses.filter((witness) => witness.unknown || witness.ancestorUnknown).length, 0);
|
||||||
const ledger = createStyleLedger(readStyleSource(root), { witnesses });
|
const ledger = createStyleLedger(readStyleSource(root), { witnesses });
|
||||||
assert.deepEqual(ledger.counts, acceptedLedger.counts);
|
assert.deepEqual(ledger.counts, acceptedLedger.counts);
|
||||||
@@ -409,8 +409,8 @@ test('main owns one public stylesheet and the regrouped production CSS is determ
|
|||||||
assert.equal((main.match(/import ['"][^'"]+\.css['"]/g) || []).length, 1);
|
assert.equal((main.match(/import ['"][^'"]+\.css['"]/g) || []).length, 1);
|
||||||
|
|
||||||
const assets = fs.readdirSync(path.join(root, 'dist/assets')).filter((file) => file.endsWith('.css'));
|
const assets = fs.readdirSync(path.join(root, 'dist/assets')).filter((file) => file.endsWith('.css'));
|
||||||
assert.deepEqual(assets, ['index--AY5M9TT.css']);
|
assert.deepEqual(assets, ['index-BLRRtFYh.css']);
|
||||||
const built = fs.readFileSync(path.join(root, 'dist/assets', assets[0]));
|
const built = fs.readFileSync(path.join(root, 'dist/assets', assets[0]));
|
||||||
assert.equal(built.byteLength, 180764);
|
assert.equal(built.byteLength, 180634);
|
||||||
assert.equal(sha256(built), 'e36629a671854f92641bd0dfefd796336adc54e026604ef39d8389daa418beac');
|
assert.equal(sha256(built), '6bf3cb9c724758de39567c606c939e6041edde82837f826e8d2d4e31ebd1d8a8');
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user