diff --git a/src/shared/versions.ts b/src/shared/versions.ts
index 32f8718..8930a02 100644
--- a/src/shared/versions.ts
+++ b/src/shared/versions.ts
@@ -1,6 +1,6 @@
export const HARBOR_VERSIONS = Object.freeze({
- macClient: '0.25.6',
- gatewayClient: '0.26.5',
+ macClient: '0.25.7',
+ gatewayClient: '0.26.6',
gatewayBackend: '0.26.5',
});
diff --git a/src/web/features/devices/DevicesPanel.tsx b/src/web/features/devices/DevicesPanel.tsx
index e917503..c0c3081 100644
--- a/src/web/features/devices/DevicesPanel.tsx
+++ b/src/web/features/devices/DevicesPanel.tsx
@@ -339,17 +339,20 @@ export function DevicesPanel({ feature }: { feature: DevicesFeature }) {
-
+
+
+ Сбросить вход и выход всех устройств
+
Устройства
diff --git a/src/web/styles/features/devices.css b/src/web/styles/features/devices.css
index 4dee98a..e3731b8 100644
--- a/src/web/styles/features/devices.css
+++ b/src/web/styles/features/devices.css
@@ -21,7 +21,7 @@
.client-devices-kicker {
width: 100%;
display: flex;
- flex-wrap: wrap;
+ flex-wrap: nowrap;
align-items: center;
gap: 8px;
}
@@ -67,20 +67,26 @@
color: var(--client-accent);
}
+.client-devices-reset-wrap {
+ width: 28px;
+ height: 28px;
+ flex: 0 0 28px;
+ display: grid;
+ place-items: center;
+ margin-left: auto;
+}
+
.client-devices-reset {
- min-height: 28px;
- display: flex;
- align-items: center;
- gap: 5px;
- padding: 0 6px;
+ width: 28px;
+ height: 28px;
+ display: grid;
+ place-items: center;
+ padding: 0;
border: 0;
+ border-radius: 50%;
background: transparent;
color: oklch(0.68 0.15 28);
- font: var(--type-label);
- letter-spacing: var(--type-label-tracking);
- text-transform: var(--type-label-transform);
cursor: pointer;
- white-space: nowrap;
transition: color 220ms ease, filter 300ms ease;
}
@@ -115,6 +121,17 @@
opacity: 0.45;
}
+.client-devices-reset-wrap > .client-tooltip {
+ right: 0;
+ left: auto;
+ transform: translate(0, 2px);
+}
+
+.client-devices-reset-wrap:hover > .client-tooltip,
+.client-devices-reset-wrap:has(> :focus-visible) > .client-tooltip {
+ transform: translate(0, 0);
+}
+
.client-devices-sort {
min-height: 28px;
display: flex;
diff --git a/test/web/device-inventory-contract.test.js b/test/web/device-inventory-contract.test.js
index 4a452b7..d40c20f 100644
--- a/test/web/device-inventory-contract.test.js
+++ b/test/web/device-inventory-contract.test.js
@@ -200,7 +200,10 @@ test('Gateway device inventory uses the existing accessible responsive drawer',
assert.match(styles, /\.client-device-traffic-plot svg \{[\s\S]*height: 100%;[\s\S]*overflow: hidden/);
assert.match(styles, /\.client-devices-sort:hover \.client-devices-sort-icon[\s\S]*rotate\(360deg\)/);
assert.match(styles, /\.client-devices-refresh-ring circle[\s\S]*client-devices-refresh-progress 15s/);
- assert.match(panel, /className="client-devices-reset"[\s\S]*Сбросить данные/);
+ assert.match(panel, /client-devices-reset-wrap client-tooltip-anchor[\s\S]*aria-label="Сбросить вход и выход всех устройств"[\s\S]*Сбросить вход и выход всех устройств<\/Tooltip>/);
+ assert.doesNotMatch(panel, /className="client-devices-reset"[\s\S]{0,320}/);
+ assert.match(styles, /\.client-devices-kicker \{[^}]*flex-wrap: nowrap/);
+ assert.match(styles, /\.client-devices-reset-wrap \{[^}]*margin-left: auto/);
assert.match(styles, /\.client-devices-reset \{[\s\S]*oklch\(0\.68 0\.15 28\)[\s\S]*\.client-devices-reset:hover:not\(:disabled\) svg[\s\S]*rotate\(-360deg\)/);
assert.match(styles, /@media \(prefers-reduced-motion: reduce\)[\s\S]*\.client-device-policy svg[\s\S]*\.client-device-alias-trigger[\s\S]*\.client-device-identity-details[\s\S]*\.client-device-identity-copy[\s\S]*\.client-device-traffic-value > span[\s\S]*\.client-device-traffic-breakdown[\s\S]*\.client-device-traffic-lines[\s\S]*\.client-text-morph-value[\s\S]*transition: none;[\s\S]*animation: none/);
assert.match(styles, /\.client-drawer \{[\s\S]*z-index: 50;[\s\S]*box-shadow:/);
diff --git a/test/web/style-boundaries.test.js b/test/web/style-boundaries.test.js
index 390c69b..89087ed 100644
--- a/test/web/style-boundaries.test.js
+++ b/test/web/style-boundaries.test.js
@@ -37,26 +37,26 @@ const expectedImports = [
const sha256 = (value) => crypto.createHash('sha256').update(value).digest('hex');
const acceptedLedger = {
counts: {
- cascadeEdges: 815,
+ cascadeEdges: 823,
customProperties: 103,
- declarations: 3299,
+ declarations: 3306,
important: 0,
keyframes: 56,
media: 13,
- rules: 947,
- variableReferences: 815,
+ rules: 950,
+ variableReferences: 812,
},
hashes: {
- cascadeEdges: '8ed02f069be17d132a23eed9e9480b31fa583f91771dffbe4d44b485042035e0',
+ cascadeEdges: '52014b4f05da82ed3e1404ac7e81e2e7dd0960431828eb22fcdcd99ea4009683',
customProperties: 'ef70fb1d9b61b177f1939f811babe1116bee631de26f5eac0aa0d0009ca5a1fb',
- declarations: '0f20800db4323aac387f740f9b55ef8d7b3b2e78bac8765941dbda4f1e832499',
+ declarations: '568631ecf7ea61652c5fbb5f6d947e8a08fff1a179a72fb2dd6439e0e9cac950',
duplicateKeyframes: '4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945',
duplicateSelectors: '257eff4727dab9ce25f4e1f9320e89bf2270eb29feae921b96601f103ad7f036',
keyframes: 'd4378751f36eccc87923c12540315462055032a5d34978a0f45ecada0a5cc1ce',
- ruleDeclarationSequences: 'bc194eaaf4351ea21cefa140fe084e8a086720dc0fc1b0159dad623e76a0d4e6',
- selectors: 'ddb869866dc84197f7a6bef2e8d07310ec2e9fcc6822b18952de800f4c5d0d59',
- variableReferences: '2ccbb06fe9f4d0e00dc40aa117add2bed00321b92beee7c581436ecc8c9da4ca',
- witnesses: 'd8f04b8250b68423a593cb471e535712cb5b9f7d85d4ebd8d34c44f2855432da',
+ ruleDeclarationSequences: 'a53ac1a62e6c88fd923971802e9ec5238c8d5d285b6fbecce1d54bbd38d91e2c',
+ selectors: '190b90a75c4dfedc9ea66e37046fbceba70b0adbbdf89872db8f83ce93119114',
+ variableReferences: 'd3a740a583156df0b42ce0f52687617a5b5507b394251070c63d355560921f03',
+ witnesses: 'ae24f63221c956797fcd18706d3f318f15d75ffded0297fdbeb81487e6c7875e',
},
};
@@ -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', () => {
const witnesses = readStyleWitnesses(root);
- assert.equal(witnesses.length, 807);
+ assert.equal(witnesses.length, 808);
assert.equal(witnesses.filter((witness) => witness.unknown || witness.ancestorUnknown).length, 0);
const ledger = createStyleLedger(readStyleSource(root), { witnesses });
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);
const assets = fs.readdirSync(path.join(root, 'dist/assets')).filter((file) => file.endsWith('.css'));
- assert.deepEqual(assets, ['index-Cen_yNNI.css']);
+ assert.deepEqual(assets, ['index-B8MBAMBM.css']);
const built = fs.readFileSync(path.join(root, 'dist/assets', assets[0]));
- assert.equal(built.byteLength, 127660);
- assert.equal(sha256(built), 'f0f09ebbe31597130121828157e9e68fc77141db5975d32f9e3062b70e5f894b');
+ assert.equal(built.byteLength, 127884);
+ assert.equal(sha256(built), 'ec9b242f2a01e75970ec6dee43a037764835c9032a1ea6cfa97df3c7735f76ba');
});
diff --git a/test/web/ui-foundations-contract.test.js b/test/web/ui-foundations-contract.test.js
index 4a388d5..a7a461b 100644
--- a/test/web/ui-foundations-contract.test.js
+++ b/test/web/ui-foundations-contract.test.js
@@ -32,7 +32,7 @@ test('all repeated client primitive consumers use the shared owners', () => {
.map(({ source }) => source)
.join('\n');
- assert.equal((production.match(/