Skip to content

Commit c09af7c

Browse files
feat(cc-session-tokens): init
Fixes #1360
1 parent 91a47d8 commit c09af7c

10 files changed

+940
-88
lines changed

src/components/cc-session-tokens/cc-session-tokens.js

+57-87
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ import '../cc-badge/cc-badge.js';
1919
import { LostFocusController } from '../../controllers/lost-focus-controller.js';
2020
import { ifDefined } from 'lit/directives/if-defined.js';
2121
import { createRef, ref } from 'lit/directives/ref.js';
22-
23-
/**
24-
*/
22+
import { isExpirationClose } from '../../lib/utils.js';
2523

2624
/**
2725
* @typedef {import('./cc-session-tokens.types.js').SessionTokenState} SessionTokenState
@@ -64,7 +62,7 @@ export class CcSessionTokens extends LitElement {
6462
this._currentSessionCardRef = createRef();
6563

6664
new ResizeController(this, {
67-
widthBreakpoints: [900, 730],
65+
widthBreakpoints: [995, 730],
6866
});
6967

7068
new LostFocusController(this, '.session-token-card__action-revoke', ({ suggestedElement }) => {
@@ -99,51 +97,28 @@ export class CcSessionTokens extends LitElement {
9997
dispatchCustomEvent(this, 'revoke-token', tokenId);
10098
}
10199

102-
/**
103-
* Adds expiration information to a token based on time remaining
104-
*
105-
* @param {SessionTokenState} token - The token to process
106-
* @returns {SessionTokenStateWithExpirationWarning} The token with added expiration information
107-
* @private
108-
*/
109-
_addIsExpirationClose(token) {
110-
const expirationDate = new Date(token.expirationDate);
111-
const now = new Date();
112-
const daysUntilExpiration = (expirationDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24);
113-
114-
let thresholdDays;
115-
if (daysUntilExpiration <= 7) {
116-
thresholdDays = 2;
117-
} else if (daysUntilExpiration <= 30) {
118-
thresholdDays = 7;
119-
} else if (daysUntilExpiration <= 60) {
120-
thresholdDays = 10;
121-
} else if (daysUntilExpiration <= 90) {
122-
thresholdDays = 20;
123-
} else {
124-
thresholdDays = 30;
125-
}
126-
127-
const isExpirationClose = daysUntilExpiration <= thresholdDays;
128-
return { ...token, isExpirationClose };
129-
}
130-
131100
/** @param {CcSessionTokensPropertyValues} changedProperties */
132101
willUpdate(changedProperties) {
133-
if (changedProperties.has('state') && this.state.type === 'loaded') {
102+
if (changedProperties.has('state') && (this.state.type === 'loaded' || this.state.type === 'revoking-all')) {
134103
this._sortedAndFormattedTokens = [...this.state.tokens]
135104
.sort((tokenA, tokenB) => {
136105
// Current session always comes first
137-
if (tokenA.isCurrentSession) {
106+
if (tokenA.type === 'current') {
138107
return -1;
139108
}
140-
if (tokenB.isCurrentSession) {
109+
if (tokenB.type === 'current') {
141110
return 1;
142111
}
143112
// Then sort by creation date (newest first)
144113
return new Date(tokenB.creationDate).getTime() - new Date(tokenA.creationDate).getTime();
145114
})
146-
.map(this._addIsExpirationClose);
115+
.map((token) => ({
116+
...token,
117+
isExpirationClose: isExpirationClose({
118+
creationDate: token.creationDate,
119+
expirationDate: token.expirationDate,
120+
}),
121+
}));
147122
}
148123
}
149124

@@ -165,7 +140,7 @@ export class CcSessionTokens extends LitElement {
165140
class="revoke-all-tokens-button"
166141
danger
167142
outlined
168-
.waiting=${this.state.type === 'revoking-all'}
143+
?waiting=${this.state.type === 'revoking-all'}
169144
@cc-button:click=${this._onRevokeAllTokens}
170145
>
171146
${i18n('cc-session-tokens.revoke-all-tokens')}
@@ -199,10 +174,8 @@ export class CcSessionTokens extends LitElement {
199174
* @returns {TemplateResult} The rendered token card
200175
* @private
201176
*/
202-
_renderTokenCard(
203-
{ type, id, creationDate, expirationDate, lastUsedDate, isCurrentSession, isExpirationClose, isCleverTeam },
204-
index,
205-
) {
177+
_renderTokenCard({ type, id, creationDate, expirationDate, lastUsedDate, isExpirationClose, isCleverTeam }, index) {
178+
const isCurrentSession = type === 'current';
206179
const tabIndex = isCurrentSession ? -1 : null;
207180
return html`
208181
<li
@@ -211,7 +184,12 @@ export class CcSessionTokens extends LitElement {
211184
${isCurrentSession ? ref(this._currentSessionCardRef) : ''}
212185
>
213186
${isCurrentSession || isCleverTeam || isExpirationClose
214-
? this._renderCardHeader({ isCurrentSession, isCleverTeam, isExpirationClose })
187+
? this._renderCardHeader({
188+
isCurrentSession,
189+
isCleverTeam,
190+
isExpirationClose,
191+
isRevoking: type === 'revoking',
192+
})
215193
: ''}
216194
<dl class="session-token-card__info ${classMap({ 'is-revoking': type === 'revoking' })}">
217195
<div class="session-token-card__info__last-used">
@@ -247,7 +225,7 @@ export class CcSessionTokens extends LitElement {
247225
hide-text
248226
.icon=${iconDelete}
249227
circle
250-
.waiting=${type === 'revoking'}
228+
?waiting=${type === 'revoking'}
251229
@cc-button:click=${() => this._onRevokeToken(id)}
252230
>
253231
${i18n('cc-session-tokens.revoke-token', { tokenNumber: index + 1 })}
@@ -258,10 +236,10 @@ export class CcSessionTokens extends LitElement {
258236
`;
259237
}
260238

261-
/** @param {Pick<SessionTokenStateWithExpirationWarning, 'isCurrentSession' | 'isCleverTeam' | 'isExpirationClose'>} params */
262-
_renderCardHeader({ isCurrentSession, isCleverTeam, isExpirationClose }) {
239+
/** @param {{ isCleverTeam: boolean, isExpirationClose: boolean, isCurrentSession: boolean, isRevoking: boolean }} params */
240+
_renderCardHeader({ isCurrentSession, isCleverTeam, isExpirationClose, isRevoking }) {
263241
return html`
264-
<div class="session-token-card__header">
242+
<div class="session-token-card__header ${classMap({ 'is-revoking': isRevoking })}">
265243
${isCurrentSession
266244
? html`
267245
<div class="session-token-card__header__current-session">
@@ -284,6 +262,7 @@ export class CcSessionTokens extends LitElement {
284262
display: block;
285263
}
286264
265+
/* Reset default margins and paddings */
287266
ul,
288267
li,
289268
dl,
@@ -297,12 +276,6 @@ export class CcSessionTokens extends LitElement {
297276
list-style: none;
298277
}
299278
300-
/* the current session card may be focused after deleting the last session */
301-
.session-token-card:focus {
302-
outline: var(--cc-focus-outline);
303-
outline-offset: var(--cc-focus-outline-offset, 2px);
304-
}
305-
306279
p {
307280
margin: 0;
308281
}
@@ -311,13 +284,14 @@ export class CcSessionTokens extends LitElement {
311284
opacity: var(--cc-opacity-when-disabled, 0.65);
312285
}
313286
314-
.session-tokens-wrapper {
315-
margin-top: 2.5em;
287+
/* When all other sessions are revoked, focus may return to the current session card */
288+
.session-token-card:focus-visible {
289+
outline: var(--cc-focus-outline);
290+
outline-offset: var(--cc-focus-outline-offset, 2px);
316291
}
317292
318-
.session-tokens-wrapper__list {
319-
display: grid;
320-
gap: 1.5em;
293+
.session-tokens-wrapper {
294+
margin-top: 2.5em;
321295
}
322296
323297
.session-token-card {
@@ -333,13 +307,13 @@ export class CcSessionTokens extends LitElement {
333307
--cc-icon-size: 1.2em;
334308
335309
align-items: center;
310+
column-gap: 1em;
336311
display: flex;
337312
flex-wrap: wrap;
338313
font-weight: bold;
339-
gap: 1em;
340314
grid-column: info-start / info-end;
341315
margin-bottom: 1em;
342-
width: 100%;
316+
row-gap: 0.5em;
343317
}
344318
345319
.session-token-card__header__current-session {
@@ -355,6 +329,12 @@ export class CcSessionTokens extends LitElement {
355329
grid-column: info-start / info-end;
356330
}
357331
332+
.session-token-card__info div {
333+
display: flex;
334+
flex-wrap: wrap;
335+
gap: 0.5em;
336+
}
337+
358338
.session-token-card__info__last-used {
359339
font-style: italic;
360340
}
@@ -363,12 +343,6 @@ export class CcSessionTokens extends LitElement {
363343
font-weight: bold;
364344
}
365345
366-
dl div {
367-
display: flex;
368-
flex-wrap: wrap;
369-
gap: 0.5em;
370-
}
371-
372346
dt {
373347
--line-height: 1.2em;
374348
--cc-icon-size: var(--line-height);
@@ -379,7 +353,6 @@ export class CcSessionTokens extends LitElement {
379353
line-height: var(--line-height);
380354
}
381355
382-
/* Remove spacing below the font so that it matches dt spacing */
383356
dd {
384357
align-items: center;
385358
display: flex;
@@ -391,6 +364,18 @@ export class CcSessionTokens extends LitElement {
391364
font-weight: normal;
392365
}
393366
367+
.session-token-card cc-button {
368+
align-self: start;
369+
grid-column: actions-start / actions-end;
370+
grid-row: 1 / -1;
371+
justify-self: end;
372+
}
373+
374+
.session-tokens-wrapper__list {
375+
display: grid;
376+
gap: 1.5em;
377+
}
378+
394379
:host([w-lt-730]) .session-token-card {
395380
grid-template-columns: [card-start info-start] 1fr [info-end actions-start] max-content [actions-end card-end];
396381
}
@@ -400,19 +385,9 @@ export class CcSessionTokens extends LitElement {
400385
row-gap: 0.5em;
401386
}
402387
403-
.session-token-card cc-button {
404-
align-self: start;
405-
grid-column: actions-start / actions-end;
406-
grid-row: 1 / -1;
407-
justify-self: end;
408-
}
409-
410388
@supports (grid-template-columns: subgrid) {
411389
.session-tokens-wrapper__list {
412-
column-gap: 1.5em;
413-
display: grid;
414-
grid-template-columns: [card-start info-start] max-content max-content max-content [info-end actions-start] 1fr [actions-end card-end];
415-
row-gap: 1.5em;
390+
grid-template-columns: [card-start info-start] max-content max-content max-content [info-end actions-start] auto [actions-end card-end];
416391
}
417392
418393
.session-token-card {
@@ -421,27 +396,22 @@ export class CcSessionTokens extends LitElement {
421396
grid-template-columns: subgrid;
422397
}
423398
424-
.session-token-card__header {
425-
grid-column: info-start / info-end;
426-
}
427-
428399
.session-token-card__info {
429400
display: grid;
430-
gap: unset;
431401
grid-column: info-start / info-end;
432402
grid-template-columns: subgrid;
433403
}
434404
435-
:host([w-lt-900]) .session-tokens-wrapper__list {
436-
grid-template-columns: [card-start info-start] 1fr 1fr 1fr [info-end actions-start] 1fr [actions-end card-end];
405+
:host([w-lt-995]) .session-tokens-wrapper__list {
406+
grid-template-columns: [card-start info-start] 1fr 1fr 1fr [info-end actions-start] auto [actions-end card-end];
437407
}
438408
439-
:host([w-lt-900]) .session-token-card__info div {
409+
:host([w-lt-995]) .session-token-card__info div {
440410
display: grid;
441411
}
442412
443413
:host([w-lt-730]) .session-tokens-wrapper__list {
444-
grid-template-columns: [card-start info-start] 1fr [info-end actions-start] max-content [actions-end card-end];
414+
grid-template-columns: [card-start info-start] 1fr [info-end actions-start] auto [actions-end card-end];
445415
}
446416
447417
:host([w-lt-730]) .session-token-card__info {

0 commit comments

Comments
 (0)