Fix profile server selection activation state
This commit is contained in:
@@ -199,11 +199,16 @@ export function createSubscriptionService(dependencies: SubscriptionServiceDepen
|
|||||||
if (!profile.servers.some((server) => server.id === serverId)) {
|
if (!profile.servers.some((server) => server.id === serverId)) {
|
||||||
throw new HarborError('SERVER_NOT_FOUND');
|
throw new HarborError('SERVER_NOT_FOUND');
|
||||||
}
|
}
|
||||||
if (profile.desiredServerId === serverId) return mutationResult(profile);
|
if (profile.desiredServerId === serverId && state.desiredProfileId === profile.id) {
|
||||||
const selected = { ...profile, desiredServerId: serverId };
|
return mutationResult(profile);
|
||||||
|
}
|
||||||
|
const selected = profile.desiredServerId === serverId
|
||||||
|
? profile
|
||||||
|
: { ...profile, desiredServerId: serverId };
|
||||||
dependencies.state.update((current) => ({
|
dependencies.state.update((current) => ({
|
||||||
...current,
|
...current,
|
||||||
profiles: replaceProfile(current, selected),
|
profiles: replaceProfile(current, selected),
|
||||||
|
desiredProfileId: profile.id,
|
||||||
}));
|
}));
|
||||||
return mutationResult(selected);
|
return mutationResult(selected);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export const HARBOR_VERSIONS = Object.freeze({
|
export const HARBOR_VERSIONS = Object.freeze({
|
||||||
macClient: '0.23.11',
|
macClient: '0.24.0',
|
||||||
gatewayClient: '0.24.11',
|
gatewayClient: '0.25.0',
|
||||||
gatewayBackend: '0.24.0',
|
gatewayBackend: '0.25.0',
|
||||||
});
|
});
|
||||||
|
|
||||||
export interface ParsedVersion {
|
export interface ParsedVersion {
|
||||||
|
|||||||
@@ -255,13 +255,6 @@ export function App() {
|
|||||||
`${profileId}:${serverId}`,
|
`${profileId}:${serverId}`,
|
||||||
profileId,
|
profileId,
|
||||||
)}
|
)}
|
||||||
onActivateProfile={(profileId: string) => run(
|
|
||||||
'profileActivate',
|
|
||||||
() => api.profiles.activate(profileId, revisionRef.current),
|
|
||||||
'connection',
|
|
||||||
profileId,
|
|
||||||
profileId,
|
|
||||||
)}
|
|
||||||
onRefreshProfile={(profileId: string) => run(
|
onRefreshProfile={(profileId: string) => run(
|
||||||
'profileRefresh',
|
'profileRefresh',
|
||||||
() => api.profiles.refresh(profileId, revisionRef.current),
|
() => api.profiles.refresh(profileId, revisionRef.current),
|
||||||
|
|||||||
@@ -105,7 +105,6 @@ interface ClientOverviewPageProps {
|
|||||||
error: UiError | null;
|
error: UiError | null;
|
||||||
onAddProfile: (label: string, url: string) => Promise<unknown>;
|
onAddProfile: (label: string, url: string) => Promise<unknown>;
|
||||||
onSelectProfileServer: (profileId: string, serverId: string) => Promise<unknown>;
|
onSelectProfileServer: (profileId: string, serverId: string) => Promise<unknown>;
|
||||||
onActivateProfile: (profileId: string) => Promise<unknown>;
|
|
||||||
onRefreshProfile: (profileId: string) => Promise<unknown>;
|
onRefreshProfile: (profileId: string) => Promise<unknown>;
|
||||||
onForgetProfile: (profileId: string, mode: 'delete' | 'stop-and-delete') => Promise<unknown>;
|
onForgetProfile: (profileId: string, mode: 'delete' | 'stop-and-delete') => Promise<unknown>;
|
||||||
onApply: (profileId: string, serverId: string) => Promise<unknown>;
|
onApply: (profileId: string, serverId: string) => Promise<unknown>;
|
||||||
@@ -411,7 +410,6 @@ export function ClientOverviewPage({
|
|||||||
error,
|
error,
|
||||||
onAddProfile,
|
onAddProfile,
|
||||||
onSelectProfileServer,
|
onSelectProfileServer,
|
||||||
onActivateProfile,
|
|
||||||
onRefreshProfile,
|
onRefreshProfile,
|
||||||
onForgetProfile,
|
onForgetProfile,
|
||||||
onApply,
|
onApply,
|
||||||
@@ -494,7 +492,6 @@ export function ClientOverviewPage({
|
|||||||
onAdd: onAddProfile,
|
onAdd: onAddProfile,
|
||||||
onRefresh: onRefreshProfile,
|
onRefresh: onRefreshProfile,
|
||||||
onForget: onForgetProfile,
|
onForget: onForgetProfile,
|
||||||
onActivate: onActivateProfile,
|
|
||||||
onDismissError,
|
onDismissError,
|
||||||
});
|
});
|
||||||
const routingFeature = useRoutingFeature({
|
const routingFeature = useRoutingFeature({
|
||||||
@@ -553,7 +550,7 @@ export function ClientOverviewPage({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
function selectServer(profile: ProfileSnapshot, serverId: string) {
|
function selectServer(profile: ProfileSnapshot, serverId: string) {
|
||||||
if (connected && !gatewayDirect && state.selection.appliedProfileId === profile.id) {
|
if (connected && !gatewayDirect) {
|
||||||
onApply(profile.id, serverId);
|
onApply(profile.id, serverId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -723,9 +720,9 @@ export function ClientOverviewPage({
|
|||||||
profileId={profile.id}
|
profileId={profile.id}
|
||||||
pingServers={actions.pingServers}
|
pingServers={actions.pingServers}
|
||||||
servers={profile.servers}
|
servers={profile.servers}
|
||||||
selectedServerId={profile.desiredServerId}
|
selectedServerId={pickerState.selectedServerId}
|
||||||
disabled={serverApplyBlocked || pickerState.disabled}
|
disabled={serverApplyBlocked || pickerState.disabled}
|
||||||
prompt={!profile.desiredServerId}
|
prompt={!pickerState.selectedServerId}
|
||||||
leaving={pickerState.leaving}
|
leaving={pickerState.leaving}
|
||||||
revealVersion={pickerState.revealVersion}
|
revealVersion={pickerState.revealVersion}
|
||||||
anchorServerId={pickerState.anchorServerId}
|
anchorServerId={pickerState.anchorServerId}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ interface ServerPickerRenderState {
|
|||||||
leaving: boolean;
|
leaving: boolean;
|
||||||
revealVersion: number;
|
revealVersion: number;
|
||||||
anchorServerId: string;
|
anchorServerId: string;
|
||||||
|
selectedServerId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SubscriptionFeatureOptions {
|
interface SubscriptionFeatureOptions {
|
||||||
@@ -45,7 +46,6 @@ interface SubscriptionFeatureOptions {
|
|||||||
onAdd: (label: string, url: string) => Promise<unknown>;
|
onAdd: (label: string, url: string) => Promise<unknown>;
|
||||||
onRefresh: (profileId: string) => Promise<unknown>;
|
onRefresh: (profileId: string) => Promise<unknown>;
|
||||||
onForget: (profileId: string, mode: 'delete' | 'stop-and-delete') => Promise<unknown>;
|
onForget: (profileId: string, mode: 'delete' | 'stop-and-delete') => Promise<unknown>;
|
||||||
onActivate: (profileId: string) => Promise<unknown>;
|
|
||||||
onDismissError: () => void;
|
onDismissError: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +64,6 @@ export function useSubscriptionFeature({
|
|||||||
onAdd,
|
onAdd,
|
||||||
onRefresh,
|
onRefresh,
|
||||||
onForget,
|
onForget,
|
||||||
onActivate,
|
|
||||||
onDismissError,
|
onDismissError,
|
||||||
}: SubscriptionFeatureOptions) {
|
}: SubscriptionFeatureOptions) {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
@@ -281,7 +280,6 @@ export function useSubscriptionFeature({
|
|||||||
addBlocked: operationBlocked(operations, 'profileAdd'),
|
addBlocked: operationBlocked(operations, 'profileAdd'),
|
||||||
refreshBlocked: operationBlocked(operations, 'profileRefresh'),
|
refreshBlocked: operationBlocked(operations, 'profileRefresh'),
|
||||||
deleteBlocked: operationBlocked(operations, 'profileDelete'),
|
deleteBlocked: operationBlocked(operations, 'profileDelete'),
|
||||||
activateBlocked: operationBlocked(operations, 'profileActivate'),
|
|
||||||
toggle: () => setOpen((current) => !current),
|
toggle: () => setOpen((current) => !current),
|
||||||
close: () => setOpen(false),
|
close: () => setOpen(false),
|
||||||
showAdd,
|
showAdd,
|
||||||
@@ -296,7 +294,6 @@ export function useSubscriptionFeature({
|
|||||||
cancelDelete: () => setDeleteId(''),
|
cancelDelete: () => setDeleteId(''),
|
||||||
confirmDelete,
|
confirmDelete,
|
||||||
refresh,
|
refresh,
|
||||||
onActivate,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,8 +391,9 @@ function ProfileGroup({
|
|||||||
const refreshing = feature.refreshingIds.includes(profile.id)
|
const refreshing = feature.refreshingIds.includes(profile.id)
|
||||||
|| feature.operations.profileRefresh?.target === profile.id;
|
|| feature.operations.profileRefresh?.target === profile.id;
|
||||||
const controlsBlocked = operationBlocked(feature.operations, 'profileSelect');
|
const controlsBlocked = operationBlocked(feature.operations, 'profileSelect');
|
||||||
const selectedServer = profileServer(profile, profile.desiredServerId);
|
const visibleServerId = applied
|
||||||
const visibleServerId = applied ? feature.selection.appliedServerId : profile.desiredServerId;
|
? feature.selection.appliedServerId
|
||||||
|
: desired ? profile.desiredServerId : '';
|
||||||
const visibleServer = profileServer(profile, visibleServerId)
|
const visibleServer = profileServer(profile, visibleServerId)
|
||||||
|| (applied && feature.selection.appliedServerSnapshot?.id === visibleServerId
|
|| (applied && feature.selection.appliedServerSnapshot?.id === visibleServerId
|
||||||
? feature.selection.appliedServerSnapshot
|
? feature.selection.appliedServerSnapshot
|
||||||
@@ -403,7 +401,6 @@ function ProfileGroup({
|
|||||||
const visibleServerLocation = [visibleServer?.city, visibleServer?.country]
|
const visibleServerLocation = [visibleServer?.city, visibleServer?.country]
|
||||||
.filter((value): value is string => typeof value === 'string' && Boolean(value))
|
.filter((value): value is string => typeof value === 'string' && Boolean(value))
|
||||||
.join(' · ');
|
.join(' · ');
|
||||||
const canActivate = !applied && feature.selection.desiredProfileId !== profile.id;
|
|
||||||
const localStatus = profileError?.message || (profile.subscription.status === 'stale'
|
const localStatus = profileError?.message || (profile.subscription.status === 'stale'
|
||||||
? `Последнее обновление не удалось. Данные от ${profile.subscription.fetchedAt
|
? `Последнее обновление не удалось. Данные от ${profile.subscription.fetchedAt
|
||||||
? new Date(profile.subscription.fetchedAt).toLocaleString('ru-RU', { dateStyle: 'short', timeStyle: 'short' })
|
? new Date(profile.subscription.fetchedAt).toLocaleString('ru-RU', { dateStyle: 'short', timeStyle: 'short' })
|
||||||
@@ -431,12 +428,7 @@ function ProfileGroup({
|
|||||||
<small>{profileDetails}</small>
|
<small>{profileDetails}</small>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
{canActivate ? <button
|
{(applied || desired) && <ProfileUsage profile={profile} />}
|
||||||
className="client-profile-activate"
|
|
||||||
type="button"
|
|
||||||
disabled={feature.activateBlocked || !selectedServer}
|
|
||||||
onClick={() => feature.onActivate(profile.id)}
|
|
||||||
>Сделать активной</button> : <ProfileUsage profile={profile} />}
|
|
||||||
<button
|
<button
|
||||||
className={`client-profile-refresh${refreshing ? ' is-refreshing' : ''}`}
|
className={`client-profile-refresh${refreshing ? ' is-refreshing' : ''}`}
|
||||||
type="button"
|
type="button"
|
||||||
@@ -483,12 +475,13 @@ function ProfileGroup({
|
|||||||
inert={!expanded ? true : undefined}
|
inert={!expanded ? true : undefined}
|
||||||
>
|
>
|
||||||
<div className="client-profile-body-inner">
|
<div className="client-profile-body-inner">
|
||||||
{!profile.desiredServerId && <p className="client-profile-server-hint">Выберите сервер этой подписки</p>}
|
{!visibleServerId && <p className="client-profile-server-hint">Выберите сервер этой подписки</p>}
|
||||||
{renderServerPicker(profile, {
|
{renderServerPicker(profile, {
|
||||||
disabled: controlsBlocked,
|
disabled: controlsBlocked,
|
||||||
leaving: false,
|
leaving: false,
|
||||||
revealVersion: feature.revealVersions[profile.id] || 0,
|
revealVersion: feature.revealVersions[profile.id] || 0,
|
||||||
anchorServerId: visibleServer?.id || '',
|
anchorServerId: visibleServer?.id || '',
|
||||||
|
selectedServerId: visibleServerId,
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>}
|
</div>}
|
||||||
|
|||||||
@@ -149,6 +149,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.client-profile-usage {
|
.client-profile-usage {
|
||||||
|
grid-column: 2;
|
||||||
|
justify-self: end;
|
||||||
max-width: 126px;
|
max-width: 126px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
color: var(--client-muted);
|
color: var(--client-muted);
|
||||||
@@ -188,6 +190,14 @@
|
|||||||
transition: transform 600ms cubic-bezier(0.16, 1, 0.3, 1);
|
transition: transform 600ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.client-profile-refresh {
|
||||||
|
grid-column: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.client-profile-delete {
|
||||||
|
grid-column: 4;
|
||||||
|
}
|
||||||
|
|
||||||
.client-profile-delete-lid {
|
.client-profile-delete-lid {
|
||||||
transform-origin: center 7px;
|
transform-origin: center 7px;
|
||||||
transition: transform 260ms cubic-bezier(0.16, 1, 0.3, 1);
|
transition: transform 260ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||||
@@ -327,7 +337,6 @@
|
|||||||
outline-offset: -2px;
|
outline-offset: -2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-profile-activate,
|
|
||||||
.client-profile-add-trigger {
|
.client-profile-add-trigger {
|
||||||
min-height: 36px;
|
min-height: 36px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -365,18 +374,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-profile-activate {
|
|
||||||
font: var(--type-micro);
|
|
||||||
letter-spacing: var(--type-micro-tracking);
|
|
||||||
text-transform: var(--type-micro-transform);
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.client-profile-activate:disabled {
|
|
||||||
opacity: 0.35;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.client-profile-add-trigger {
|
.client-profile-add-trigger {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
|
|||||||
@@ -487,6 +487,7 @@ setInterval(() => {}, 60_000);
|
|||||||
selected.state.profiles.find(({ id }) => id === workProfileId).desiredServerId,
|
selected.state.profiles.find(({ id }) => id === workProfileId).desiredServerId,
|
||||||
testServerId,
|
testServerId,
|
||||||
);
|
);
|
||||||
|
assert.equal(selected.state.selection.desiredProfileId, workProfileId);
|
||||||
assert.equal(selected.state.profiles.find(({ id }) => id === primaryProfileId).desiredServerId, testServerId);
|
assert.equal(selected.state.profiles.find(({ id }) => id === primaryProfileId).desiredServerId, testServerId);
|
||||||
|
|
||||||
const applied = await mutation('/api/apply', 'POST', {
|
const applied = await mutation('/api/apply', 'POST', {
|
||||||
|
|||||||
@@ -179,6 +179,13 @@ test('rename and server selection are profile-scoped and reject stale or duplica
|
|||||||
await scoped.service.selectProfileServer('work', 'next', state.revision);
|
await scoped.service.selectProfileServer('work', 'next', state.revision);
|
||||||
assert.equal(scoped.snapshot().state.profiles.find(({ id }) => id === 'work').desiredServerId, 'next');
|
assert.equal(scoped.snapshot().state.profiles.find(({ id }) => id === 'work').desiredServerId, 'next');
|
||||||
assert.equal(scoped.snapshot().state.profiles.find(({ id }) => id === 'personal').desiredServerId, 'shared');
|
assert.equal(scoped.snapshot().state.profiles.find(({ id }) => id === 'personal').desiredServerId, 'shared');
|
||||||
|
assert.equal(scoped.snapshot().state.desiredProfileId, 'work');
|
||||||
|
|
||||||
|
const sameServer = scoped.snapshot().state;
|
||||||
|
sameServer.desiredProfileId = 'personal';
|
||||||
|
const reactivated = createHarness({ state: sameServer });
|
||||||
|
await reactivated.service.selectProfileServer('work', 'next', sameServer.revision);
|
||||||
|
assert.equal(reactivated.snapshot().state.desiredProfileId, 'work');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('refreshing an inactive profile does not mutate config, runtime, or the applied pair', async () => {
|
test('refreshing an inactive profile does not mutate config, runtime, or the applied pair', async () => {
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ test('server picker has one public feature owner without legacy shims', () => {
|
|||||||
assert.equal((overview.match(/<ServerPicker/g) || []).length, 1);
|
assert.equal((overview.match(/<ServerPicker/g) || []).length, 1);
|
||||||
assert.doesNotMatch(picker, /from ['"][^'"]*\/api\/|\bapi\./);
|
assert.doesNotMatch(picker, /from ['"][^'"]*\/api\/|\bapi\./);
|
||||||
assert.match(overview, /const selectedServerId = desiredProfile\?\.desiredServerId \|\| ''/);
|
assert.match(overview, /const selectedServerId = desiredProfile\?\.desiredServerId \|\| ''/);
|
||||||
assert.match(overview, /function selectServer\(profile: ProfileSnapshot, serverId: string\)[\s\S]*onApply\(profile\.id, serverId\)[\s\S]*onSelectProfileServer\(profile\.id, serverId\)/);
|
assert.match(overview, /function selectServer\(profile: ProfileSnapshot, serverId: string\)[\s\S]*if \(connected && !gatewayDirect\)[\s\S]*onApply\(profile\.id, serverId\)[\s\S]*onSelectProfileServer\(profile\.id, serverId\)/);
|
||||||
|
assert.match(overview, /selectedServerId=\{pickerState\.selectedServerId\}/);
|
||||||
});
|
});
|
||||||
|
|
||||||
const fixtures = (count) => Array.from({ length: count }, (_, index) => ({
|
const fixtures = (count) => Array.from({ length: count }, (_, index) => ({
|
||||||
|
|||||||
@@ -37,26 +37,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: 752,
|
cascadeEdges: 749,
|
||||||
customProperties: 103,
|
customProperties: 103,
|
||||||
declarations: 3202,
|
declarations: 3200,
|
||||||
important: 0,
|
important: 0,
|
||||||
keyframes: 56,
|
keyframes: 56,
|
||||||
media: 13,
|
media: 13,
|
||||||
rules: 917,
|
rules: 917,
|
||||||
variableReferences: 794,
|
variableReferences: 791,
|
||||||
},
|
},
|
||||||
hashes: {
|
hashes: {
|
||||||
cascadeEdges: '5c09bfa1ab715bdd522969d017f4ff974e2a8fc391305e68943e39612245f815',
|
cascadeEdges: 'a47dbf5212045c865de7a41d420e78df8b992a6ec1b06fb18a8d459cd480f0ae',
|
||||||
customProperties: 'fc8401b40b8d2cc8a1fc1716360ba8e5baccb694cdabde68427d3c92c04a84d4',
|
customProperties: 'fc8401b40b8d2cc8a1fc1716360ba8e5baccb694cdabde68427d3c92c04a84d4',
|
||||||
declarations: '0cacb55296aad8af6790036c75831f7a87429ec055481d9eb71d564e4d8a828c',
|
declarations: '198ccda82654a42a5ba3f452fed7a6e9a0ef1c0ff13d243eceb2c1965b4a91cd',
|
||||||
duplicateKeyframes: '4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945',
|
duplicateKeyframes: '4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945',
|
||||||
duplicateSelectors: '419962e669cbfdf5c8186318cb26688477fc0199cae98df8e1cd9bf5cddd76c2',
|
duplicateSelectors: '257eff4727dab9ce25f4e1f9320e89bf2270eb29feae921b96601f103ad7f036',
|
||||||
keyframes: 'fb859c4d0d1bfd2f5a18904e30a5f79c6ce6931d74fe88cbd506fb28c334b7ac',
|
keyframes: 'fb859c4d0d1bfd2f5a18904e30a5f79c6ce6931d74fe88cbd506fb28c334b7ac',
|
||||||
ruleDeclarationSequences: 'b2b02e78df98c48405a5243bb07e0cd6dfcfac83f7fea7847e82041741a56e14',
|
ruleDeclarationSequences: 'e4d989c091659ad82e79de7281c2b94b7b76d5f032f2a814e630275b7f7b7c4b',
|
||||||
selectors: 'e4c3dc48d8998e9fc76a0a3eb147fe6366ebfc93e22ba9ebe77f08f1fe84de2f',
|
selectors: 'd1948bb0fb3899264af80cd1f86b9c8e9cdcf1a4473ef77a0dec4ffad10d1f8d',
|
||||||
variableReferences: '252702ab07ce1c790d77a60f8e674cb3b55f7ffe6e52329a50b69e5306442f1f',
|
variableReferences: '00551e699e5530d624d364db9e546c0ffc05d7c79d04abc42930a98be874b3bf',
|
||||||
witnesses: 'f51f070cc2c7dba0f8d08518cdeee49eaf176aac82e3571cdd8498315ba8db83',
|
witnesses: '07f462edf94d90909902283f5af130f290c957c3f10ddaa5a2b2339eb64d468a',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -209,7 +209,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, 730);
|
assert.equal(witnesses.length, 729);
|
||||||
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);
|
||||||
@@ -405,8 +405,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-dA_YmbDB.css']);
|
assert.deepEqual(assets, ['index-SYp2glgN.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, 123538);
|
assert.equal(built.byteLength, 123402);
|
||||||
assert.equal(sha256(built), '7c506bdd5d073515239a4d779f6f5365a07ef245c057772ba6a343b6d90838e7');
|
assert.equal(sha256(built), '8050f9e31292529b97d716d38140da72364c26368af92dd5b3a8d56c9fe752ad');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -111,7 +111,10 @@ test('profiles render as flat accordion groups with scoped controls', () => {
|
|||||||
assert.match(feature, /feature\.operations\.profileRefresh\?\.target === profile\.id/);
|
assert.match(feature, /feature\.operations\.profileRefresh\?\.target === profile\.id/);
|
||||||
assert.match(feature, /\{visibleServer && <button[\s\S]*client-profile-selected-server[\s\S]*aria-expanded=\{expanded\}/);
|
assert.match(feature, /\{visibleServer && <button[\s\S]*client-profile-selected-server[\s\S]*aria-expanded=\{expanded\}/);
|
||||||
assert.match(feature, /anchorServerId: visibleServer\?\.id \|\| ''/);
|
assert.match(feature, /anchorServerId: visibleServer\?\.id \|\| ''/);
|
||||||
assert.match(feature, /const visibleServerId = applied \? feature\.selection\.appliedServerId : profile\.desiredServerId/);
|
assert.match(feature, /const visibleServerId = applied[\s\S]*feature\.selection\.appliedServerId[\s\S]*desired \? profile\.desiredServerId : ''/);
|
||||||
|
assert.match(feature, /selectedServerId: visibleServerId/);
|
||||||
|
assert.doesNotMatch(feature, /Сделать активной|client-profile-activate|onActivate/);
|
||||||
|
assert.doesNotMatch(page, /onActivateProfile/);
|
||||||
assert.match(feature, /const desired = !feature\.connected[\s\S]*&& !feature\.gatewayDirect/);
|
assert.match(feature, /const desired = !feature\.connected[\s\S]*&& !feature\.gatewayDirect/);
|
||||||
assert.match(feature, /const profileDomain = subscriptionDomain\(profile\.subscription\.host\)/);
|
assert.match(feature, /const profileDomain = subscriptionDomain\(profile\.subscription\.host\)/);
|
||||||
assert.match(feature, /const profileDetails = `Серверов: \$\{profile\.servers\.length\}/);
|
assert.match(feature, /const profileDetails = `Серверов: \$\{profile\.servers\.length\}/);
|
||||||
@@ -122,6 +125,7 @@ test('profiles render as flat accordion groups with scoped controls', () => {
|
|||||||
assert.match(styles, /@media \(prefers-reduced-motion: reduce\)[\s\S]*\.client-profile-body \*/);
|
assert.match(styles, /@media \(prefers-reduced-motion: reduce\)[\s\S]*\.client-profile-body \*/);
|
||||||
assert.match(styles, /\.client-profile-refresh\.is-refreshing/);
|
assert.match(styles, /\.client-profile-refresh\.is-refreshing/);
|
||||||
assert.match(styles, /\.client-profile-refresh,[\s\S]*\.client-profile-delete\s*\{[\s\S]*width:\s*36px;[\s\S]*height:\s*36px;[\s\S]*display:\s*grid;[\s\S]*place-items:\s*center/);
|
assert.match(styles, /\.client-profile-refresh,[\s\S]*\.client-profile-delete\s*\{[\s\S]*width:\s*36px;[\s\S]*height:\s*36px;[\s\S]*display:\s*grid;[\s\S]*place-items:\s*center/);
|
||||||
assert.match(styles, /\.client-profile-activate\s*\{[\s\S]*font:\s*var\(--type-micro\)/);
|
assert.match(styles, /\.client-profile-refresh\s*\{[\s\S]*grid-column:\s*3/);
|
||||||
|
assert.match(styles, /\.client-profile-delete\s*\{[\s\S]*grid-column:\s*4/);
|
||||||
assert.doesNotMatch(feature, /client-subscription-card|role="tab"/);
|
assert.doesNotMatch(feature, /client-subscription-card|role="tab"/);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user