web: Tidy temporal utilities. (#13755)
This commit is contained in:
		| @ -2,7 +2,7 @@ import { EventGeo, EventUser } from "@goauthentik/admin/events/utils"; | |||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { EventWithContext } from "@goauthentik/common/events"; | import { EventWithContext } from "@goauthentik/common/events"; | ||||||
| import { actionToLabel } from "@goauthentik/common/labels"; | import { actionToLabel } from "@goauthentik/common/labels"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import "@goauthentik/components/ak-event-info"; | import "@goauthentik/components/ak-event-info"; | ||||||
| import "@goauthentik/elements/Tabs"; | import "@goauthentik/elements/Tabs"; | ||||||
| import "@goauthentik/elements/buttons/Dropdown"; | import "@goauthentik/elements/buttons/Dropdown"; | ||||||
| @ -74,7 +74,7 @@ export class RecentEventsCard extends Table<Event> { | |||||||
|             html`<div><a href="${`#/events/log/${item.pk}`}">${actionToLabel(item.action)}</a></div> |             html`<div><a href="${`#/events/log/${item.pk}`}">${actionToLabel(item.action)}</a></div> | ||||||
|                 <small>${item.app}</small>`, |                 <small>${item.app}</small>`, | ||||||
|             EventUser(item), |             EventUser(item), | ||||||
|             html`<div>${getRelativeTime(item.created)}</div> |             html`<div>${formatElapsedTime(item.created)}</div> | ||||||
|                 <small>${item.created.toLocaleString()}</small>`, |                 <small>${item.created.toLocaleString()}</small>`, | ||||||
|             html` <div>${item.clientIp || msg("-")}</div> |             html` <div>${item.clientIp || msg("-")}</div> | ||||||
|                 <small>${EventGeo(item)}</small>`, |                 <small>${EventGeo(item)}</small>`, | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ import "@goauthentik/admin/blueprints/BlueprintForm"; | |||||||
| import "@goauthentik/admin/rbac/ObjectPermissionModal"; | import "@goauthentik/admin/rbac/ObjectPermissionModal"; | ||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { EVENT_REFRESH } from "@goauthentik/common/constants"; | import { EVENT_REFRESH } from "@goauthentik/common/constants"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import "@goauthentik/components/ak-status-label"; | import "@goauthentik/components/ak-status-label"; | ||||||
| import "@goauthentik/elements/buttons/ActionButton"; | import "@goauthentik/elements/buttons/ActionButton"; | ||||||
| import "@goauthentik/elements/buttons/SpinnerButton"; | import "@goauthentik/elements/buttons/SpinnerButton"; | ||||||
| @ -141,7 +141,7 @@ export class BlueprintListPage extends TablePage<BlueprintInstance> { | |||||||
|             html`<div>${item.name}</div> |             html`<div>${item.name}</div> | ||||||
|                 ${description ? html`<small>${description}</small>` : html``}`, |                 ${description ? html`<small>${description}</small>` : html``}`, | ||||||
|             html`${BlueprintStatus(item)}`, |             html`${BlueprintStatus(item)}`, | ||||||
|             html`<div>${getRelativeTime(item.lastApplied)}</div> |             html`<div>${formatElapsedTime(item.lastApplied)}</div> | ||||||
|                 <small>${item.lastApplied.toLocaleString()}</small>`, |                 <small>${item.lastApplied.toLocaleString()}</small>`, | ||||||
|             html`<ak-status-label ?good=${item.enabled}></ak-status-label>`, |             html`<ak-status-label ?good=${item.enabled}></ak-status-label>`, | ||||||
|             html`<ak-forms-modal> |             html`<ak-forms-modal> | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ import "@goauthentik/admin/enterprise/EnterpriseLicenseForm"; | |||||||
| import "@goauthentik/admin/enterprise/EnterpriseStatusCard"; | import "@goauthentik/admin/enterprise/EnterpriseStatusCard"; | ||||||
| import "@goauthentik/admin/rbac/ObjectPermissionModal"; | import "@goauthentik/admin/rbac/ObjectPermissionModal"; | ||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import { PFColor } from "@goauthentik/elements/Label"; | import { PFColor } from "@goauthentik/elements/Label"; | ||||||
| import "@goauthentik/elements/Spinner"; | import "@goauthentik/elements/Spinner"; | ||||||
| import "@goauthentik/elements/buttons/SpinnerButton"; | import "@goauthentik/elements/buttons/SpinnerButton"; | ||||||
| @ -186,7 +186,7 @@ export class EnterpriseLicenseListPage extends TablePage<License> { | |||||||
|                     > |                     > | ||||||
|                         ${this.summary && |                         ${this.summary && | ||||||
|                         this.summary?.status !== LicenseSummaryStatusEnum.Unlicensed |                         this.summary?.status !== LicenseSummaryStatusEnum.Unlicensed | ||||||
|                             ? html`<div>${getRelativeTime(this.summary.latestValid)}</div> |                             ? html`<div>${formatElapsedTime(this.summary.latestValid)}</div> | ||||||
|                                   <small>${this.summary.latestValid.toLocaleString()}</small>` |                                   <small>${this.summary.latestValid.toLocaleString()}</small>` | ||||||
|                             : "-"} |                             : "-"} | ||||||
|                     </ak-aggregate-card> |                     </ak-aggregate-card> | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ import { EventGeo, EventUser } from "@goauthentik/admin/events/utils"; | |||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { EventWithContext } from "@goauthentik/common/events"; | import { EventWithContext } from "@goauthentik/common/events"; | ||||||
| import { actionToLabel } from "@goauthentik/common/labels"; | import { actionToLabel } from "@goauthentik/common/labels"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import "@goauthentik/components/ak-event-info"; | import "@goauthentik/components/ak-event-info"; | ||||||
| import { PaginatedResponse } from "@goauthentik/elements/table/Table"; | import { PaginatedResponse } from "@goauthentik/elements/table/Table"; | ||||||
| import { TableColumn } from "@goauthentik/elements/table/Table"; | import { TableColumn } from "@goauthentik/elements/table/Table"; | ||||||
| @ -78,7 +78,7 @@ export class EventListPage extends TablePage<Event> { | |||||||
|             html`<div>${actionToLabel(item.action)}</div> |             html`<div>${actionToLabel(item.action)}</div> | ||||||
|                 <small>${item.app}</small>`, |                 <small>${item.app}</small>`, | ||||||
|             EventUser(item), |             EventUser(item), | ||||||
|             html`<div>${getRelativeTime(item.created)}</div> |             html`<div>${formatElapsedTime(item.created)}</div> | ||||||
|                 <small>${item.created.toLocaleString()}</small>`, |                 <small>${item.created.toLocaleString()}</small>`, | ||||||
|             html`<div>${item.clientIp || msg("-")}</div> |             html`<div>${item.clientIp || msg("-")}</div> | ||||||
|                 <small>${EventGeo(item)}</small>`, |                 <small>${EventGeo(item)}</small>`, | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ import { EventGeo, EventUser } from "@goauthentik/admin/events/utils"; | |||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { EventWithContext } from "@goauthentik/common/events"; | import { EventWithContext } from "@goauthentik/common/events"; | ||||||
| import { actionToLabel } from "@goauthentik/common/labels"; | import { actionToLabel } from "@goauthentik/common/labels"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import "@goauthentik/components/ak-event-info"; | import "@goauthentik/components/ak-event-info"; | ||||||
| import { AKElement } from "@goauthentik/elements/Base"; | import { AKElement } from "@goauthentik/elements/Base"; | ||||||
| import "@goauthentik/elements/PageHeader"; | import "@goauthentik/elements/PageHeader"; | ||||||
| @ -104,7 +104,7 @@ export class EventViewPage extends AKElement { | |||||||
|                                     </dt> |                                     </dt> | ||||||
|                                     <dd class="pf-c-description-list__description"> |                                     <dd class="pf-c-description-list__description"> | ||||||
|                                         <div class="pf-c-description-list__text"> |                                         <div class="pf-c-description-list__text"> | ||||||
|                                             <div>${getRelativeTime(this.event.created)}</div> |                                             <div>${formatElapsedTime(this.event.created)}</div> | ||||||
|                                             <small>${this.event.created.toLocaleString()}</small> |                                             <small>${this.event.created.toLocaleString()}</small> | ||||||
|                                         </div> |                                         </div> | ||||||
|                                     </dd> |                                     </dd> | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import "@goauthentik/components/ak-status-label"; | import "@goauthentik/components/ak-status-label"; | ||||||
| import "@goauthentik/elements/buttons/SpinnerButton"; | import "@goauthentik/elements/buttons/SpinnerButton"; | ||||||
| import { PaginatedResponse } from "@goauthentik/elements/table/Table"; | import { PaginatedResponse } from "@goauthentik/elements/table/Table"; | ||||||
| @ -105,7 +105,7 @@ export class MemberSelectTable extends TableModal<User> { | |||||||
|                 <small>${item.name}</small>`, |                 <small>${item.name}</small>`, | ||||||
|             html` <ak-status-label type="warning" ?good=${item.isActive}></ak-status-label>`, |             html` <ak-status-label type="warning" ?good=${item.isActive}></ak-status-label>`, | ||||||
|             html`${item.lastLogin |             html`${item.lastLogin | ||||||
|                 ? html`<div>${getRelativeTime(item.lastLogin)}</div> |                 ? html`<div>${formatElapsedTime(item.lastLogin)}</div> | ||||||
|                       <small>${item.lastLogin.toLocaleString()}</small>` |                       <small>${item.lastLogin.toLocaleString()}</small>` | ||||||
|                 : msg("-")}`, |                 : msg("-")}`, | ||||||
|         ]; |         ]; | ||||||
|  | |||||||
| @ -8,8 +8,8 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | |||||||
| import { PFSize } from "@goauthentik/common/enums.js"; | import { PFSize } from "@goauthentik/common/enums.js"; | ||||||
| import { parseAPIResponseError, pluckErrorDetail } from "@goauthentik/common/errors/network"; | import { parseAPIResponseError, pluckErrorDetail } from "@goauthentik/common/errors/network"; | ||||||
| import { MessageLevel } from "@goauthentik/common/messages"; | import { MessageLevel } from "@goauthentik/common/messages"; | ||||||
|  | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import { me } from "@goauthentik/common/users"; | import { me } from "@goauthentik/common/users"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; |  | ||||||
| import "@goauthentik/components/ak-status-label"; | import "@goauthentik/components/ak-status-label"; | ||||||
| import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider"; | import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider"; | ||||||
| import { | import { | ||||||
| @ -194,7 +194,7 @@ export class RelatedUserList extends WithBrandConfig(WithCapabilitiesConfig(Tabl | |||||||
|             </a>`, |             </a>`, | ||||||
|             html`<ak-status-label ?good=${item.isActive}></ak-status-label>`, |             html`<ak-status-label ?good=${item.isActive}></ak-status-label>`, | ||||||
|             html`${item.lastLogin |             html`${item.lastLogin | ||||||
|                 ? html`<div>${getRelativeTime(item.lastLogin)}</div> |                 ? html`<div>${formatElapsedTime(item.lastLogin)}</div> | ||||||
|                       <small>${item.lastLogin.toLocaleString()}</small>` |                       <small>${item.lastLogin.toLocaleString()}</small>` | ||||||
|                 : msg("-")}`, |                 : msg("-")}`, | ||||||
|             html`<ak-forms-modal> |             html`<ak-forms-modal> | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import { AKElement } from "@goauthentik/elements/Base"; | import { AKElement } from "@goauthentik/elements/Base"; | ||||||
| import { PFColor } from "@goauthentik/elements/Label"; | import { PFColor } from "@goauthentik/elements/Label"; | ||||||
| import "@goauthentik/elements/Spinner"; | import "@goauthentik/elements/Spinner"; | ||||||
| @ -51,7 +51,7 @@ export class OutpostHealthElement extends AKElement { | |||||||
|                     <div class="pf-c-description-list__text"> |                     <div class="pf-c-description-list__text"> | ||||||
|                         <ak-label color=${PFColor.Green} ?compact=${true}> |                         <ak-label color=${PFColor.Green} ?compact=${true}> | ||||||
|                             ${msg( |                             ${msg( | ||||||
|                                 str`${getRelativeTime(this.outpostHealth.lastSeen)} (${this.outpostHealth.lastSeen?.toLocaleTimeString()})`, |                                 str`${formatElapsedTime(this.outpostHealth.lastSeen)} (${this.outpostHealth.lastSeen?.toLocaleTimeString()})`, | ||||||
|                             )} |                             )} | ||||||
|                         </ak-label> |                         </ak-label> | ||||||
|                     </div> |                     </div> | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { EVENT_REFRESH } from "@goauthentik/common/constants"; | import { EVENT_REFRESH } from "@goauthentik/common/constants"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import { AKElement } from "@goauthentik/elements/Base"; | import { AKElement } from "@goauthentik/elements/Base"; | ||||||
| import { PFColor } from "@goauthentik/elements/Label"; | import { PFColor } from "@goauthentik/elements/Label"; | ||||||
| import "@goauthentik/elements/Spinner"; | import "@goauthentik/elements/Spinner"; | ||||||
| @ -69,7 +69,7 @@ export class OutpostHealthSimpleElement extends AKElement { | |||||||
|         const lastSeen = this.outpostHealths[0].lastSeen; |         const lastSeen = this.outpostHealths[0].lastSeen; | ||||||
|         return html`<ak-label color=${PFColor.Green}> |         return html`<ak-label color=${PFColor.Green}> | ||||||
|             ${msg( |             ${msg( | ||||||
|                 str`Last seen: ${getRelativeTime(lastSeen)} (${lastSeen.toLocaleTimeString()})`, |                 str`Last seen: ${formatElapsedTime(lastSeen)} (${lastSeen.toLocaleTimeString()})`, | ||||||
|             )}</ak-label |             )}</ak-label | ||||||
|         >`; |         >`; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| import "@goauthentik/admin/rbac/ObjectPermissionModal"; | import "@goauthentik/admin/rbac/ObjectPermissionModal"; | ||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import "@goauthentik/elements/buttons/ModalButton"; | import "@goauthentik/elements/buttons/ModalButton"; | ||||||
| import "@goauthentik/elements/buttons/SpinnerButton"; | import "@goauthentik/elements/buttons/SpinnerButton"; | ||||||
| import "@goauthentik/elements/forms/DeleteBulkForm"; | import "@goauthentik/elements/forms/DeleteBulkForm"; | ||||||
| @ -89,7 +89,7 @@ export class ReputationListPage extends TablePage<Reputation> { | |||||||
|                 : html``} |                 : html``} | ||||||
|             ${item.ip}`, |             ${item.ip}`, | ||||||
|             html`${item.score}`, |             html`${item.score}`, | ||||||
|             html`<div>${getRelativeTime(item.updated)}</div> |             html`<div>${formatElapsedTime(item.updated)}</div> | ||||||
|                 <small>${item.updated.toLocaleString()}</small>`, |                 <small>${item.updated.toLocaleString()}</small>`, | ||||||
|             html` |             html` | ||||||
|                 <ak-rbac-object-permission-modal |                 <ak-rbac-object-permission-modal | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| import "@goauthentik/admin/common/ak-flow-search/ak-flow-search"; | import "@goauthentik/admin/common/ak-flow-search/ak-flow-search"; | ||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { dateTimeLocal, first } from "@goauthentik/common/utils"; | import { dateTimeLocal } from "@goauthentik/common/temporal"; | ||||||
|  | import { first } from "@goauthentik/common/utils"; | ||||||
| import "@goauthentik/elements/CodeMirror"; | import "@goauthentik/elements/CodeMirror"; | ||||||
| import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror"; | import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror"; | ||||||
| import "@goauthentik/elements/forms/HorizontalFormElement"; | import "@goauthentik/elements/forms/HorizontalFormElement"; | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { EVENT_REFRESH } from "@goauthentik/common/constants"; | import { EVENT_REFRESH } from "@goauthentik/common/constants"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import { PFColor } from "@goauthentik/elements/Label"; | import { PFColor } from "@goauthentik/elements/Label"; | ||||||
| import "@goauthentik/elements/buttons/ActionButton"; | import "@goauthentik/elements/buttons/ActionButton"; | ||||||
| import "@goauthentik/elements/buttons/SpinnerButton"; | import "@goauthentik/elements/buttons/SpinnerButton"; | ||||||
| @ -100,7 +100,7 @@ export class SystemTaskListPage extends TablePage<SystemTask> { | |||||||
|                                                       item.expires || new Date() |                                                       item.expires || new Date() | ||||||
|                                                   ).toLocaleString()} |                                                   ).toLocaleString()} | ||||||
|                                               > |                                               > | ||||||
|                                                   ${getRelativeTime(item.expires || new Date())} |                                                   ${formatElapsedTime(item.expires || new Date())} | ||||||
|                                               </pf-tooltip> |                                               </pf-tooltip> | ||||||
|                                           ` |                                           ` | ||||||
|                                         : msg("-")} |                                         : msg("-")} | ||||||
| @ -128,7 +128,7 @@ export class SystemTaskListPage extends TablePage<SystemTask> { | |||||||
|         return [ |         return [ | ||||||
|             html`<pre>${item.name}${item.uid ? `:${item.uid}` : ""}</pre>`, |             html`<pre>${item.name}${item.uid ? `:${item.uid}` : ""}</pre>`, | ||||||
|             html`${item.description}`, |             html`${item.description}`, | ||||||
|             html`<div>${getRelativeTime(item.finishTimestamp)}</div> |             html`<div>${formatElapsedTime(item.finishTimestamp)}</div> | ||||||
|                 <small>${item.finishTimestamp.toLocaleString()}</small>`, |                 <small>${item.finishTimestamp.toLocaleString()}</small>`, | ||||||
|             this.taskStatus(item), |             this.taskStatus(item), | ||||||
|             html`<ak-action-button |             html`<ak-action-button | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { dateTimeLocal, first } from "@goauthentik/common/utils"; | import { dateTimeLocal } from "@goauthentik/common/temporal"; | ||||||
|  | import { first } from "@goauthentik/common/utils"; | ||||||
| import "@goauthentik/elements/forms/FormGroup"; | import "@goauthentik/elements/forms/FormGroup"; | ||||||
| import "@goauthentik/elements/forms/HorizontalFormElement"; | import "@goauthentik/elements/forms/HorizontalFormElement"; | ||||||
| import { ModelForm } from "@goauthentik/elements/forms/ModelForm"; | import { ModelForm } from "@goauthentik/elements/forms/ModelForm"; | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ import "@goauthentik/admin/rbac/ObjectPermissionModal"; | |||||||
| import "@goauthentik/admin/tokens/TokenForm"; | import "@goauthentik/admin/tokens/TokenForm"; | ||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { intentToLabel } from "@goauthentik/common/labels"; | import { intentToLabel } from "@goauthentik/common/labels"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import "@goauthentik/components/ak-status-label"; | import "@goauthentik/components/ak-status-label"; | ||||||
| import "@goauthentik/elements/buttons/Dropdown"; | import "@goauthentik/elements/buttons/Dropdown"; | ||||||
| import "@goauthentik/elements/buttons/TokenCopyButton"; | import "@goauthentik/elements/buttons/TokenCopyButton"; | ||||||
| @ -107,7 +107,7 @@ export class TokenListPage extends TablePage<Token> { | |||||||
|             html`<a href="#/identity/users/${item.userObj?.pk}">${item.userObj?.username}</a>`, |             html`<a href="#/identity/users/${item.userObj?.pk}">${item.userObj?.username}</a>`, | ||||||
|             html`<ak-status-label type="warning" ?good=${item.expiring}></ak-status-label>`, |             html`<ak-status-label type="warning" ?good=${item.expiring}></ak-status-label>`, | ||||||
|             html`${item.expires && item.expiring |             html`${item.expires && item.expiring | ||||||
|                 ? html`<div>${getRelativeTime(item.expires)}</div> |                 ? html`<div>${formatElapsedTime(item.expires)}</div> | ||||||
|                       <small>${item.expires.toLocaleString()}</small>` |                       <small>${item.expires.toLocaleString()}</small>` | ||||||
|                 : msg("-")}`, |                 : msg("-")}`, | ||||||
|             html`${intentToLabel(item.intent ?? IntentEnum.Api)}`, |             html`${intentToLabel(item.intent ?? IntentEnum.Api)}`, | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { dateTimeLocal } from "@goauthentik/common/utils"; | import { dateTimeLocal } from "@goauthentik/common/temporal"; | ||||||
| import { Form } from "@goauthentik/elements/forms/Form"; | import { Form } from "@goauthentik/elements/forms/Form"; | ||||||
| import "@goauthentik/elements/forms/HorizontalFormElement"; | import "@goauthentik/elements/forms/HorizontalFormElement"; | ||||||
| import { ModalForm } from "@goauthentik/elements/forms/ModalForm"; | import { ModalForm } from "@goauthentik/elements/forms/ModalForm"; | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { deviceTypeName } from "@goauthentik/common/labels"; | import { deviceTypeName } from "@goauthentik/common/labels"; | ||||||
| import { SentryIgnoredError } from "@goauthentik/common/sentry"; | import { SentryIgnoredError } from "@goauthentik/common/sentry"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import "@goauthentik/elements/forms/DeleteBulkForm"; | import "@goauthentik/elements/forms/DeleteBulkForm"; | ||||||
| import { PaginatedResponse } from "@goauthentik/elements/table/Table"; | import { PaginatedResponse } from "@goauthentik/elements/table/Table"; | ||||||
| import { Table, TableColumn } from "@goauthentik/elements/table/Table"; | import { Table, TableColumn } from "@goauthentik/elements/table/Table"; | ||||||
| @ -108,15 +108,15 @@ export class UserDeviceTable extends Table<Device> { | |||||||
|             ${item.extraDescription ? ` - ${item.extraDescription}` : ""}`, |             ${item.extraDescription ? ` - ${item.extraDescription}` : ""}`, | ||||||
|             html`${item.confirmed ? msg("Yes") : msg("No")}`, |             html`${item.confirmed ? msg("Yes") : msg("No")}`, | ||||||
|             html`${item.created.getTime() > 0 |             html`${item.created.getTime() > 0 | ||||||
|                 ? html`<div>${getRelativeTime(item.created)}</div> |                 ? html`<div>${formatElapsedTime(item.created)}</div> | ||||||
|                       <small>${item.created.toLocaleString()}</small>` |                       <small>${item.created.toLocaleString()}</small>` | ||||||
|                 : html`-`}`, |                 : html`-`}`, | ||||||
|             html`${item.lastUpdated |             html`${item.lastUpdated | ||||||
|                 ? html`<div>${getRelativeTime(item.lastUpdated)}</div> |                 ? html`<div>${formatElapsedTime(item.lastUpdated)}</div> | ||||||
|                       <small>${item.lastUpdated.toLocaleString()}</small>` |                       <small>${item.lastUpdated.toLocaleString()}</small>` | ||||||
|                 : html`-`}`, |                 : html`-`}`, | ||||||
|             html`${item.lastUsed |             html`${item.lastUsed | ||||||
|                 ? html`<div>${getRelativeTime(item.lastUsed)}</div> |                 ? html`<div>${formatElapsedTime(item.lastUsed)}</div> | ||||||
|                       <small>${item.lastUsed.toLocaleString()}</small>` |                       <small>${item.lastUsed.toLocaleString()}</small>` | ||||||
|                 : html`-`}`, |                 : html`-`}`, | ||||||
|         ]; |         ]; | ||||||
|  | |||||||
| @ -10,9 +10,9 @@ import { PFSize } from "@goauthentik/common/enums.js"; | |||||||
| import { parseAPIResponseError } from "@goauthentik/common/errors/network"; | import { parseAPIResponseError } from "@goauthentik/common/errors/network"; | ||||||
| import { userTypeToLabel } from "@goauthentik/common/labels"; | import { userTypeToLabel } from "@goauthentik/common/labels"; | ||||||
| import { MessageLevel } from "@goauthentik/common/messages"; | import { MessageLevel } from "@goauthentik/common/messages"; | ||||||
|  | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import { DefaultUIConfig, uiConfig } from "@goauthentik/common/ui/config"; | import { DefaultUIConfig, uiConfig } from "@goauthentik/common/ui/config"; | ||||||
| import { me } from "@goauthentik/common/users"; | import { me } from "@goauthentik/common/users"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; |  | ||||||
| import "@goauthentik/components/ak-status-label"; | import "@goauthentik/components/ak-status-label"; | ||||||
| import { rootInterface } from "@goauthentik/elements/Base"; | import { rootInterface } from "@goauthentik/elements/Base"; | ||||||
| import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider"; | import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider"; | ||||||
| @ -244,7 +244,7 @@ export class UserListPage extends WithBrandConfig(WithCapabilitiesConfig(TablePa | |||||||
|             </a>`, |             </a>`, | ||||||
|             html`<ak-status-label ?good=${item.isActive}></ak-status-label>`, |             html`<ak-status-label ?good=${item.isActive}></ak-status-label>`, | ||||||
|             html`${item.lastLogin |             html`${item.lastLogin | ||||||
|                 ? html`<div>${getRelativeTime(item.lastLogin)}</div> |                 ? html`<div>${formatElapsedTime(item.lastLogin)}</div> | ||||||
|                       <small>${item.lastLogin.toLocaleString()}</small>` |                       <small>${item.lastLogin.toLocaleString()}</small>` | ||||||
|                 : msg("-")}`, |                 : msg("-")}`, | ||||||
|             html`${userTypeToLabel(item.type)}`, |             html`${userTypeToLabel(item.type)}`, | ||||||
|  | |||||||
| @ -15,8 +15,8 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | |||||||
| import { EVENT_REFRESH } from "@goauthentik/common/constants"; | import { EVENT_REFRESH } from "@goauthentik/common/constants"; | ||||||
| import { PFSize } from "@goauthentik/common/enums.js"; | import { PFSize } from "@goauthentik/common/enums.js"; | ||||||
| import { userTypeToLabel } from "@goauthentik/common/labels"; | import { userTypeToLabel } from "@goauthentik/common/labels"; | ||||||
|  | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import { me } from "@goauthentik/common/users"; | import { me } from "@goauthentik/common/users"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; |  | ||||||
| import "@goauthentik/components/DescriptionList"; | import "@goauthentik/components/DescriptionList"; | ||||||
| import { | import { | ||||||
|     type DescriptionPair, |     type DescriptionPair, | ||||||
| @ -155,11 +155,11 @@ export class UserViewPage extends WithCapabilitiesConfig(AKElement) { | |||||||
|             [msg("Name"), user.name], |             [msg("Name"), user.name], | ||||||
|             [msg("Email"), user.email || "-"], |             [msg("Email"), user.email || "-"], | ||||||
|             [msg("Last login"), user.lastLogin |             [msg("Last login"), user.lastLogin | ||||||
|                 ? html`<div>${getRelativeTime(user.lastLogin)}</div> |                 ? html`<div>${formatElapsedTime(user.lastLogin)}</div> | ||||||
|                       <small>${user.lastLogin.toLocaleString()}</small>` |                       <small>${user.lastLogin.toLocaleString()}</small>` | ||||||
|                 : html`${msg("-")}`], |                 : html`${msg("-")}`], | ||||||
|             [msg("Last password change"), user.passwordChangeDate |             [msg("Last password change"), user.passwordChangeDate | ||||||
|                 ? html`<div>${getRelativeTime(user.passwordChangeDate)}</div> |                 ? html`<div>${formatElapsedTime(user.passwordChangeDate)}</div> | ||||||
|                       <small>${user.passwordChangeDate.toLocaleString()}</small>` |                       <small>${user.passwordChangeDate.toLocaleString()}</small>` | ||||||
|                 : html`${msg("-")}`], |                 : html`${msg("-")}`], | ||||||
|             [msg("Active"), html`<ak-status-label type="warning" ?good=${user.isActive}></ak-status-label>`], |             [msg("Active"), html`<ak-status-label type="warning" ?good=${user.isActive}></ak-status-label>`], | ||||||
|  | |||||||
							
								
								
									
										132
									
								
								web/src/common/temporal.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								web/src/common/temporal.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,132 @@ | |||||||
|  | /** | ||||||
|  |  * @file Temporal utilitie for working with dates and times. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Duration in milliseconds for time units used by the `Intl.RelativeTimeFormat` API. | ||||||
|  |  */ | ||||||
|  | export const Duration = { | ||||||
|  |     /** | ||||||
|  |      * The number of milliseconds in a year. | ||||||
|  |      */ | ||||||
|  |     year: 1000 * 60 * 60 * 24 * 365, | ||||||
|  |     /** | ||||||
|  |      * The number of milliseconds in a month. | ||||||
|  |      */ | ||||||
|  |     month: (24 * 60 * 60 * 1000 * 365) / 12, | ||||||
|  |     /** | ||||||
|  |      * The number of milliseconds in a day. | ||||||
|  |      */ | ||||||
|  |     day: 1000 * 60 * 60 * 24, | ||||||
|  |     /** | ||||||
|  |      * The number of milliseconds in an hour. | ||||||
|  |      */ | ||||||
|  |     hour: 1000 * 60 * 60, | ||||||
|  |     /** | ||||||
|  |      * The number of milliseconds in a minute. | ||||||
|  |      */ | ||||||
|  |     minute: 1000 * 60, | ||||||
|  |     /** | ||||||
|  |      * The number of milliseconds in a second. | ||||||
|  |      */ | ||||||
|  |     second: 1000, | ||||||
|  | } as const satisfies Partial<Record<Intl.RelativeTimeFormatUnit, number>>; | ||||||
|  |  | ||||||
|  | export type DurationUnit = keyof typeof Duration; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * The order of time units used by the `Intl.RelativeTimeFormat` API. | ||||||
|  |  */ | ||||||
|  | const DurationGranularity = [ | ||||||
|  |     "year", | ||||||
|  |     "month", | ||||||
|  |     "day", | ||||||
|  |     "hour", | ||||||
|  |     "minute", | ||||||
|  |     "second", | ||||||
|  | ] as const satisfies DurationUnit[]; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Given two dates, return a human-readable string describing the time elapsed between them. | ||||||
|  |  */ | ||||||
|  | export function formatElapsedTime(d1: Date, d2: Date = new Date()): string { | ||||||
|  |     const elapsed = d1.getTime() - d2.getTime(); | ||||||
|  |     const rtf = new Intl.RelativeTimeFormat("default", { numeric: "auto" }); | ||||||
|  |  | ||||||
|  |     for (const unit of DurationGranularity) { | ||||||
|  |         const duration = Duration[unit]; | ||||||
|  |  | ||||||
|  |         if (Math.abs(elapsed) > duration || unit === "second") { | ||||||
|  |             let rounded = Math.round(elapsed / duration); | ||||||
|  |  | ||||||
|  |             if (!isFinite(rounded)) { | ||||||
|  |                 rounded = 0; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return rtf.format(rounded, unit); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return rtf.format(Math.round(elapsed / 1000), "second"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Convert a Date object to a string in the format required by the datetime-local input field. | ||||||
|  |  * | ||||||
|  |  * ```js | ||||||
|  |  *  html`<input | ||||||
|  |  *     type="datetime-local" | ||||||
|  |  *     data-type="datetime-local" | ||||||
|  |  *     class="pf-c-form-control" | ||||||
|  |  *     required | ||||||
|  |  *     value="${dateTimeLocal(new Date())}" | ||||||
|  |  *   /> | ||||||
|  |  * ``` | ||||||
|  |  * | ||||||
|  |  * @param input - The Date object to convert. | ||||||
|  |  * @returns A string in the format "YYYY-MM-DDTHH:MM" (e.g., "2023-10-01T12:00"). | ||||||
|  |  * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/datetime-local | ||||||
|  |  * | ||||||
|  |  * @remarks | ||||||
|  |  * | ||||||
|  |  * So for some reason, the datetime-local input field requires ISO Datetime as value. | ||||||
|  |  * | ||||||
|  |  * But the standard`date.toISOString()` returns everything with seconds and milliseconds, | ||||||
|  |  * which the input field doesn't like (on chrome, on firefox its fine) | ||||||
|  |  * | ||||||
|  |  * On chrome, setting .valueAsNumber works, but that causes an error on firefox, so go figure. | ||||||
|  |  * | ||||||
|  |  * Additionally, `toISOString` always returns the date without timezone, | ||||||
|  |  * which we would like to include for better usability | ||||||
|  |  */ | ||||||
|  | export function dateTimeLocal(input: Date): string { | ||||||
|  |     const tzOffset = new Date().getTimezoneOffset() * 60_000; //offset in milliseconds | ||||||
|  |     const localISOTime = new Date(input.getTime() - tzOffset).toISOString().slice(0, -1); | ||||||
|  |  | ||||||
|  |     const [datePart, timePart] = localISOTime.split(":"); | ||||||
|  |  | ||||||
|  |     return [datePart, timePart].join(":"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Convert a Date object to UTC. | ||||||
|  |  * | ||||||
|  |  * @remarks | ||||||
|  |  * | ||||||
|  |  * Sigh...so our API is UTC/can take TZ info in the ISO format as it should. | ||||||
|  |  * | ||||||
|  |  * datetime-local fields (which is almost the only date-time input we use) | ||||||
|  |  * can return its value as a UTC timestamp...however the generated API client | ||||||
|  |  * _requires_ a Date object, only to then convert it to an ISO string anyways | ||||||
|  |  * JS Dates don't include timezone info in the ISO string, so that just sends | ||||||
|  |  * the local time as UTC...which is wrong. | ||||||
|  |  * | ||||||
|  |  * Instead we have to do this, convert the given date to a UTC timestamp, | ||||||
|  |  * then subtract the timezone offset to create an "invalid" date (correct time&date) | ||||||
|  |  * but it still "thinks" it's in local TZ. | ||||||
|  |  */ | ||||||
|  | export function dateToUTC(input: Date): Date { | ||||||
|  |     const timestamp = input.getTime(); | ||||||
|  |     const offset = -1 * (new Date().getTimezoneOffset() * 60_000); | ||||||
|  |  | ||||||
|  |     return new Date(timestamp - offset); | ||||||
|  | } | ||||||
| @ -103,35 +103,6 @@ export function randomString(len: number, charset: string): string { | |||||||
|     return chars.join(""); |     return chars.join(""); | ||||||
| } | } | ||||||
|  |  | ||||||
| export function dateTimeLocal(date: Date): string { |  | ||||||
|     // So for some reason, the datetime-local input field requires ISO Datetime as value |  | ||||||
|     // But the standard javascript date.toISOString() returns everything with seconds and |  | ||||||
|     // milliseconds, which the input field doesn't like (on chrome, on firefox its fine) |  | ||||||
|     // On chrome, setting .valueAsNumber works, but that causes an error on firefox, so go |  | ||||||
|     // figure. |  | ||||||
|     // Additionally, toISOString always returns the date without timezone, which we would like |  | ||||||
|     // to include for better usability |  | ||||||
|     const tzOffset = new Date().getTimezoneOffset() * 60000; //offset in milliseconds |  | ||||||
|     const localISOTime = new Date(date.getTime() - tzOffset).toISOString().slice(0, -1); |  | ||||||
|     const parts = localISOTime.split(":"); |  | ||||||
|     return `${parts[0]}:${parts[1]}`; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function dateToUTC(date: Date): Date { |  | ||||||
|     // Sigh...so our API is UTC/can take TZ info in the ISO format as it should. |  | ||||||
|     // datetime-local fields (which is almost the only date-time input we use) |  | ||||||
|     // can return its value as a UTC timestamp...however the generated API client |  | ||||||
|     // _requires_ a Date object, only to then convert it to an ISO string anyways |  | ||||||
|     // JS Dates don't include timezone info in the ISO string, so that just sends |  | ||||||
|     // the local time as UTC...which is wrong |  | ||||||
|     // Instead we have to do this, convert the given date to a UTC timestamp, |  | ||||||
|     // then subtract the timezone offset to create an "invalid" date (correct time&date) |  | ||||||
|     // but it still "thinks" it's in local TZ |  | ||||||
|     const timestamp = date.getTime(); |  | ||||||
|     const offset = -1 * (new Date().getTimezoneOffset() * 60000); |  | ||||||
|     return new Date(timestamp - offset); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Lit is extremely well-typed with regard to CSS, and Storybook's `build` does not currently have a | // Lit is extremely well-typed with regard to CSS, and Storybook's `build` does not currently have a | ||||||
| // coherent way of importing CSS-as-text into CSSStyleSheet. It works well when Storybook is running | // coherent way of importing CSS-as-text into CSSStyleSheet. It works well when Storybook is running | ||||||
| // in `dev,` but in `build` it fails. Storied components will have to map their textual CSS imports | // in `dev,` but in `build` it fails. Storied components will have to map their textual CSS imports | ||||||
| @ -156,28 +127,3 @@ export function adaptCSS(sheet: AdaptableStylesheet[]): CSSStyleSheet[]; | |||||||
| export function adaptCSS(sheet: AdaptableStylesheet | AdaptableStylesheet[]): AdaptedStylesheets { | export function adaptCSS(sheet: AdaptableStylesheet | AdaptableStylesheet[]): AdaptedStylesheets { | ||||||
|     return Array.isArray(sheet) ? sheet.map(_adaptCSS) : _adaptCSS(sheet); |     return Array.isArray(sheet) ? sheet.map(_adaptCSS) : _adaptCSS(sheet); | ||||||
| } | } | ||||||
|  |  | ||||||
| export function getRelativeTime(d1: Date, d2: Date = new Date()): string { |  | ||||||
|     const elapsed = d1.getTime() - d2.getTime(); |  | ||||||
|     const rtf = new Intl.RelativeTimeFormat("default", { numeric: "auto" }); |  | ||||||
|  |  | ||||||
|     const _timeUnits: [Intl.RelativeTimeFormatUnit, number][] = [ |  | ||||||
|         ["year", 1000 * 60 * 60 * 24 * 365], |  | ||||||
|         ["month", (24 * 60 * 60 * 1000 * 365) / 12], |  | ||||||
|         ["day", 1000 * 60 * 60 * 24], |  | ||||||
|         ["hour", 1000 * 60 * 60], |  | ||||||
|         ["minute", 1000 * 60], |  | ||||||
|         ["second", 1000], |  | ||||||
|     ]; |  | ||||||
|  |  | ||||||
|     for (const [key, value] of _timeUnits) { |  | ||||||
|         if (Math.abs(elapsed) > value || key === "second") { |  | ||||||
|             let rounded = Math.round(elapsed / value); |  | ||||||
|             if (!isFinite(rounded)) { |  | ||||||
|                 rounded = 0; |  | ||||||
|             } |  | ||||||
|             return rtf.format(rounded, key); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     return rtf.format(Math.round(elapsed / 1000), "second"); |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ import { EventGeo, EventUser } from "@goauthentik/admin/events/utils"; | |||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { EventWithContext } from "@goauthentik/common/events"; | import { EventWithContext } from "@goauthentik/common/events"; | ||||||
| import { actionToLabel } from "@goauthentik/common/labels"; | import { actionToLabel } from "@goauthentik/common/labels"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import "@goauthentik/components/ak-event-info"; | import "@goauthentik/components/ak-event-info"; | ||||||
| import "@goauthentik/elements/Tabs"; | import "@goauthentik/elements/Tabs"; | ||||||
| import "@goauthentik/elements/buttons/Dropdown"; | import "@goauthentik/elements/buttons/Dropdown"; | ||||||
| @ -73,7 +73,7 @@ export class ObjectChangelog extends Table<Event> { | |||||||
|         return [ |         return [ | ||||||
|             html`${actionToLabel(item.action)}`, |             html`${actionToLabel(item.action)}`, | ||||||
|             EventUser(item), |             EventUser(item), | ||||||
|             html`<div>${getRelativeTime(item.created)}</div> |             html`<div>${formatElapsedTime(item.created)}</div> | ||||||
|                 <small>${item.created.toLocaleString()}</small>`, |                 <small>${item.created.toLocaleString()}</small>`, | ||||||
|             html`<div>${item.clientIp || msg("-")}</div> |             html`<div>${item.clientIp || msg("-")}</div> | ||||||
|  |  | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ import { EventUser } from "@goauthentik/admin/events/utils"; | |||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { EventWithContext } from "@goauthentik/common/events"; | import { EventWithContext } from "@goauthentik/common/events"; | ||||||
| import { actionToLabel } from "@goauthentik/common/labels"; | import { actionToLabel } from "@goauthentik/common/labels"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import "@goauthentik/components/ak-event-info"; | import "@goauthentik/components/ak-event-info"; | ||||||
| import "@goauthentik/elements/Tabs"; | import "@goauthentik/elements/Tabs"; | ||||||
| import "@goauthentik/elements/buttons/Dropdown"; | import "@goauthentik/elements/buttons/Dropdown"; | ||||||
| @ -47,7 +47,7 @@ export class UserEvents extends Table<Event> { | |||||||
|         return [ |         return [ | ||||||
|             html`${actionToLabel(item.action)}`, |             html`${actionToLabel(item.action)}`, | ||||||
|             EventUser(item), |             EventUser(item), | ||||||
|             html`<div>${getRelativeTime(item.created)}</div> |             html`<div>${formatElapsedTime(item.created)}</div> | ||||||
|                 <small>${item.created.toLocaleString()}</small>`, |                 <small>${item.created.toLocaleString()}</small>`, | ||||||
|             html`<span>${item.clientIp || msg("-")}</span>`, |             html`<span>${item.clientIp || msg("-")}</span>`, | ||||||
|         ]; |         ]; | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ import { | |||||||
|     parseAPIResponseError, |     parseAPIResponseError, | ||||||
|     pluckErrorDetail, |     pluckErrorDetail, | ||||||
| } from "@goauthentik/common/errors/network"; | } from "@goauthentik/common/errors/network"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import { AKElement } from "@goauthentik/elements/Base"; | import { AKElement } from "@goauthentik/elements/Base"; | ||||||
| import "@goauthentik/elements/EmptyState"; | import "@goauthentik/elements/EmptyState"; | ||||||
| import { | import { | ||||||
| @ -176,7 +176,7 @@ export abstract class AKChart<T> extends AKElement { | |||||||
|  |  | ||||||
|     timeTickCallback(tickValue: string | number, index: number, ticks: Tick[]): string { |     timeTickCallback(tickValue: string | number, index: number, ticks: Tick[]): string { | ||||||
|         const valueStamp = ticks[index]; |         const valueStamp = ticks[index]; | ||||||
|         return getRelativeTime(new Date(valueStamp.value)); |         return formatElapsedTime(new Date(valueStamp.value)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     getOptions(): ChartOptions { |     getOptions(): ChartOptions { | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import "@goauthentik/components/ak-status-label"; | import "@goauthentik/components/ak-status-label"; | ||||||
| import "@goauthentik/elements/EmptyState"; | import "@goauthentik/elements/EmptyState"; | ||||||
| import { PaginatedResponse, Table, TableColumn } from "@goauthentik/elements/table/Table"; | import { PaginatedResponse, Table, TableColumn } from "@goauthentik/elements/table/Table"; | ||||||
| @ -102,7 +102,7 @@ export class LogViewer extends Table<LogEvent> { | |||||||
|  |  | ||||||
|     row(item: LogEvent): TemplateResult[] { |     row(item: LogEvent): TemplateResult[] { | ||||||
|         return [ |         return [ | ||||||
|             html`${getRelativeTime(item.timestamp)}`, |             html`${formatElapsedTime(item.timestamp)}`, | ||||||
|             html`<ak-status-label |             html`<ak-status-label | ||||||
|                 type=${this.statusForItem(item)} |                 type=${this.statusForItem(item)} | ||||||
|                 bad-label=${item.logLevel} |                 bad-label=${item.logLevel} | ||||||
|  | |||||||
| @ -1,7 +1,8 @@ | |||||||
| import { EVENT_REFRESH } from "@goauthentik/common/constants"; | import { EVENT_REFRESH } from "@goauthentik/common/constants"; | ||||||
| import { parseAPIResponseError, pluckErrorDetail } from "@goauthentik/common/errors/network"; | import { parseAPIResponseError, pluckErrorDetail } from "@goauthentik/common/errors/network"; | ||||||
| import { MessageLevel } from "@goauthentik/common/messages"; | import { MessageLevel } from "@goauthentik/common/messages"; | ||||||
| import { camelToSnake, convertToSlug, dateToUTC } from "@goauthentik/common/utils"; | import { dateToUTC } from "@goauthentik/common/temporal"; | ||||||
|  | import { camelToSnake, convertToSlug } from "@goauthentik/common/utils"; | ||||||
| import { AKElement } from "@goauthentik/elements/Base"; | import { AKElement } from "@goauthentik/elements/Base"; | ||||||
| import { HorizontalFormElement } from "@goauthentik/elements/forms/HorizontalFormElement"; | import { HorizontalFormElement } from "@goauthentik/elements/forms/HorizontalFormElement"; | ||||||
| import { PreventFormSubmit } from "@goauthentik/elements/forms/helpers"; | import { PreventFormSubmit } from "@goauthentik/elements/forms/helpers"; | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| import { RequestInfo } from "@goauthentik/common/api/middleware"; | import { RequestInfo } from "@goauthentik/common/api/middleware"; | ||||||
| import { EVENT_API_DRAWER_TOGGLE, EVENT_REQUEST_POST } from "@goauthentik/common/constants"; | import { EVENT_API_DRAWER_TOGGLE, EVENT_REQUEST_POST } from "@goauthentik/common/constants"; | ||||||
| import { globalAK } from "@goauthentik/common/global"; | import { globalAK } from "@goauthentik/common/global"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import { AKElement } from "@goauthentik/elements/Base"; | import { AKElement } from "@goauthentik/elements/Base"; | ||||||
|  |  | ||||||
| import { msg } from "@lit/localize"; | import { msg } from "@lit/localize"; | ||||||
| @ -79,7 +79,7 @@ export class APIDrawer extends AKElement { | |||||||
|                 >${item.path}</a |                 >${item.path}</a | ||||||
|             > |             > | ||||||
|             <div class="pf-c-notification-drawer__list-item-timestamp"> |             <div class="pf-c-notification-drawer__list-item-timestamp"> | ||||||
|                 ${getRelativeTime(new Date(item.time))} |                 ${formatElapsedTime(new Date(item.time))} | ||||||
|             </div> |             </div> | ||||||
|         </li>`; |         </li>`; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -3,8 +3,8 @@ import { EVENT_NOTIFICATION_DRAWER_TOGGLE, EVENT_REFRESH } from "@goauthentik/co | |||||||
| import { globalAK } from "@goauthentik/common/global"; | import { globalAK } from "@goauthentik/common/global"; | ||||||
| import { actionToLabel } from "@goauthentik/common/labels"; | import { actionToLabel } from "@goauthentik/common/labels"; | ||||||
| import { MessageLevel } from "@goauthentik/common/messages"; | import { MessageLevel } from "@goauthentik/common/messages"; | ||||||
|  | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import { me } from "@goauthentik/common/users"; | import { me } from "@goauthentik/common/users"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; |  | ||||||
| import { AKElement } from "@goauthentik/elements/Base"; | import { AKElement } from "@goauthentik/elements/Base"; | ||||||
| import "@goauthentik/elements/EmptyState"; | import "@goauthentik/elements/EmptyState"; | ||||||
| import { showMessage } from "@goauthentik/elements/messages/MessageContainer"; | import { showMessage } from "@goauthentik/elements/messages/MessageContainer"; | ||||||
| @ -134,7 +134,7 @@ export class NotificationDrawer extends AKElement { | |||||||
|             <p class="pf-c-notification-drawer__list-item-description">${item.body}</p> |             <p class="pf-c-notification-drawer__list-item-description">${item.body}</p> | ||||||
|             <small class="pf-c-notification-drawer__list-item-timestamp" |             <small class="pf-c-notification-drawer__list-item-timestamp" | ||||||
|                 ><pf-tooltip position="top" .content=${item.created?.toLocaleString()}> |                 ><pf-tooltip position="top" .content=${item.created?.toLocaleString()}> | ||||||
|                     ${getRelativeTime(item.created!)} |                     ${formatElapsedTime(item.created!)} | ||||||
|                 </pf-tooltip></small |                 </pf-tooltip></small | ||||||
|             > |             > | ||||||
|         </li>`; |         </li>`; | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import "@goauthentik/components/ak-status-label"; | import "@goauthentik/components/ak-status-label"; | ||||||
| import "@goauthentik/elements/chips/Chip"; | import "@goauthentik/elements/chips/Chip"; | ||||||
| import "@goauthentik/elements/chips/ChipGroup"; | import "@goauthentik/elements/chips/ChipGroup"; | ||||||
| @ -92,7 +92,7 @@ export class UserOAuthAccessTokenList extends Table<TokenModel> { | |||||||
|                 bad-label=${msg("Yes")} |                 bad-label=${msg("Yes")} | ||||||
|             ></ak-status-label>`, |             ></ak-status-label>`, | ||||||
|             html`${item.expires |             html`${item.expires | ||||||
|                 ? html`<div>${getRelativeTime(item.expires)}</div> |                 ? html`<div>${formatElapsedTime(item.expires)}</div> | ||||||
|                       <small>${item.expires.toLocaleString()}</small>` |                       <small>${item.expires.toLocaleString()}</small>` | ||||||
|                 : msg("-")}`, |                 : msg("-")}`, | ||||||
|             html`<ak-chip-group> |             html`<ak-chip-group> | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import "@goauthentik/components/ak-status-label"; | import "@goauthentik/components/ak-status-label"; | ||||||
| import "@goauthentik/elements/chips/Chip"; | import "@goauthentik/elements/chips/Chip"; | ||||||
| import "@goauthentik/elements/chips/ChipGroup"; | import "@goauthentik/elements/chips/ChipGroup"; | ||||||
| @ -93,7 +93,7 @@ export class UserOAuthRefreshTokenList extends Table<TokenModel> { | |||||||
|                 bad-label=${msg("Yes")} |                 bad-label=${msg("Yes")} | ||||||
|             ></ak-status-label>`, |             ></ak-status-label>`, | ||||||
|             html`${item.expires |             html`${item.expires | ||||||
|                 ? html`<div>${getRelativeTime(item.expires)}</div> |                 ? html`<div>${formatElapsedTime(item.expires)}</div> | ||||||
|                       <small>${item.expires.toLocaleString()}</small>` |                       <small>${item.expires.toLocaleString()}</small>` | ||||||
|                 : msg("-")}`, |                 : msg("-")}`, | ||||||
|             html`<ak-chip-group> |             html`<ak-chip-group> | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import { EVENT_REFRESH } from "@goauthentik/common/constants"; | import { EVENT_REFRESH } from "@goauthentik/common/constants"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import "@goauthentik/components/ak-status-label"; | import "@goauthentik/components/ak-status-label"; | ||||||
| import { AKElement } from "@goauthentik/elements/Base"; | import { AKElement } from "@goauthentik/elements/Base"; | ||||||
| import "@goauthentik/elements/EmptyState"; | import "@goauthentik/elements/EmptyState"; | ||||||
| @ -71,7 +71,7 @@ export class SyncStatusTable extends Table<SystemTask> { | |||||||
|                 good-label=${msg("Finished successfully")} |                 good-label=${msg("Finished successfully")} | ||||||
|                 bad-label=${msg("Finished with errors")} |                 bad-label=${msg("Finished with errors")} | ||||||
|             ></ak-status-label>`, |             ></ak-status-label>`, | ||||||
|             html`<div>${getRelativeTime(item.finishTimestamp)}</div> |             html`<div>${formatElapsedTime(item.finishTimestamp)}</div> | ||||||
|                 <small>${item.finishTimestamp.toLocaleString()}</small>`, |                 <small>${item.finishTimestamp.toLocaleString()}</small>`, | ||||||
|         ]; |         ]; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import "@goauthentik/elements/forms/DeleteBulkForm"; | import "@goauthentik/elements/forms/DeleteBulkForm"; | ||||||
| import { PaginatedResponse } from "@goauthentik/elements/table/Table"; | import { PaginatedResponse } from "@goauthentik/elements/table/Table"; | ||||||
| import { Table, TableColumn } from "@goauthentik/elements/table/Table"; | import { Table, TableColumn } from "@goauthentik/elements/table/Table"; | ||||||
| @ -73,9 +73,9 @@ export class AuthenticatedSessionList extends Table<AuthenticatedSession> { | |||||||
|                     ${item.lastIp} |                     ${item.lastIp} | ||||||
|                 </div> |                 </div> | ||||||
|                 <small>${item.userAgent.userAgent?.family}, ${item.userAgent.os?.family}</small>`, |                 <small>${item.userAgent.userAgent?.family}, ${item.userAgent.os?.family}</small>`, | ||||||
|             html`<div>${getRelativeTime(item.lastUsed)}</div> |             html`<div>${formatElapsedTime(item.lastUsed)}</div> | ||||||
|                 <small>${item.lastUsed?.toLocaleString()}</small>`, |                 <small>${item.lastUsed?.toLocaleString()}</small>`, | ||||||
|             html`<div>${getRelativeTime(item.expires || new Date())}</div> |             html`<div>${formatElapsedTime(item.expires || new Date())}</div> | ||||||
|                 <small>${item.expires?.toLocaleString()}</small>`, |                 <small>${item.expires?.toLocaleString()}</small>`, | ||||||
|         ]; |         ]; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import "@goauthentik/elements/chips/Chip"; | import "@goauthentik/elements/chips/Chip"; | ||||||
| import "@goauthentik/elements/chips/ChipGroup"; | import "@goauthentik/elements/chips/ChipGroup"; | ||||||
| import "@goauthentik/elements/forms/DeleteBulkForm"; | import "@goauthentik/elements/forms/DeleteBulkForm"; | ||||||
| @ -62,7 +62,7 @@ export class UserConsentList extends Table<UserConsent> { | |||||||
|         return [ |         return [ | ||||||
|             html`${item.application.name}`, |             html`${item.application.name}`, | ||||||
|             html`${item.expires && item.expiring |             html`${item.expires && item.expiring | ||||||
|                 ? html`<div>${getRelativeTime(item.expires)}</div> |                 ? html`<div>${formatElapsedTime(item.expires)}</div> | ||||||
|                       <small>${item.expires.toLocaleString()}</small>` |                       <small>${item.expires.toLocaleString()}</small>` | ||||||
|                 : msg("-")}`, |                 : msg("-")}`, | ||||||
|             html`${item.permissions |             html`${item.permissions | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import "@goauthentik/elements/forms/DeleteBulkForm"; | import "@goauthentik/elements/forms/DeleteBulkForm"; | ||||||
| import { PaginatedResponse } from "@goauthentik/elements/table/Table"; | import { PaginatedResponse } from "@goauthentik/elements/table/Table"; | ||||||
| import { Table, TableColumn } from "@goauthentik/elements/table/Table"; | import { Table, TableColumn } from "@goauthentik/elements/table/Table"; | ||||||
| @ -73,7 +73,7 @@ export class UserReputationList extends Table<Reputation> { | |||||||
|                 : html``} |                 : html``} | ||||||
|             ${item.ip}`, |             ${item.ip}`, | ||||||
|             html`${item.score}`, |             html`${item.score}`, | ||||||
|             html`<div>${getRelativeTime(item.updated)}</div> |             html`<div>${formatElapsedTime(item.updated)}</div> | ||||||
|                 <small>${item.updated.toLocaleString()}</small>`, |                 <small>${item.updated.toLocaleString()}</small>`, | ||||||
|         ]; |         ]; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ import { AndNext, DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | |||||||
| import { globalAK } from "@goauthentik/common/global"; | import { globalAK } from "@goauthentik/common/global"; | ||||||
| import { deviceTypeName } from "@goauthentik/common/labels"; | import { deviceTypeName } from "@goauthentik/common/labels"; | ||||||
| import { SentryIgnoredError } from "@goauthentik/common/sentry"; | import { SentryIgnoredError } from "@goauthentik/common/sentry"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import "@goauthentik/elements/buttons/Dropdown"; | import "@goauthentik/elements/buttons/Dropdown"; | ||||||
| import "@goauthentik/elements/buttons/ModalButton"; | import "@goauthentik/elements/buttons/ModalButton"; | ||||||
| import "@goauthentik/elements/buttons/TokenCopyButton"; | import "@goauthentik/elements/buttons/TokenCopyButton"; | ||||||
| @ -133,11 +133,11 @@ export class MFADevicesPage extends Table<Device> { | |||||||
|             html`${deviceTypeName(item)} |             html`${deviceTypeName(item)} | ||||||
|             ${item.extraDescription ? ` - ${item.extraDescription}` : ""}`, |             ${item.extraDescription ? ` - ${item.extraDescription}` : ""}`, | ||||||
|             html`${item.created.getTime() > 0 |             html`${item.created.getTime() > 0 | ||||||
|                 ? html`<div>${getRelativeTime(item.created)}</div> |                 ? html`<div>${formatElapsedTime(item.created)}</div> | ||||||
|                       <small>${item.created.toLocaleString()}</small>` |                       <small>${item.created.toLocaleString()}</small>` | ||||||
|                 : html`-`}`, |                 : html`-`}`, | ||||||
|             html`${item.lastUsed |             html`${item.lastUsed | ||||||
|                 ? html`<div>${getRelativeTime(item.lastUsed)}</div> |                 ? html`<div>${formatElapsedTime(item.lastUsed)}</div> | ||||||
|                       <small>${item.lastUsed.toLocaleString()}</small>` |                       <small>${item.lastUsed.toLocaleString()}</small>` | ||||||
|                 : html`-`}`, |                 : html`-`}`, | ||||||
|             html` |             html` | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { dateTimeLocal } from "@goauthentik/common/utils"; | import { dateTimeLocal } from "@goauthentik/common/temporal"; | ||||||
| import "@goauthentik/elements/forms/HorizontalFormElement"; | import "@goauthentik/elements/forms/HorizontalFormElement"; | ||||||
| import { ModelForm } from "@goauthentik/elements/forms/ModelForm"; | import { ModelForm } from "@goauthentik/elements/forms/ModelForm"; | ||||||
|  |  | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||||
| import { intentToLabel } from "@goauthentik/common/labels"; | import { intentToLabel } from "@goauthentik/common/labels"; | ||||||
|  | import { formatElapsedTime } from "@goauthentik/common/temporal"; | ||||||
| import { me } from "@goauthentik/common/users"; | import { me } from "@goauthentik/common/users"; | ||||||
| import { getRelativeTime } from "@goauthentik/common/utils"; |  | ||||||
| import "@goauthentik/components/ak-status-label"; | import "@goauthentik/components/ak-status-label"; | ||||||
| import "@goauthentik/elements/buttons/Dropdown"; | import "@goauthentik/elements/buttons/Dropdown"; | ||||||
| import "@goauthentik/elements/buttons/ModalButton"; | import "@goauthentik/elements/buttons/ModalButton"; | ||||||
| @ -110,7 +110,7 @@ export class UserTokenList extends Table<Token> { | |||||||
|                                               position="top" |                                               position="top" | ||||||
|                                               .content=${item.expires?.toLocaleString()} |                                               .content=${item.expires?.toLocaleString()} | ||||||
|                                           > |                                           > | ||||||
|                                               ${getRelativeTime(item.expires!)} |                                               ${formatElapsedTime(item.expires!)} | ||||||
|                                           </pf-tooltip>` |                                           </pf-tooltip>` | ||||||
|                                         : msg("-")} |                                         : msg("-")} | ||||||
|                                 </div> |                                 </div> | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Teffen Ellis
					Teffen Ellis