web/admin: revamped rbac and user settings tabs (#8299)
* web/admin: fix duplicate RBAC preview banner on permission modal Signed-off-by: Jens Langhammer <jens@goauthentik.io> * switch non-embedded permission page to use vertical tabs Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix some leftover html? Signed-off-by: Jens Langhammer <jens@goauthentik.io> * move stuff into vertical subtab Signed-off-by: Jens Langhammer <jens@goauthentik.io> * show all of users permission tabs on one main tab Signed-off-by: Jens Langhammer <jens@goauthentik.io> * rework role page to match user page Signed-off-by: Jens Langhammer <jens@goauthentik.io> * use separate tabs Signed-off-by: Jens Langhammer <jens@goauthentik.io> * rename role permission tables to match user tables Signed-off-by: Jens Langhammer <jens@goauthentik.io> * rename to credentials and tokens Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add country icon to session list Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add oauth access token list Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add helper to get relative time Signed-off-by: Jens Langhammer <jens@goauthentik.io> * use pfdivider Signed-off-by: Jens Langhammer <jens@goauthentik.io> * replace plain hr with pf-c-divider Signed-off-by: Jens Langhammer <jens@goauthentik.io> * use new logic for showing relative time in charts Signed-off-by: Jens Langhammer <jens@goauthentik.io> * use consistent relative time for event display Signed-off-by: Jens Langhammer <jens@goauthentik.io> * remove more leftovers Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix some alignment issues on the admin dashboard Signed-off-by: Jens Langhammer <jens@goauthentik.io> * update storybook map Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add sanity check to event app lookup Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make api drawer header fixed Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix table padding for toggle Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix notification drawer for user interface Signed-off-by: Jens Langhammer <jens@goauthentik.io> * enable system task search Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix formatting, exclude generated script from formatting Signed-off-by: Jens Langhammer <jens@goauthentik.io> * web: minor fixes There's a renderer (it's not a component, not yet) for producing definition lists without the risk of missing a class or tag. Breaking conditionally rendered components out to make their use easier to identify. * fix prettier Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix outpost form Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix more flaky tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> * re-create locale Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add some description for different permission views Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix system task search Signed-off-by: Jens Langhammer <jens@goauthentik.io> * update docs Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> Co-authored-by: Ken Sternberg <ken@goauthentik.io>
This commit is contained in:
		| @ -86,7 +86,6 @@ class NotificationTransportViewSet(UsedByMixin, ModelViewSet): | ||||
|         event = Event.new( | ||||
|             action="notification_test", | ||||
|             user=get_user(request.user), | ||||
|             app=self.__class__.__module__, | ||||
|             context={"foo": "bar"}, | ||||
|         ) | ||||
|         event.save() | ||||
|  | ||||
| @ -209,8 +209,9 @@ class Event(SerializerModel, ExpiringModel): | ||||
|             app = parent.f_globals["__name__"] | ||||
|             # Attempt to match the calling module to the django app it belongs to | ||||
|             # if we can't find a match, keep the module name | ||||
|             django_apps = get_close_matches(app, django_app_names(), n=1) | ||||
|             if len(django_apps) > 0: | ||||
|             django_apps: list[str] = get_close_matches(app, django_app_names(), n=1) | ||||
|             # Also ensure that closest django app has the correct prefix | ||||
|             if len(django_apps) > 0 and django_apps[0].startswith(app): | ||||
|                 app = django_apps[0] | ||||
|         cleaned_kwargs = cleanse_dict(sanitize_dict(kwargs)) | ||||
|         event = Event(action=action, app=app, context=cleaned_kwargs) | ||||
|  | ||||
| @ -70,7 +70,7 @@ class TestRecovery(TenantAPITestCase): | ||||
|         body = loads(response.content.decode()) | ||||
|         token = Token.objects.get(intent=TokenIntents.INTENT_RECOVERY, user=self.user) | ||||
|         self.assertIn(token.key, body["url"]) | ||||
|         self.assertEqual(len(Token.objects.all()), 1) | ||||
|         self.assertEqual(len(Token.objects.filter(intent=TokenIntents.INTENT_RECOVERY)), 1) | ||||
|  | ||||
|     @CONFIG.patch("outposts.disable_embedded_outpost", True) | ||||
|     @CONFIG.patch("tenants.enabled", True) | ||||
| @ -86,4 +86,4 @@ class TestRecovery(TenantAPITestCase): | ||||
|             headers=HEADERS, | ||||
|         ) | ||||
|         self.assertEqual(response.status_code, 404) | ||||
|         self.assertEqual(len(Token.objects.all()), 0) | ||||
|         self.assertEqual(len(Token.objects.filter(intent=TokenIntents.INTENT_RECOVERY)), 0) | ||||
|  | ||||
| @ -11,3 +11,4 @@ src/locales/ | ||||
| storybook-static/ | ||||
| # Prettier breaks the tsconfig file | ||||
| tsconfig.json | ||||
| .storybook/css-import-maps* | ||||
|  | ||||
| @ -27,6 +27,7 @@ const rawCssImportMaps = [ | ||||
|     'import PFDataList from "@patternfly/patternfly/components/DataList/data-list.css";', | ||||
|     'import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css";', | ||||
|     'import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css";', | ||||
|     'import PFDivider from "@patternfly/patternfly/components/Divider/divider.css";', | ||||
|     'import PFDrawer from "@patternfly/patternfly/components/Drawer/drawer.css";', | ||||
|     'import PFDropdown from "@patternfly/patternfly/components/Dropdown/dropdown.css";', | ||||
|     'import PFDualListSelector from "@patternfly/patternfly/components/DualListSelector/dual-list-selector.css";', | ||||
| @ -70,10 +71,8 @@ const rawCssImportMaps = [ | ||||
|     'import styles from "./LibraryPageImpl.css";', | ||||
| ]; | ||||
|  | ||||
| const cssImportMaps = rawCssImportMaps.reduce( | ||||
|     (acc, line) => ({ ...acc, [line]: line.replace(/\.css/, ".css?inline") }), | ||||
|     {}, | ||||
| ); | ||||
| const cssImportMaps = rawCssImportMaps.reduce((acc, line) => ( | ||||
| {...acc, [line]: line.replace(/\.css/, ".css?inline")}), {}); | ||||
|  | ||||
| export { cssImportMaps }; | ||||
| export default cssImportMaps; | ||||
|  | ||||
| @ -63,8 +63,7 @@ function getTheImportLines(importPaths: string[]) { | ||||
| const importPaths = getTheSourceFiles(); | ||||
| const importLines = getTheImportLines(importPaths); | ||||
|  | ||||
| const outputFile = ` | ||||
| // THIS IS A GENERATED FILE.  DO NOT EDIT BY HAND. | ||||
| const outputFile = `// THIS IS A GENERATED FILE.  DO NOT EDIT BY HAND. | ||||
| // | ||||
| // This file is generated by the build-storybook-import-maps script in the UI's base directory. | ||||
| // This is a *hack* to work around an inconsistency in the way rollup, vite, and storybook | ||||
|  | ||||
| @ -19,6 +19,7 @@ import { CSSResult, TemplateResult, css, html } from "lit"; | ||||
| import { customElement, state } from "lit/decorators.js"; | ||||
|  | ||||
| import PFContent from "@patternfly/patternfly/components/Content/content.css"; | ||||
| import PFDivider from "@patternfly/patternfly/components/Divider/divider.css"; | ||||
| import PFList from "@patternfly/patternfly/components/List/list.css"; | ||||
| import PFPage from "@patternfly/patternfly/components/Page/page.css"; | ||||
| import PFGrid from "@patternfly/patternfly/layouts/Grid/grid.css"; | ||||
| @ -41,15 +42,12 @@ export class AdminOverviewPage extends AKElement { | ||||
|             PFPage, | ||||
|             PFContent, | ||||
|             PFList, | ||||
|             PFDivider, | ||||
|             css` | ||||
|                 .row-divider { | ||||
|                     margin-top: -4px; | ||||
|                     margin-bottom: -4px; | ||||
|                 .pf-l-grid__item { | ||||
|                     height: 100%; | ||||
|                 } | ||||
|                 .graph-container { | ||||
|                     height: 20em; | ||||
|                 } | ||||
|                 .big-graph-container { | ||||
|                 .pf-l-grid__item.big-graph-container { | ||||
|                     height: 35em; | ||||
|                 } | ||||
|                 .card-container { | ||||
| @ -82,9 +80,7 @@ export class AdminOverviewPage extends AKElement { | ||||
|                 <div class="pf-l-grid pf-m-gutter"> | ||||
|                     <!-- row 1 --> | ||||
|                     <div class="pf-l-grid__item pf-m-6-col pf-l-grid pf-m-gutter"> | ||||
|                         <div | ||||
|                             class="pf-l-grid__item pf-m-12-col pf-m-6-col-on-xl pf-m-4-col-on-2xl graph-container" | ||||
|                         > | ||||
|                         <div class="pf-l-grid__item pf-m-12-col pf-m-6-col-on-xl pf-m-4-col-on-2xl"> | ||||
|                             <ak-aggregate-card | ||||
|                                 icon="fa fa-share" | ||||
|                                 header=${msg("Quick actions")} | ||||
| @ -136,9 +132,7 @@ export class AdminOverviewPage extends AKElement { | ||||
|                                 </ul> | ||||
|                             </ak-aggregate-card> | ||||
|                         </div> | ||||
|                         <div | ||||
|                             class="pf-l-grid__item pf-m-12-col pf-m-6-col-on-xl pf-m-4-col-on-2xl graph-container" | ||||
|                         > | ||||
|                         <div class="pf-l-grid__item pf-m-12-col pf-m-6-col-on-xl pf-m-4-col-on-2xl"> | ||||
|                             <ak-aggregate-card | ||||
|                                 icon="pf-icon pf-icon-zone" | ||||
|                                 header=${msg("Outpost status")} | ||||
| @ -148,14 +142,14 @@ export class AdminOverviewPage extends AKElement { | ||||
|                             </ak-aggregate-card> | ||||
|                         </div> | ||||
|                         <div | ||||
|                             class="pf-l-grid__item pf-m-12-col pf-m-12-col-on-xl pf-m-4-col-on-2xl graph-container" | ||||
|                             class="pf-l-grid__item pf-m-12-col pf-m-12-col-on-xl pf-m-4-col-on-2xl" | ||||
|                         > | ||||
|                             <ak-aggregate-card icon="fa fa-sync-alt" header=${msg("Sync status")}> | ||||
|                                 <ak-admin-status-chart-sync></ak-admin-status-chart-sync> | ||||
|                             </ak-aggregate-card> | ||||
|                         </div> | ||||
|                         <div class="pf-l-grid__item pf-m-12-col row-divider"> | ||||
|                             <hr /> | ||||
|                         <div class="pf-l-grid__item pf-m-12-col"> | ||||
|                             <hr class="pf-c-divider" /> | ||||
|                         </div> | ||||
|                         <div | ||||
|                             class="pf-l-grid__item pf-m-6-col pf-m-4-col-on-md pf-m-4-col-on-xl card-container" | ||||
| @ -176,8 +170,8 @@ export class AdminOverviewPage extends AKElement { | ||||
|                     <div class="pf-l-grid__item pf-m-6-col"> | ||||
|                         <ak-recent-events pageSize="6"></ak-recent-events> | ||||
|                     </div> | ||||
|                     <div class="pf-l-grid__item pf-m-12-col row-divider"> | ||||
|                         <hr /> | ||||
|                     <div class="pf-l-grid__item pf-m-12-col"> | ||||
|                         <hr class="pf-c-divider" /> | ||||
|                     </div> | ||||
|                     <!-- row 3 --> | ||||
|                     <div | ||||
|  | ||||
| @ -8,6 +8,7 @@ import { CSSResult, TemplateResult, css, html } from "lit"; | ||||
| import { customElement } from "lit/decorators.js"; | ||||
|  | ||||
| import PFContent from "@patternfly/patternfly/components/Content/content.css"; | ||||
| import PFDivider from "@patternfly/patternfly/components/Divider/divider.css"; | ||||
| import PFList from "@patternfly/patternfly/components/List/list.css"; | ||||
| import PFPage from "@patternfly/patternfly/components/Page/page.css"; | ||||
| import PFGrid from "@patternfly/patternfly/layouts/Grid/grid.css"; | ||||
| @ -22,14 +23,8 @@ export class DashboardUserPage extends AKElement { | ||||
|             PFPage, | ||||
|             PFContent, | ||||
|             PFList, | ||||
|             PFDivider, | ||||
|             css` | ||||
|                 .row-divider { | ||||
|                     margin-top: -4px; | ||||
|                     margin-bottom: -4px; | ||||
|                 } | ||||
|                 .graph-container { | ||||
|                     height: 20em; | ||||
|                 } | ||||
|                 .big-graph-container { | ||||
|                     height: 35em; | ||||
|                 } | ||||
| @ -59,8 +54,8 @@ export class DashboardUserPage extends AKElement { | ||||
|                             </ak-charts-admin-model-per-day> | ||||
|                         </ak-aggregate-card> | ||||
|                     </div> | ||||
|                     <div class="pf-l-grid__item pf-m-12-col row-divider"> | ||||
|                         <hr /> | ||||
|                     <div class="pf-l-grid__item pf-m-12-col"> | ||||
|                         <hr class="pf-c-divider" /> | ||||
|                     </div> | ||||
|                     <!-- row 2 --> | ||||
|                     <div | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| import { EventGeo, EventUser } from "@goauthentik/admin/events/utils"; | ||||
| import { getRelativeTime } from "@goauthentik/app/common/utils"; | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { EventWithContext } from "@goauthentik/common/events"; | ||||
| import { actionToLabel } from "@goauthentik/common/labels"; | ||||
| @ -71,7 +72,8 @@ export class RecentEventsCard extends Table<Event> { | ||||
|             html`<div><a href="${`#/events/log/${item.pk}`}">${actionToLabel(item.action)}</a></div> | ||||
|                 <small>${item.app}</small>`, | ||||
|             EventUser(item), | ||||
|             html`<span>${item.created?.toLocaleString()}</span>`, | ||||
|             html`<div>${getRelativeTime(item.created)}</div> | ||||
|                 <small>${item.created.toLocaleString()}</small>`, | ||||
|             html` <div>${item.clientIp || msg("-")}</div> | ||||
|                 <small>${EventGeo(item)}</small>`, | ||||
|             html`<span>${item.brand?.name || msg("-")}</span>`, | ||||
|  | ||||
| @ -1,8 +1,8 @@ | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { AKChart, RGBAColor } from "@goauthentik/elements/charts/Chart"; | ||||
| import { ChartData, Tick } from "chart.js"; | ||||
| import { ChartData } from "chart.js"; | ||||
|  | ||||
| import { msg, str } from "@lit/localize"; | ||||
| import { msg } from "@lit/localize"; | ||||
| import { customElement } from "lit/decorators.js"; | ||||
|  | ||||
| import { AdminApi, LoginMetrics } from "@goauthentik/api"; | ||||
| @ -13,13 +13,6 @@ export class AdminLoginAuthorizeChart extends AKChart<LoginMetrics> { | ||||
|         return new AdminApi(DEFAULT_CONFIG).adminMetricsRetrieve(); | ||||
|     } | ||||
|  | ||||
|     timeTickCallback(tickValue: string | number, index: number, ticks: Tick[]): string { | ||||
|         const valueStamp = ticks[index]; | ||||
|         const delta = Date.now() - valueStamp.value; | ||||
|         const ago = Math.round(delta / 1000 / 3600 / 24); | ||||
|         return msg(str`${ago} day(s) ago`); | ||||
|     } | ||||
|  | ||||
|     getChartData(data: LoginMetrics): ChartData { | ||||
|         return { | ||||
|             datasets: [ | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| import "@goauthentik/admin/events/EventVolumeChart"; | ||||
| import { EventGeo, EventUser } from "@goauthentik/admin/events/utils"; | ||||
| import { getRelativeTime } from "@goauthentik/app/common/utils"; | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { EventWithContext } from "@goauthentik/common/events"; | ||||
| import { actionToLabel } from "@goauthentik/common/labels"; | ||||
| @ -82,9 +83,9 @@ export class EventListPage extends TablePage<Event> { | ||||
|             html`<div>${actionToLabel(item.action)}</div> | ||||
|                 <small>${item.app}</small>`, | ||||
|             EventUser(item), | ||||
|             html`<span>${item.created?.toLocaleString()}</span>`, | ||||
|             html`<div>${getRelativeTime(item.created)}</div> | ||||
|                 <small>${item.created.toLocaleString()}</small>`, | ||||
|             html`<div>${item.clientIp || msg("-")}</div> | ||||
|  | ||||
|                 <small>${EventGeo(item)}</small>`, | ||||
|             html`<span>${item.brand?.name || msg("-")}</span>`, | ||||
|             html`<a href="#/events/log/${item.pk}"> | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| import { EventGeo, EventUser } from "@goauthentik/admin/events/utils"; | ||||
| import { getRelativeTime } from "@goauthentik/app/common/utils"; | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { EventWithContext } from "@goauthentik/common/events"; | ||||
| import { actionToLabel } from "@goauthentik/common/labels"; | ||||
| @ -99,7 +100,8 @@ export class EventViewPage extends AKElement { | ||||
|                                     </dt> | ||||
|                                     <dd class="pf-c-description-list__description"> | ||||
|                                         <div class="pf-c-description-list__text"> | ||||
|                                             ${this.event.created?.toLocaleString()} | ||||
|                                             <div>${getRelativeTime(this.event.created)}</div> | ||||
|                                             <small>${this.event.created.toLocaleString()}</small> | ||||
|                                         </div> | ||||
|                                     </dd> | ||||
|                                 </div> | ||||
|  | ||||
| @ -230,6 +230,7 @@ export class OutpostForm extends ModelForm<Outpost, string> { | ||||
|             </ak-form-element-horizontal> | ||||
|             <ak-form-group aria-label="Advanced settings"> | ||||
|                 <span slot="header"> ${msg("Advanced settings")} </span> | ||||
|                 <div slot="body" class="pf-c-form"> | ||||
|                     <ak-form-element-horizontal label=${msg("Configuration")} name="config"> | ||||
|                         <ak-codemirror | ||||
|                             mode=${CodeMirrorMode.YAML} | ||||
| @ -244,11 +245,14 @@ export class OutpostForm extends ModelForm<Outpost, string> { | ||||
|                             ${msg("See more here:")}  | ||||
|                             <a | ||||
|                                 target="_blank" | ||||
|                             href="${docLink("/docs/outposts?utm_source=authentik#configuration")}" | ||||
|                                 href="${docLink( | ||||
|                                     "/docs/outposts?utm_source=authentik#configuration", | ||||
|                                 )}" | ||||
|                                 >${msg("Documentation")}</a | ||||
|                             > | ||||
|                         </p> | ||||
|                     </ak-form-element-horizontal> | ||||
|                 </div> | ||||
|             </ak-form-group>`; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -22,6 +22,7 @@ import PFButton from "@patternfly/patternfly/components/Button/button.css"; | ||||
| import PFCard from "@patternfly/patternfly/components/Card/card.css"; | ||||
| import PFContent from "@patternfly/patternfly/components/Content/content.css"; | ||||
| import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css"; | ||||
| import PFDivider from "@patternfly/patternfly/components/Divider/divider.css"; | ||||
| import PFForm from "@patternfly/patternfly/components/Form/form.css"; | ||||
| import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; | ||||
| import PFPage from "@patternfly/patternfly/components/Page/page.css"; | ||||
| @ -70,6 +71,7 @@ export class OAuth2ProviderViewPage extends AKElement { | ||||
|             PFForm, | ||||
|             PFFormControl, | ||||
|             PFBanner, | ||||
|             PFDivider, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
| @ -258,7 +260,7 @@ export class OAuth2ProviderViewPage extends AKElement { | ||||
|                                     value="${this.providerUrls?.issuer || msg("-")}" | ||||
|                                 /> | ||||
|                             </div> | ||||
|                             <hr /> | ||||
|                             <hr class="pf-c-divider" /> | ||||
|                             <div class="pf-c-form__group"> | ||||
|                                 <label class="pf-c-form__label"> | ||||
|                                     <span class="pf-c-form__label-text" | ||||
|  | ||||
| @ -11,8 +11,8 @@ import { ifDefined } from "lit/directives/if-defined.js"; | ||||
| 
 | ||||
| import { Permission, RbacApi } from "@goauthentik/api"; | ||||
| 
 | ||||
| @customElement("ak-role-permissions-global-table") | ||||
| export class RolePermissionGlobalTable extends Table<Permission> { | ||||
| @customElement("ak-role-assigned-global-permissions-table") | ||||
| export class RoleAssignedGlobalPermissionsTable extends Table<Permission> { | ||||
|     @property() | ||||
|     roleUuid?: string; | ||||
| 
 | ||||
| @ -10,8 +10,8 @@ import { customElement, property } from "lit/decorators.js"; | ||||
| 
 | ||||
| import { ExtraRoleObjectPermission, ModelEnum, RbacApi } from "@goauthentik/api"; | ||||
| 
 | ||||
| @customElement("ak-role-permissions-object-table") | ||||
| export class RolePermissionObjectTable extends Table<ExtraRoleObjectPermission> { | ||||
| @customElement("ak-role-assigned-object-permissions-table") | ||||
| export class RoleAssignedObjectPermissionTable extends Table<ExtraRoleObjectPermission> { | ||||
|     @property() | ||||
|     roleUuid?: string; | ||||
| 
 | ||||
| @ -1,21 +1,20 @@ | ||||
| import "@goauthentik/admin/groups/RelatedGroupList"; | ||||
| import "@goauthentik/app/admin/roles/RolePermissionGlobalTable"; | ||||
| import "@goauthentik/app/admin/roles/RolePermissionObjectTable"; | ||||
| import "@goauthentik/admin/roles/RoleForm"; | ||||
| import "@goauthentik/app/elements/rbac/ObjectPermissionsPage"; | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { EVENT_REFRESH } from "@goauthentik/common/constants"; | ||||
| import { renderDescriptionList } from "@goauthentik/components/DescriptionList"; | ||||
| import "@goauthentik/components/events/ObjectChangelog"; | ||||
| import "@goauthentik/components/events/UserEvents"; | ||||
| import { AKElement } from "@goauthentik/elements/Base"; | ||||
| import "@goauthentik/elements/CodeMirror"; | ||||
| import "@goauthentik/elements/PageHeader"; | ||||
| import "@goauthentik/elements/Tabs"; | ||||
| import "@goauthentik/elements/forms/ModalForm"; | ||||
|  | ||||
| import { msg, str } from "@lit/localize"; | ||||
| import { CSSResult, TemplateResult, css, html } from "lit"; | ||||
| import { css, html, nothing } from "lit"; | ||||
| import { customElement, property, state } from "lit/decorators.js"; | ||||
|  | ||||
| import PFBanner from "@patternfly/patternfly/components/Banner/banner.css"; | ||||
| import PFButton from "@patternfly/patternfly/components/Button/button.css"; | ||||
| import PFCard from "@patternfly/patternfly/components/Card/card.css"; | ||||
| import PFContent from "@patternfly/patternfly/components/Content/content.css"; | ||||
| @ -43,7 +42,7 @@ export class RoleViewPage extends AKElement { | ||||
|     @state() | ||||
|     _role?: Role; | ||||
|  | ||||
|     static get styles(): CSSResult[] { | ||||
|     static get styles() { | ||||
|         return [ | ||||
|             PFBase, | ||||
|             PFPage, | ||||
| @ -53,7 +52,6 @@ export class RoleViewPage extends AKElement { | ||||
|             PFContent, | ||||
|             PFCard, | ||||
|             PFDescriptionList, | ||||
|             PFBanner, | ||||
|             css` | ||||
|                 .pf-c-description-list__description ak-action-button { | ||||
|                     margin-right: 6px; | ||||
| @ -74,7 +72,7 @@ export class RoleViewPage extends AKElement { | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     render(): TemplateResult { | ||||
|     render() { | ||||
|         return html`<ak-page-header | ||||
|                 icon="fa fa-lock" | ||||
|                 header=${msg(str`Role ${this._role?.name || ""}`)} | ||||
| @ -83,15 +81,23 @@ export class RoleViewPage extends AKElement { | ||||
|             ${this.renderBody()}`; | ||||
|     } | ||||
|  | ||||
|     renderBody(): TemplateResult { | ||||
|         if (!this._role) { | ||||
|             return html``; | ||||
|     renderUpdateControl(role: Role) { | ||||
|         return html` <div class="pf-c-description-list__text"> | ||||
|             <ak-forms-modal> | ||||
|                 <span slot="submit"> ${msg("Update")} </span> | ||||
|                 <span slot="header"> ${msg("Update Role")} </span> | ||||
|                 <ak-role-form slot="form" .instancePk=${role.pk}> </ak-role-form> | ||||
|                 <button slot="trigger" class="pf-c-button pf-m-primary">${msg("Edit")}</button> | ||||
|             </ak-forms-modal> | ||||
|         </div>`; | ||||
|     } | ||||
|         return html`<div class="pf-c-banner pf-m-info"> | ||||
|                 ${msg("RBAC is in preview.")} | ||||
|                 <a href="mailto:hello@goauthentik.io">${msg("Send us feedback!")}</a> | ||||
|             </div> | ||||
|             <ak-tabs> | ||||
|  | ||||
|     renderBody() { | ||||
|         if (!this._role) { | ||||
|             return nothing; | ||||
|         } | ||||
|  | ||||
|         return html` <ak-tabs> | ||||
|             <section | ||||
|                 slot="page-overview" | ||||
|                 data-tab-title="${msg("Overview")}" | ||||
| @ -103,42 +109,23 @@ export class RoleViewPage extends AKElement { | ||||
|                     > | ||||
|                         <div class="pf-c-card__title">${msg("Role Info")}</div> | ||||
|                         <div class="pf-c-card__body"> | ||||
|                                 <dl class="pf-c-description-list"> | ||||
|                                     <div class="pf-c-description-list__group"> | ||||
|                                         <dt class="pf-c-description-list__term"> | ||||
|                                             <span class="pf-c-description-list__text" | ||||
|                                                 >${msg("Name")}</span | ||||
|                                             > | ||||
|                                         </dt> | ||||
|                                         <dd class="pf-c-description-list__description"> | ||||
|                                             <div class="pf-c-description-list__text"> | ||||
|                                                 ${this._role.name} | ||||
|                                             </div> | ||||
|                                         </dd> | ||||
|                                     </div> | ||||
|                                 </dl> | ||||
|                             ${renderDescriptionList([ | ||||
|                                 [msg("Name"), this._role.name], | ||||
|                                 [msg("Edit"), this.renderUpdateControl(this._role)], | ||||
|                             ])} | ||||
|                         </div> | ||||
|                     </div> | ||||
|                     <div | ||||
|                         class="pf-c-card pf-l-grid__item pf-m-12-col pf-m-9-col-on-xl pf-m-9-col-on-2xl" | ||||
|                     > | ||||
|                             <div class="pf-c-card__title"> | ||||
|                                 ${msg("Assigned global permissions")} | ||||
|                             </div> | ||||
|                         <div class="pf-c-card__title">${msg("Changelog")}</div> | ||||
|                         <div class="pf-c-card__body"> | ||||
|                                 <ak-role-permissions-global-table | ||||
|                                     roleUuid=${this._role.pk} | ||||
|                                 ></ak-role-permissions-global-table> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                         <div class="pf-c-card pf-l-grid__item pf-m-12-col"> | ||||
|                             <div class="pf-c-card__title"> | ||||
|                                 ${msg("Assigned object permissions")} | ||||
|                             </div> | ||||
|                             <div class="pf-c-card__body"> | ||||
|                                 <ak-role-permissions-object-table | ||||
|                                     roleUuid=${this._role.pk} | ||||
|                                 ></ak-role-permissions-object-table> | ||||
|                             <ak-object-changelog | ||||
|                                 targetModelPk=${this.roleId} | ||||
|                                 targetModelApp="authentik_rbac" | ||||
|                                 targetModelName="role" | ||||
|                             > | ||||
|                             </ak-object-changelog> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
| @ -148,7 +135,6 @@ export class RoleViewPage extends AKElement { | ||||
|                 data-tab-title="${msg("Permissions")}" | ||||
|                 model=${RbacPermissionsAssignedByUsersListModelEnum.RbacRole} | ||||
|                 objectPk=${this._role.pk} | ||||
|                     .showBanner=${false} | ||||
|             ></ak-rbac-object-permission-page> | ||||
|         </ak-tabs>`; | ||||
|     } | ||||
|  | ||||
| @ -31,6 +31,10 @@ export class SystemTaskListPage extends TablePage<SystemTask> { | ||||
|  | ||||
|     expandable = true; | ||||
|  | ||||
|     searchEnabled(): boolean { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     @property() | ||||
|     order = "name"; | ||||
|  | ||||
|  | ||||
| @ -3,13 +3,13 @@ import "@goauthentik/admin/users/UserActiveForm"; | ||||
| import "@goauthentik/admin/users/UserChart"; | ||||
| import "@goauthentik/admin/users/UserForm"; | ||||
| import "@goauthentik/admin/users/UserPasswordForm"; | ||||
| import "@goauthentik/app/admin/users/UserAssignedGlobalPermissionsTable"; | ||||
| import "@goauthentik/app/admin/users/UserAssignedObjectPermissionsTable"; | ||||
| import { | ||||
|     renderRecoveryEmailRequest, | ||||
|     requestRecoveryLink, | ||||
| } from "@goauthentik/app/admin/users/UserListPage"; | ||||
| import { me } from "@goauthentik/app/common/users"; | ||||
| import "@goauthentik/app/elements/oauth/UserAccessTokenList"; | ||||
| import "@goauthentik/app/elements/oauth/UserRefreshTokenList"; | ||||
| import "@goauthentik/app/elements/rbac/ObjectPermissionsPage"; | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { EVENT_REFRESH } from "@goauthentik/common/constants"; | ||||
| @ -31,12 +31,11 @@ import "@goauthentik/elements/Tabs"; | ||||
| import "@goauthentik/elements/buttons/ActionButton"; | ||||
| import "@goauthentik/elements/buttons/SpinnerButton"; | ||||
| import "@goauthentik/elements/forms/ModalForm"; | ||||
| import "@goauthentik/elements/oauth/UserRefreshList"; | ||||
| import "@goauthentik/elements/user/SessionList"; | ||||
| import "@goauthentik/elements/user/UserConsentList"; | ||||
|  | ||||
| import { msg, str } from "@lit/localize"; | ||||
| import { css, html, nothing } from "lit"; | ||||
| import { TemplateResult, css, html, nothing } from "lit"; | ||||
| import { customElement, property, state } from "lit/decorators.js"; | ||||
|  | ||||
| import PFBanner from "@patternfly/patternfly/components/Banner/banner.css"; | ||||
| @ -230,18 +229,9 @@ export class UserViewPage extends WithCapabilitiesConfig(AKElement) { | ||||
|             <ak-forms-modal size=${PFSize.Medium} id="update-password-request"> | ||||
|                 <span slot="submit">${msg("Update password")}</span> | ||||
|                 <span slot="header">${msg("Update password")}</span> | ||||
|                                     <ak-user-password-form | ||||
|                                         slot="form" | ||||
|                                         .instancePk=${user.pk} | ||||
|                                     ></ak-user-password-form> | ||||
|                                     <button | ||||
|                                         slot="trigger" | ||||
|                                         class="pf-c-button pf-m-secondary pf-m-block" | ||||
|                                     > | ||||
|                                         <pf-tooltip | ||||
|                                             position="top" | ||||
|                                             content=${msg("Enter a new password for this user")} | ||||
|                                         > | ||||
|                 <ak-user-password-form slot="form" .instancePk=${user.pk}></ak-user-password-form> | ||||
|                 <button slot="trigger" class="pf-c-button pf-m-secondary pf-m-block"> | ||||
|                     <pf-tooltip position="top" content=${msg("Enter a new password for this user")}> | ||||
|                         ${msg("Set password")} | ||||
|                     </pf-tooltip> | ||||
|                 </button> | ||||
| @ -253,19 +243,77 @@ export class UserViewPage extends WithCapabilitiesConfig(AKElement) { | ||||
|             > | ||||
|                 <pf-tooltip | ||||
|                     position="top" | ||||
|                                         content=${msg( | ||||
|                                             "Create a link for this user to reset their password", | ||||
|                                         )} | ||||
|                     content=${msg("Create a link for this user to reset their password")} | ||||
|                 > | ||||
|                     ${msg("Create Recovery Link")} | ||||
|                 </pf-tooltip> | ||||
|             </ak-action-button> | ||||
|             ${user.email ? renderRecoveryEmailRequest(user) : nothing} | ||||
|         </div> `; | ||||
|     } | ||||
|  | ||||
|     renderTabCredentialsToken(user: User): TemplateResult { | ||||
|         return html` | ||||
|             <ak-tabs pageIdentifier="userCredentialsTokens" ?vertical=${true}> | ||||
|                 <section | ||||
|                     slot="page-sessions" | ||||
|                     data-tab-title="${msg("Sessions")}" | ||||
|                     class="pf-c-page__main-section pf-m-no-padding-mobile" | ||||
|                 > | ||||
|                     <div class="pf-c-card"> | ||||
|                         <div class="pf-c-card__body"> | ||||
|                             <ak-user-session-list targetUser=${user.username}> | ||||
|                             </ak-user-session-list> | ||||
|                         </div> | ||||
|                         </dd> | ||||
|                     </div> | ||||
|                 </dl> | ||||
|                 </section> | ||||
|                 <section | ||||
|                     slot="page-consent" | ||||
|                     data-tab-title="${msg("Explicit Consent")}" | ||||
|                     class="pf-c-page__main-section pf-m-no-padding-mobile" | ||||
|                 > | ||||
|                     <div class="pf-c-card"> | ||||
|                         <div class="pf-c-card__body"> | ||||
|                             <ak-user-consent-list userId=${user.pk}> </ak-user-consent-list> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </section> | ||||
|                 <section | ||||
|                     slot="page-oauth-access" | ||||
|                     data-tab-title="${msg("OAuth Access Tokens")}" | ||||
|                     class="pf-c-page__main-section pf-m-no-padding-mobile" | ||||
|                 > | ||||
|                     <div class="pf-c-card"> | ||||
|                         <div class="pf-c-card__body"> | ||||
|                             <ak-user-oauth-access-token-list userId=${user.pk}> | ||||
|                             </ak-user-oauth-access-token-list> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </section> | ||||
|                 <section | ||||
|                     slot="page-oauth-refresh" | ||||
|                     data-tab-title="${msg("OAuth Refresh Tokens")}" | ||||
|                     class="pf-c-page__main-section pf-m-no-padding-mobile" | ||||
|                 > | ||||
|                     <div class="pf-c-card"> | ||||
|                         <div class="pf-c-card__body"> | ||||
|                             <ak-user-oauth-refresh-token-list userId=${user.pk}> | ||||
|                             </ak-user-oauth-refresh-token-list> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </section> | ||||
|                 <section | ||||
|                     slot="page-mfa-authenticators" | ||||
|                     data-tab-title="${msg("MFA Authenticators")}" | ||||
|                     class="pf-c-page__main-section pf-m-no-padding-mobile" | ||||
|                 > | ||||
|                     <div class="pf-c-card"> | ||||
|                         <div class="pf-c-card__body"> | ||||
|                             <ak-user-device-table userId=${user.pk}> </ak-user-device-table> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </section> | ||||
|             </ak-tabs> | ||||
|         `; | ||||
|     } | ||||
|  | ||||
| @ -326,18 +374,6 @@ export class UserViewPage extends WithCapabilitiesConfig(AKElement) { | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </section> | ||||
|             <section | ||||
|                 slot="page-sessions" | ||||
|                 data-tab-title="${msg("Sessions")}" | ||||
|                 class="pf-c-page__main-section pf-m-no-padding-mobile" | ||||
|             > | ||||
|                 <div class="pf-c-card"> | ||||
|                     <div class="pf-c-card__body"> | ||||
|                         <ak-user-session-list targetUser=${this.user.username}> | ||||
|                         </ak-user-session-list> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </section> | ||||
|             <section | ||||
|                 slot="page-groups" | ||||
|                 data-tab-title="${msg("Groups")}" | ||||
| @ -360,78 +396,16 @@ export class UserViewPage extends WithCapabilitiesConfig(AKElement) { | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </section> | ||||
|             <section | ||||
|                 slot="page-consent" | ||||
|                 data-tab-title="${msg("Explicit Consent")}" | ||||
|                 class="pf-c-page__main-section pf-m-no-padding-mobile" | ||||
|             > | ||||
|                 <div class="pf-c-card"> | ||||
|                     <div class="pf-c-card__body"> | ||||
|                         <ak-user-consent-list userId=${this.user.pk}> </ak-user-consent-list> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </section> | ||||
|             <section | ||||
|                 slot="page-oauth-refresh" | ||||
|                 data-tab-title="${msg("OAuth Refresh Tokens")}" | ||||
|                 class="pf-c-page__main-section pf-m-no-padding-mobile" | ||||
|             > | ||||
|                 <div class="pf-c-card"> | ||||
|                     <div class="pf-c-card__body"> | ||||
|                         <ak-user-oauth-refresh-list userId=${this.user.pk}> | ||||
|                         </ak-user-oauth-refresh-list> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </section> | ||||
|             <section | ||||
|                 slot="page-mfa-authenticators" | ||||
|                 data-tab-title="${msg("MFA Authenticators")}" | ||||
|                 class="pf-c-page__main-section pf-m-no-padding-mobile" | ||||
|             > | ||||
|                 <div class="pf-c-card"> | ||||
|                     <div class="pf-c-card__body"> | ||||
|                         <ak-user-device-table userId=${this.user.pk}> </ak-user-device-table> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             <section slot="page-credentials" data-tab-title="${msg("Credentials / Tokens")}"> | ||||
|                 ${this.renderTabCredentialsToken(this.user)} | ||||
|             </section> | ||||
|             <ak-rbac-object-permission-page | ||||
|                 slot="page-permissions" | ||||
|                 data-tab-title="${msg("Permissions")}" | ||||
|                 model=${RbacPermissionsAssignedByUsersListModelEnum.CoreUser} | ||||
|                 objectPk=${this.user.pk} | ||||
|             ></ak-rbac-object-permission-page> | ||||
|             <div | ||||
|                 slot="page-mfa-assigned-permissions" | ||||
|                 data-tab-title="${msg("Assigned permissions")}" | ||||
|                 class="" | ||||
|             > | ||||
|                 <div class="pf-c-banner pf-m-info"> | ||||
|                     ${msg("RBAC is in preview.")} | ||||
|                     <a href="mailto:hello@goauthentik.io">${msg("Send us feedback!")}</a> | ||||
|                 </div> | ||||
|                 <section class="pf-c-page__main-section pf-m-no-padding-mobile"> | ||||
|                     <div class="pf-l-grid pf-m-gutter"> | ||||
|                         <div class="pf-c-card pf-l-grid__item pf-m-12-col"> | ||||
|                             <div class="pf-c-card__title"> | ||||
|                                 ${msg("Assigned global permissions")} | ||||
|                             </div> | ||||
|                             <div class="pf-c-card__body"> | ||||
|                                 <ak-user-assigned-global-permissions-table userId=${this.user.pk}> | ||||
|                                 </ak-user-assigned-global-permissions-table> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                         <div class="pf-c-card pf-l-grid__item pf-m-12-col"> | ||||
|                             <div class="pf-c-card__title"> | ||||
|                                 ${msg("Assigned object permissions")} | ||||
|                             </div> | ||||
|                             <div class="pf-c-card__body"> | ||||
|                                 <ak-user-assigned-object-permissions-table userId=${this.user.pk}> | ||||
|                                 </ak-user-assigned-object-permissions-table> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </section> | ||||
|             </div> | ||||
|             </ak-rbac-object-permission-page> | ||||
|         </ak-tabs>`; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -149,3 +149,25 @@ export function adaptCSS(sheet: AdaptableStylesheet[]): CSSStyleSheet[]; | ||||
| export function adaptCSS(sheet: AdaptableStylesheet | AdaptableStylesheet[]): AdaptedStylesheets { | ||||
|     return Array.isArray(sheet) ? sheet.map(_adaptCSS) : _adaptCSS(sheet); | ||||
| } | ||||
|  | ||||
| const _timeUnits = new Map<Intl.RelativeTimeFormatUnit, number>([ | ||||
|     ["year", 24 * 60 * 60 * 1000 * 365], | ||||
|     ["month", (24 * 60 * 60 * 1000 * 365) / 12], | ||||
|     ["day", 24 * 60 * 60 * 1000], | ||||
|     ["hour", 60 * 60 * 1000], | ||||
|     ["minute", 60 * 1000], | ||||
|     ["second", 1000], | ||||
| ]); | ||||
|  | ||||
| export function getRelativeTime(d1: Date, d2: Date = new Date()): string { | ||||
|     const rtf = new Intl.RelativeTimeFormat("default", { numeric: "auto" }); | ||||
|     const elapsed = d1.getTime() - d2.getTime(); | ||||
|  | ||||
|     // "Math.abs" accounts for both "past" & "future" scenarios | ||||
|     for (const [key, value] of _timeUnits) { | ||||
|         if (Math.abs(elapsed) > value || key == "second") { | ||||
|             return rtf.format(Math.round(elapsed / value), key); | ||||
|         } | ||||
|     } | ||||
|     return rtf.format(Math.round(elapsed / 1000), "second"); | ||||
| } | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| import { EventGeo, EventUser } from "@goauthentik/app/admin/events/utils"; | ||||
| import { actionToLabel } from "@goauthentik/app/common/labels"; | ||||
| import { getRelativeTime } from "@goauthentik/app/common/utils"; | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { EventWithContext } from "@goauthentik/common/events"; | ||||
| import { uiConfig } from "@goauthentik/common/ui/config"; | ||||
| @ -46,7 +47,7 @@ export class ObjectChangelog extends Table<Event> { | ||||
|         let modelName = this._targetModelName; | ||||
|         let appName = this.targetModelApp; | ||||
|         if (this._targetModelName.indexOf(".") !== -1) { | ||||
|             const parts = this._targetModelName.split("."); | ||||
|             const parts = this._targetModelName.split(".", 1); | ||||
|             appName = parts[0]; | ||||
|             modelName = parts[1]; | ||||
|         } | ||||
| @ -77,7 +78,8 @@ export class ObjectChangelog extends Table<Event> { | ||||
|         return [ | ||||
|             html`${actionToLabel(item.action)}`, | ||||
|             EventUser(item), | ||||
|             html`<span>${item.created?.toLocaleString()}</span>`, | ||||
|             html`<div>${getRelativeTime(item.created)}</div> | ||||
|                 <small>${item.created.toLocaleString()}</small>`, | ||||
|             html`<div>${item.clientIp || msg("-")}</div> | ||||
|  | ||||
|                 <small>${EventGeo(item)}</small>`, | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| import { EventUser } from "@goauthentik/app/admin/events/utils"; | ||||
| import { getRelativeTime } from "@goauthentik/app/common/utils"; | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { EventWithContext } from "@goauthentik/common/events"; | ||||
| import { actionToLabel } from "@goauthentik/common/labels"; | ||||
| @ -48,7 +49,8 @@ export class UserEvents extends Table<Event> { | ||||
|         return [ | ||||
|             html`${actionToLabel(item.action)}`, | ||||
|             EventUser(item), | ||||
|             html`<span>${item.created?.toLocaleString()}</span>`, | ||||
|             html`<div>${getRelativeTime(item.created)}</div> | ||||
|                 <small>${item.created.toLocaleString()}</small>`, | ||||
|             html`<span>${item.clientIp || msg("-")}</span>`, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
| @ -84,6 +84,7 @@ export class AggregateCard extends AKElement { | ||||
|                 ${this.renderInner()} | ||||
|                 ${this.subtext ? html`<p class="subtext">${this.subtext}</p>` : html``} | ||||
|             </div> | ||||
|             <div class="pf-c-card__footer"> </div> | ||||
|         </div>`; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| import { getRelativeTime } from "@goauthentik/app/common/utils"; | ||||
| import { EVENT_REFRESH, EVENT_THEME_CHANGE } from "@goauthentik/common/constants"; | ||||
| import { AKElement } from "@goauthentik/elements/Base"; | ||||
| import "@goauthentik/elements/EmptyState"; | ||||
| @ -18,7 +19,7 @@ import { ArcElement, BarElement } from "chart.js"; | ||||
| import { LinearScale, TimeScale } from "chart.js"; | ||||
| import "chartjs-adapter-moment"; | ||||
|  | ||||
| import { msg, str } from "@lit/localize"; | ||||
| import { msg } from "@lit/localize"; | ||||
| import { CSSResult, TemplateResult, css, html } from "lit"; | ||||
| import { property, state } from "lit/decorators.js"; | ||||
|  | ||||
| @ -161,9 +162,7 @@ export abstract class AKChart<T> extends AKElement { | ||||
|  | ||||
|     timeTickCallback(tickValue: string | number, index: number, ticks: Tick[]): string { | ||||
|         const valueStamp = ticks[index]; | ||||
|         const delta = Date.now() - valueStamp.value; | ||||
|         const ago = Math.round(delta / 1000 / 3600); | ||||
|         return msg(str`${ago} hour(s) ago`); | ||||
|         return getRelativeTime(new Date(valueStamp.value)); | ||||
|     } | ||||
|  | ||||
|     getOptions(): ChartOptions { | ||||
|  | ||||
| @ -25,8 +25,11 @@ export class APIDrawer extends AKElement { | ||||
|             PFContent, | ||||
|             PFDropdown, | ||||
|             css` | ||||
|                 :host { | ||||
|                     --header-height: 114px; | ||||
|                 } | ||||
|                 .pf-c-notification-drawer__header { | ||||
|                     height: 114px; | ||||
|                     height: var(--header-height); | ||||
|                     align-items: center; | ||||
|                 } | ||||
|                 .pf-c-notification-drawer__header-action, | ||||
| @ -41,6 +44,9 @@ export class APIDrawer extends AKElement { | ||||
|                 .pf-c-notification-drawer__body { | ||||
|                     overflow-x: hidden; | ||||
|                 } | ||||
|                 .pf-c-notification-drawer__list { | ||||
|                     max-height: calc(100vh - var(--header-height)); | ||||
|                 } | ||||
|             `, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
							
								
								
									
										93
									
								
								web/src/elements/oauth/UserAccessTokenList.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								web/src/elements/oauth/UserAccessTokenList.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,93 @@ | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { uiConfig } from "@goauthentik/common/ui/config"; | ||||
| import "@goauthentik/components/ak-status-label"; | ||||
| import "@goauthentik/elements/forms/DeleteBulkForm"; | ||||
| import { PaginatedResponse } from "@goauthentik/elements/table/Table"; | ||||
| import { Table, TableColumn } from "@goauthentik/elements/table/Table"; | ||||
|  | ||||
| import { msg } from "@lit/localize"; | ||||
| import { CSSResult, TemplateResult, html } from "lit"; | ||||
| import { customElement, property } from "lit/decorators.js"; | ||||
|  | ||||
| import PFFlex from "@patternfly/patternfly/layouts/Flex/flex.css"; | ||||
|  | ||||
| import { ExpiringBaseGrantModel, Oauth2Api, TokenModel } from "@goauthentik/api"; | ||||
|  | ||||
| @customElement("ak-user-oauth-access-token-list") | ||||
| export class UserOAuthAccessTokenList extends Table<TokenModel> { | ||||
|     expandable = true; | ||||
|  | ||||
|     @property({ type: Number }) | ||||
|     userId?: number; | ||||
|  | ||||
|     static get styles(): CSSResult[] { | ||||
|         return super.styles.concat(PFFlex); | ||||
|     } | ||||
|  | ||||
|     async apiEndpoint(page: number): Promise<PaginatedResponse<TokenModel>> { | ||||
|         return new Oauth2Api(DEFAULT_CONFIG).oauth2AccessTokensList({ | ||||
|             user: this.userId, | ||||
|             ordering: "expires", | ||||
|             page: page, | ||||
|             pageSize: (await uiConfig()).pagination.perPage, | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     checkbox = true; | ||||
|     order = "-expires"; | ||||
|  | ||||
|     columns(): TableColumn[] { | ||||
|         return [ | ||||
|             new TableColumn(msg("Provider"), "provider"), | ||||
|             new TableColumn(msg("Revoked?"), "revoked"), | ||||
|             new TableColumn(msg("Expires"), "expires"), | ||||
|             new TableColumn(msg("Scopes"), "scope"), | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     renderExpanded(item: TokenModel): TemplateResult { | ||||
|         return html` <td role="cell" colspan="4"> | ||||
|                 <div class="pf-c-table__expandable-row-content"> | ||||
|                     <div class="pf-l-flex"> | ||||
|                         <div class="pf-l-flex__item"> | ||||
|                             <h3>${msg("ID Token")}</h3> | ||||
|                             <pre>${item.idToken}</pre> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </td> | ||||
|             <td></td> | ||||
|             <td></td>`; | ||||
|     } | ||||
|  | ||||
|     renderToolbarSelected(): TemplateResult { | ||||
|         const disabled = this.selectedElements.length < 1; | ||||
|         return html`<ak-forms-delete-bulk | ||||
|             objectLabel=${msg("Refresh Tokens(s)")} | ||||
|             .objects=${this.selectedElements} | ||||
|             .usedBy=${(item: ExpiringBaseGrantModel) => { | ||||
|                 return new Oauth2Api(DEFAULT_CONFIG).oauth2RefreshTokensUsedByList({ | ||||
|                     id: item.pk, | ||||
|                 }); | ||||
|             }} | ||||
|             .delete=${(item: ExpiringBaseGrantModel) => { | ||||
|                 return new Oauth2Api(DEFAULT_CONFIG).oauth2RefreshTokensDestroy({ | ||||
|                     id: item.pk, | ||||
|                 }); | ||||
|             }} | ||||
|         > | ||||
|             <button ?disabled=${disabled} slot="trigger" class="pf-c-button pf-m-danger"> | ||||
|                 ${msg("Delete")} | ||||
|             </button> | ||||
|         </ak-forms-delete-bulk>`; | ||||
|     } | ||||
|  | ||||
|     row(item: TokenModel): TemplateResult[] { | ||||
|         return [ | ||||
|             html`<a href="#/core/providers/${item.provider?.pk}"> ${item.provider?.name} </a>`, | ||||
|             html`<ak-status-label type="warning" ?good=${item.revoked}></ak-status-label>`, | ||||
|             html`${item.expires?.toLocaleString()}`, | ||||
|             html`${item.scope.join(", ")}`, | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
| @ -13,8 +13,8 @@ import PFFlex from "@patternfly/patternfly/layouts/Flex/flex.css"; | ||||
| 
 | ||||
| import { ExpiringBaseGrantModel, Oauth2Api, TokenModel } from "@goauthentik/api"; | ||||
| 
 | ||||
| @customElement("ak-user-oauth-refresh-list") | ||||
| export class UserOAuthRefreshList extends Table<TokenModel> { | ||||
| @customElement("ak-user-oauth-refresh-token-list") | ||||
| export class UserOAuthRefreshTokenList extends Table<TokenModel> { | ||||
|     expandable = true; | ||||
| 
 | ||||
|     @property({ type: Number }) | ||||
| @ -38,6 +38,7 @@ export class ObjectPermissionsPageForm extends ModelForm<unknown, string> { | ||||
|             .model=${this.model} | ||||
|             .objectPk=${this.objectPk} | ||||
|             slot="form" | ||||
|             .embedded=${true} | ||||
|         > | ||||
|         </ak-rbac-object-permission-page>`; | ||||
|     } | ||||
|  | ||||
| @ -1,10 +1,14 @@ | ||||
| import "@goauthentik/app/admin/roles/RoleAssignedGlobalPermissionsTable"; | ||||
| import "@goauthentik/app/admin/roles/RoleAssignedObjectPermissionTable"; | ||||
| import "@goauthentik/app/admin/users/UserAssignedGlobalPermissionsTable"; | ||||
| import "@goauthentik/app/admin/users/UserAssignedObjectPermissionsTable"; | ||||
| import { AKElement } from "@goauthentik/app/elements/Base"; | ||||
| import "@goauthentik/app/elements/rbac/RoleObjectPermissionTable"; | ||||
| import "@goauthentik/app/elements/rbac/UserObjectPermissionTable"; | ||||
| import "@goauthentik/elements/Tabs"; | ||||
|  | ||||
| import { msg } from "@lit/localize"; | ||||
| import { CSSResult, TemplateResult, html } from "lit"; | ||||
| import { html, nothing } from "lit"; | ||||
| import { customElement, property } from "lit/decorators.js"; | ||||
|  | ||||
| import PFBanner from "@patternfly/patternfly/components/Banner/banner.css"; | ||||
| @ -24,20 +28,26 @@ export class ObjectPermissionPage extends AKElement { | ||||
|     objectPk?: string | number; | ||||
|  | ||||
|     @property({ type: Boolean }) | ||||
|     showBanner = true; | ||||
|     embedded = false; | ||||
|  | ||||
|     static get styles(): CSSResult[] { | ||||
|     static get styles() { | ||||
|         return [PFBase, PFGrid, PFPage, PFCard, PFBanner]; | ||||
|     } | ||||
|  | ||||
|     render(): TemplateResult { | ||||
|         return html`${this.showBanner | ||||
|     render() { | ||||
|         return html`${!this.embedded | ||||
|                 ? html`<div class="pf-c-banner pf-m-info"> | ||||
|                       ${msg("RBAC is in preview.")} | ||||
|                       <a href="mailto:hello@goauthentik.io">${msg("Send us feedback!")}</a> | ||||
|                   </div>` | ||||
|                 : html``} | ||||
|             <ak-tabs pageIdentifier="permissionPage"> | ||||
|                 : nothing} | ||||
|             <ak-tabs pageIdentifier="permissionPage" ?vertical=${!this.embedded}> | ||||
|                 ${this.model === RbacPermissionsAssignedByUsersListModelEnum.CoreUser | ||||
|                     ? this.renderCoreUser() | ||||
|                     : nothing} | ||||
|                 ${this.model === RbacPermissionsAssignedByUsersListModelEnum.RbacRole | ||||
|                     ? this.renderRbacRole() | ||||
|                     : nothing} | ||||
|                 <section | ||||
|                     slot="page-object-user" | ||||
|                     data-tab-title="${msg("User Object Permissions")}" | ||||
| @ -45,7 +55,10 @@ export class ObjectPermissionPage extends AKElement { | ||||
|                 > | ||||
|                     <div class="pf-l-grid pf-m-gutter"> | ||||
|                         <div class="pf-c-card pf-l-grid__item pf-m-12-col"> | ||||
|                             <div class="pf-c-card__title">User Object Permissions</div> | ||||
|                             <div class="pf-c-card__title">${msg("User Object Permissions")}</div> | ||||
|                             <div class="pf-c-card__body"> | ||||
|                                 ${msg("Permissions set on users which affect this object.")} | ||||
|                             </div> | ||||
|                             <div class="pf-c-card__body"> | ||||
|                                 <ak-rbac-user-object-permission-table | ||||
|                                     .model=${this.model} | ||||
| @ -63,7 +76,10 @@ export class ObjectPermissionPage extends AKElement { | ||||
|                 > | ||||
|                     <div class="pf-l-grid pf-m-gutter"> | ||||
|                         <div class="pf-c-card pf-l-grid__item pf-m-12-col"> | ||||
|                             <div class="pf-c-card__title">Role Object Permissions</div> | ||||
|                             <div class="pf-c-card__title">${msg("Role Object Permissions")}</div> | ||||
|                             <div class="pf-c-card__body"> | ||||
|                                 ${msg("Permissions set on roles which affect this object.")} | ||||
|                             </div> | ||||
|                             <div class="pf-c-card__body"> | ||||
|                                 <ak-rbac-role-object-permission-table | ||||
|                                     .model=${this.model} | ||||
| @ -76,4 +92,98 @@ export class ObjectPermissionPage extends AKElement { | ||||
|                 </section> | ||||
|             </ak-tabs>`; | ||||
|     } | ||||
|  | ||||
|     renderCoreUser() { | ||||
|         return html` | ||||
|             <div | ||||
|                 slot="page-assigned-global-permissions" | ||||
|                 data-tab-title="${msg("Assigned global permissions")}" | ||||
|             > | ||||
|                 <section class="pf-c-page__main-section pf-m-no-padding-mobile"> | ||||
|                     <div class="pf-c-card"> | ||||
|                         <div class="pf-c-card__title">${msg("Assigned global permissions")}</div> | ||||
|                         <div class="pf-c-card__body"> | ||||
|                             ${msg( | ||||
|                                 "Permissions assigned to this user which affect all object instances of a given type.", | ||||
|                             )} | ||||
|                         </div> | ||||
|                         <div class="pf-c-card__body"> | ||||
|                             <ak-user-assigned-global-permissions-table | ||||
|                                 userId=${this.objectPk as number} | ||||
|                             > | ||||
|                             </ak-user-assigned-global-permissions-table> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </section> | ||||
|             </div> | ||||
|             <div | ||||
|                 slot="page-assigned-object-permissions" | ||||
|                 data-tab-title="${msg("Assigned object permissions")}" | ||||
|             > | ||||
|                 <section class="pf-c-page__main-section pf-m-no-padding-mobile"> | ||||
|                     <div class="pf-c-card"> | ||||
|                         <div class="pf-c-card__title">${msg("Assigned object permissions")}</div> | ||||
|                         <div class="pf-c-card__body"> | ||||
|                             ${msg( | ||||
|                                 "Permissions assigned to this user affecting specific object instances.", | ||||
|                             )} | ||||
|                         </div> | ||||
|                         <div class="pf-c-card__body"> | ||||
|                             <ak-user-assigned-object-permissions-table | ||||
|                                 userId=${this.objectPk as number} | ||||
|                             > | ||||
|                             </ak-user-assigned-object-permissions-table> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </section> | ||||
|             </div> | ||||
|         `; | ||||
|     } | ||||
|  | ||||
|     renderRbacRole() { | ||||
|         return html` | ||||
|             <div | ||||
|                 slot="page-assigned-global-permissions" | ||||
|                 data-tab-title="${msg("Assigned global permissions")}" | ||||
|             > | ||||
|                 <section class="pf-c-page__main-section pf-m-no-padding-mobile"> | ||||
|                     <div class="pf-c-card"> | ||||
|                         <div class="pf-c-card__title">${msg("Assigned global permissions")}</div> | ||||
|                         <div class="pf-c-card__body"> | ||||
|                             ${msg( | ||||
|                                 "Permissions assigned to this role which affect all object instances of a given type.", | ||||
|                             )} | ||||
|                         </div> | ||||
|                         <div class="pf-c-card__body"> | ||||
|                             <ak-role-assigned-global-permissions-table | ||||
|                                 roleUuid=${this.objectPk as string} | ||||
|                             > | ||||
|                             </ak-role-assigned-global-permissions-table> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </section> | ||||
|             </div> | ||||
|             <div | ||||
|                 slot="page-assigned-object-permissions" | ||||
|                 data-tab-title="${msg("Assigned object permissions")}" | ||||
|             > | ||||
|                 <section class="pf-c-page__main-section pf-m-no-padding-mobile"> | ||||
|                     <div class="pf-c-card"> | ||||
|                         <div class="pf-c-card__title">${msg("Assigned object permissions")}</div> | ||||
|                         <div class="pf-c-card__body"> | ||||
|                             ${msg( | ||||
|                                 "Permissions assigned to this user affecting specific object instances.", | ||||
|                             )} | ||||
|                         </div> | ||||
|                         <div class="pf-c-card__body"> | ||||
|                             <ak-role-assigned-object-permissions-table | ||||
|                                 roleUuid=${this.objectPk as string} | ||||
|                             > | ||||
|                             </ak-role-assigned-object-permissions-table> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </section> | ||||
|             </div> | ||||
|         `; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -180,6 +180,12 @@ export abstract class Table<T> extends AKElement implements TableLike { | ||||
|                 .pf-c-table tbody .pf-c-table__check input { | ||||
|                     margin-top: calc(var(--pf-c-table__check--input--MarginTop) + 1px); | ||||
|                 } | ||||
|                 .pf-c-toolbar__content { | ||||
|                     row-gap: var(--pf-global--spacer--sm); | ||||
|                 } | ||||
|                 .pf-c-toolbar__item .pf-c-input-group { | ||||
|                     padding: 0 var(--pf-global--spacer--sm); | ||||
|                 } | ||||
|             `, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
| @ -1,8 +1,10 @@ | ||||
| import { getRelativeTime } from "@goauthentik/app/common/utils"; | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { uiConfig } from "@goauthentik/common/ui/config"; | ||||
| import "@goauthentik/elements/forms/DeleteBulkForm"; | ||||
| import { PaginatedResponse } from "@goauthentik/elements/table/Table"; | ||||
| import { Table, TableColumn } from "@goauthentik/elements/table/Table"; | ||||
| import getUnicodeFlagIcon from "country-flag-icons/unicode"; | ||||
|  | ||||
| import { msg } from "@lit/localize"; | ||||
| import { TemplateResult, html } from "lit"; | ||||
| @ -31,6 +33,7 @@ export class AuthenticatedSessionList extends Table<AuthenticatedSession> { | ||||
|     columns(): TableColumn[] { | ||||
|         return [ | ||||
|             new TableColumn(msg("Last IP"), "last_ip"), | ||||
|             new TableColumn(msg("Last used"), "last_used"), | ||||
|             new TableColumn(msg("Expires"), "expires"), | ||||
|         ]; | ||||
|     } | ||||
| @ -66,10 +69,17 @@ export class AuthenticatedSessionList extends Table<AuthenticatedSession> { | ||||
|     row(item: AuthenticatedSession): TemplateResult[] { | ||||
|         return [ | ||||
|             html`<div> | ||||
|                     ${item.current ? html`${msg("(Current session)")} ` : html``}${item.lastIp} | ||||
|                     ${item.current ? html`${msg("(Current session)")} ` : html``} | ||||
|                     ${item.lastIp} | ||||
|                     ${item.geoIp?.country | ||||
|                         ? html` ${getUnicodeFlagIcon(item.geoIp.country)} ` | ||||
|                         : html``} | ||||
|                 </div> | ||||
|                 <small>${item.userAgent.userAgent?.family}, ${item.userAgent.os?.family}</small>`, | ||||
|             html`${item.expires?.toLocaleString()}`, | ||||
|             html`<div>${getRelativeTime(item.lastUsed)}</div> | ||||
|                 <small>${item.lastUsed?.toLocaleString()}</small>`, | ||||
|             html`<div>${getRelativeTime(item.expires || new Date())}</div> | ||||
|                 <small>${item.expires?.toLocaleString()}</small>`, | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -10,6 +10,7 @@ import { TemplateResult, html } from "lit"; | ||||
| import { customElement, state } from "lit/decorators.js"; | ||||
|  | ||||
| import PFButton from "@patternfly/patternfly/components/Button/button.css"; | ||||
| import PFDivider from "@patternfly/patternfly/components/Divider/divider.css"; | ||||
| import PFForm from "@patternfly/patternfly/components/Form/form.css"; | ||||
| import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; | ||||
| import PFLogin from "@patternfly/patternfly/components/Login/login.css"; | ||||
| @ -32,7 +33,7 @@ export class PlexLoginInit extends BaseStage< | ||||
|     authUrl?: string; | ||||
|  | ||||
|     static get styles(): CSSResult[] { | ||||
|         return [PFBase, PFLogin, PFForm, PFFormControl, PFButton, PFTitle]; | ||||
|         return [PFBase, PFLogin, PFForm, PFFormControl, PFButton, PFTitle, PFDivider]; | ||||
|     } | ||||
|  | ||||
|     async firstUpdated(): Promise<void> { | ||||
| @ -76,7 +77,7 @@ export class PlexLoginInit extends BaseStage< | ||||
|                         header=${msg("Waiting for authentication...")} | ||||
|                     > | ||||
|                     </ak-empty-state> | ||||
|                     <hr /> | ||||
|                     <hr class="pf-c-divider" /> | ||||
|                     <p>${msg("If no Plex popup opens, click the button below.")}</p> | ||||
|                     <button | ||||
|                         class="pf-c-button pf-m-block pf-m-primary" | ||||
|  | ||||
| @ -8,6 +8,7 @@ import { CSSResult, TemplateResult, css, html } from "lit"; | ||||
| import { customElement, property } from "lit/decorators.js"; | ||||
| import { ifDefined } from "lit/directives/if-defined.js"; | ||||
|  | ||||
| import PFDivider from "@patternfly/patternfly/components/Divider/divider.css"; | ||||
| import PFForm from "@patternfly/patternfly/components/Form/form.css"; | ||||
| import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; | ||||
| import PFList from "@patternfly/patternfly/components/List/list.css"; | ||||
| @ -26,6 +27,7 @@ export class AccessDeniedIcon extends AKElement { | ||||
|         return [ | ||||
|             PFBase, | ||||
|             PFTitle, | ||||
|             PFDivider, | ||||
|             css` | ||||
|                 .big-icon { | ||||
|                     display: flex; | ||||
| @ -51,7 +53,7 @@ export class AccessDeniedIcon extends AKElement { | ||||
|             </p> | ||||
|             <h3 class="pf-c-title pf-m-3xl reason">${msg("Request has been denied.")}</h3> | ||||
|             ${this.errorMessage | ||||
|                 ? html`<hr /> | ||||
|                 ? html` <hr class="pf-c-divider" /> | ||||
|                       <p>${this.errorMessage}</p>` | ||||
|                 : html``} | ||||
|         </div>`; | ||||
|  | ||||
| @ -121,6 +121,9 @@ export class UserInterface extends Interface { | ||||
|                     display: flex; | ||||
|                     flex-direction: column; | ||||
|                 } | ||||
|                 .pf-c-drawer__main { | ||||
|                     max-height: calc(100vh - 76px); | ||||
|                 } | ||||
|             `, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
| @ -427,12 +427,6 @@ | ||||
|         <source>No workers connected. Background tasks will not run.</source> | ||||
|         <target>Keine Worker verbunden. Hintergrundaufgaben werden nicht ausgeführt.</target> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s2ed8eb02525a920a"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> hour(s) ago</source> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s1f1c857c0c4250e4"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> day(s) ago</source> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s11bc220e8fa9d797"> | ||||
|         <source>Authorizations</source> | ||||
|         <target>Berechtigungen</target> | ||||
| @ -5834,9 +5828,6 @@ Bindings to groups/users are checked against the user of the event.</source> | ||||
| <trans-unit id="s1455753daa00f1bc"> | ||||
|   <source>User doesn't have view permission so description cannot be retrieved.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sa3a3e09b88ed9791"> | ||||
|   <source>Assigned permissions</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s9cc631505c17b028"> | ||||
|   <source>Assigned global permissions</source> | ||||
| </trans-unit> | ||||
| @ -6372,6 +6363,30 @@ Bindings to groups/users are checked against the user of the event.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sb2275335377069aa"> | ||||
|   <source>This feature requires an enterprise license.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s6d3f81dc4bcacbda"> | ||||
|   <source>Last used</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s96b2703420bfbd0c"> | ||||
|   <source>OAuth Access Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sd99e668c54f78f6e"> | ||||
|   <source>Credentials / Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="saada50e84c7c646d"> | ||||
|   <source>Permissions set on users which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s37d1b74df205b528"> | ||||
|   <source>Permissions set on roles which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sc443bfff8a5dd106"> | ||||
|   <source>Permissions assigned to this user which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s3eba09a350b7d6c9"> | ||||
|   <source>Permissions assigned to this user affecting specific object instances.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s17032e57ba222d2f"> | ||||
|   <source>Permissions assigned to this role which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
|     </body> | ||||
|   </file> | ||||
|  | ||||
| @ -433,16 +433,6 @@ | ||||
|         <source>No workers connected. Background tasks will not run.</source> | ||||
|         <target>No workers connected. Background tasks will not run.</target> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s2ed8eb02525a920a"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> hour(s) ago</source> | ||||
|         <target> | ||||
|         <x id="0" equiv-text="${ago}"/>hour(s) ago</target> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s1f1c857c0c4250e4"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> day(s) ago</source> | ||||
|         <target> | ||||
|         <x id="0" equiv-text="${ago}"/>day(s) ago</target> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s11bc220e8fa9d797"> | ||||
|         <source>Authorizations</source> | ||||
|         <target>Authorizations</target> | ||||
| @ -6109,9 +6099,6 @@ Bindings to groups/users are checked against the user of the event.</source> | ||||
| <trans-unit id="s1455753daa00f1bc"> | ||||
|   <source>User doesn't have view permission so description cannot be retrieved.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sa3a3e09b88ed9791"> | ||||
|   <source>Assigned permissions</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s9cc631505c17b028"> | ||||
|   <source>Assigned global permissions</source> | ||||
| </trans-unit> | ||||
| @ -6647,6 +6634,30 @@ Bindings to groups/users are checked against the user of the event.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sb2275335377069aa"> | ||||
|   <source>This feature requires an enterprise license.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s6d3f81dc4bcacbda"> | ||||
|   <source>Last used</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s96b2703420bfbd0c"> | ||||
|   <source>OAuth Access Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sd99e668c54f78f6e"> | ||||
|   <source>Credentials / Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="saada50e84c7c646d"> | ||||
|   <source>Permissions set on users which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s37d1b74df205b528"> | ||||
|   <source>Permissions set on roles which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sc443bfff8a5dd106"> | ||||
|   <source>Permissions assigned to this user which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s3eba09a350b7d6c9"> | ||||
|   <source>Permissions assigned to this user affecting specific object instances.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s17032e57ba222d2f"> | ||||
|   <source>Permissions assigned to this role which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
|     </body> | ||||
|   </file> | ||||
|  | ||||
| @ -420,12 +420,6 @@ | ||||
|         <source>No workers connected. Background tasks will not run.</source> | ||||
|         <target>No hay trabajadores conectados. No se ejecutarán tareas en segundo plano.</target> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s2ed8eb02525a920a"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> hour(s) ago</source> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s1f1c857c0c4250e4"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> day(s) ago</source> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s11bc220e8fa9d797"> | ||||
|         <source>Authorizations</source> | ||||
|         <target>Autorizaciones</target> | ||||
| @ -5750,9 +5744,6 @@ Bindings to groups/users are checked against the user of the event.</source> | ||||
| <trans-unit id="s1455753daa00f1bc"> | ||||
|   <source>User doesn't have view permission so description cannot be retrieved.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sa3a3e09b88ed9791"> | ||||
|   <source>Assigned permissions</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s9cc631505c17b028"> | ||||
|   <source>Assigned global permissions</source> | ||||
| </trans-unit> | ||||
| @ -6288,6 +6279,30 @@ Bindings to groups/users are checked against the user of the event.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sb2275335377069aa"> | ||||
|   <source>This feature requires an enterprise license.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s6d3f81dc4bcacbda"> | ||||
|   <source>Last used</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s96b2703420bfbd0c"> | ||||
|   <source>OAuth Access Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sd99e668c54f78f6e"> | ||||
|   <source>Credentials / Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="saada50e84c7c646d"> | ||||
|   <source>Permissions set on users which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s37d1b74df205b528"> | ||||
|   <source>Permissions set on roles which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sc443bfff8a5dd106"> | ||||
|   <source>Permissions assigned to this user which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s3eba09a350b7d6c9"> | ||||
|   <source>Permissions assigned to this user affecting specific object instances.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s17032e57ba222d2f"> | ||||
|   <source>Permissions assigned to this role which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
|     </body> | ||||
|   </file> | ||||
|  | ||||
| @ -537,18 +537,6 @@ | ||||
|         <source>No workers connected. Background tasks will not run.</source> | ||||
|         <target>Aucun worker connecté. Les tâches de fond ne tourneront pas.</target> | ||||
|          | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s2ed8eb02525a920a"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> hour(s) ago</source> | ||||
|         <target> | ||||
| Il y a <x id="0" equiv-text="${ago}"/> heure(s)</target> | ||||
|          | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s1f1c857c0c4250e4"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> day(s) ago</source> | ||||
|         <target> | ||||
| Il y a <x id="0" equiv-text="${ago}"/> jour(s)</target> | ||||
|          | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s11bc220e8fa9d797"> | ||||
|         <source>Authorizations</source> | ||||
| @ -7666,10 +7654,6 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti | ||||
|   <source>User doesn't have view permission so description cannot be retrieved.</source> | ||||
|   <target>L'utilisateur n'a pas les permissions de lecture, la description ne peut donc pas être récupérée.</target> | ||||
| </trans-unit> | ||||
| <trans-unit id="sa3a3e09b88ed9791"> | ||||
|   <source>Assigned permissions</source> | ||||
|   <target>Permissions assignées</target> | ||||
| </trans-unit> | ||||
| <trans-unit id="s9cc631505c17b028"> | ||||
|   <source>Assigned global permissions</source> | ||||
|   <target>Permissions globales assignées</target> | ||||
| @ -8375,6 +8359,30 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti | ||||
| </trans-unit> | ||||
| <trans-unit id="sb2275335377069aa"> | ||||
|   <source>This feature requires an enterprise license.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s6d3f81dc4bcacbda"> | ||||
|   <source>Last used</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s96b2703420bfbd0c"> | ||||
|   <source>OAuth Access Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sd99e668c54f78f6e"> | ||||
|   <source>Credentials / Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="saada50e84c7c646d"> | ||||
|   <source>Permissions set on users which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s37d1b74df205b528"> | ||||
|   <source>Permissions set on roles which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sc443bfff8a5dd106"> | ||||
|   <source>Permissions assigned to this user which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s3eba09a350b7d6c9"> | ||||
|   <source>Permissions assigned to this user affecting specific object instances.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s17032e57ba222d2f"> | ||||
|   <source>Permissions assigned to this role which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
|     </body> | ||||
|   </file> | ||||
|  | ||||
| @ -536,18 +536,6 @@ | ||||
|         <source>No workers connected. Background tasks will not run.</source> | ||||
|         <target>연결된 워커가 없습니다. 백그라운드 작업이 실행되지 않습니다.</target> | ||||
|  | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s2ed8eb02525a920a"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> hour(s) ago</source> | ||||
|         <target> | ||||
|         <x id="0" equiv-text="${ago}"/>시간 전</target> | ||||
|  | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s1f1c857c0c4250e4"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> day(s) ago</source> | ||||
|         <target> | ||||
|         <x id="0" equiv-text="${ago}"/> 일 전</target> | ||||
|  | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s11bc220e8fa9d797"> | ||||
|         <source>Authorizations</source> | ||||
| @ -7629,10 +7617,6 @@ Bindings to groups/users are checked against the user of the event.</source> | ||||
|   <source>User doesn't have view permission so description cannot be retrieved.</source> | ||||
|   <target>사용자에게 보기 권한이 없으므로 설명을 검색할 수 없습니다.</target> | ||||
| </trans-unit> | ||||
| <trans-unit id="sa3a3e09b88ed9791"> | ||||
|   <source>Assigned permissions</source> | ||||
|   <target>할당된 권한</target> | ||||
| </trans-unit> | ||||
| <trans-unit id="s9cc631505c17b028"> | ||||
|   <source>Assigned global permissions</source> | ||||
|   <target>전역 권한 할당</target> | ||||
| @ -8245,6 +8229,30 @@ Bindings to groups/users are checked against the user of the event.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sb2275335377069aa"> | ||||
|   <source>This feature requires an enterprise license.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s6d3f81dc4bcacbda"> | ||||
|   <source>Last used</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s96b2703420bfbd0c"> | ||||
|   <source>OAuth Access Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sd99e668c54f78f6e"> | ||||
|   <source>Credentials / Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="saada50e84c7c646d"> | ||||
|   <source>Permissions set on users which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s37d1b74df205b528"> | ||||
|   <source>Permissions set on roles which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sc443bfff8a5dd106"> | ||||
|   <source>Permissions assigned to this user which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s3eba09a350b7d6c9"> | ||||
|   <source>Permissions assigned to this user affecting specific object instances.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s17032e57ba222d2f"> | ||||
|   <source>Permissions assigned to this role which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
|     </body> | ||||
|   </file> | ||||
|  | ||||
| @ -530,16 +530,6 @@ | ||||
|         <source>No workers connected. Background tasks will not run.</source> | ||||
|         <target>Geen medewerkers verbonden. Achtergrondtaken worden niet uitgevoerd.</target> | ||||
|  | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s2ed8eb02525a920a"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> hour(s) ago</source> | ||||
|         <target><x id="0" equiv-text="${ago}"/> uur geleden</target> | ||||
|  | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s1f1c857c0c4250e4"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> day(s) ago</source> | ||||
|         <target><x id="0" equiv-text="${ago}"/> dag(en) geleden</target> | ||||
|  | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s11bc220e8fa9d797"> | ||||
|         <source>Authorizations</source> | ||||
| @ -7769,9 +7759,6 @@ Bindingen naar groepen/gebruikers worden gecontroleerd tegen de gebruiker van de | ||||
| <trans-unit id="se5c795faf2c07514"> | ||||
|   <source>Create Recovery Link</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sa3a3e09b88ed9791"> | ||||
|   <source>Assigned permissions</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s9cc631505c17b028"> | ||||
|   <source>Assigned global permissions</source> | ||||
| </trans-unit> | ||||
| @ -8085,6 +8072,30 @@ Bindingen naar groepen/gebruikers worden gecontroleerd tegen de gebruiker van de | ||||
| </trans-unit> | ||||
| <trans-unit id="sb2275335377069aa"> | ||||
|   <source>This feature requires an enterprise license.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s6d3f81dc4bcacbda"> | ||||
|   <source>Last used</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s96b2703420bfbd0c"> | ||||
|   <source>OAuth Access Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sd99e668c54f78f6e"> | ||||
|   <source>Credentials / Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="saada50e84c7c646d"> | ||||
|   <source>Permissions set on users which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s37d1b74df205b528"> | ||||
|   <source>Permissions set on roles which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sc443bfff8a5dd106"> | ||||
|   <source>Permissions assigned to this user which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s3eba09a350b7d6c9"> | ||||
|   <source>Permissions assigned to this user affecting specific object instances.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s17032e57ba222d2f"> | ||||
|   <source>Permissions assigned to this role which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
|     </body> | ||||
|   </file> | ||||
|  | ||||
| @ -429,12 +429,6 @@ | ||||
|         <source>No workers connected. Background tasks will not run.</source> | ||||
|         <target>Brak połączonych workerów. Zadania w tle nie będą działać.</target> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s2ed8eb02525a920a"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> hour(s) ago</source> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s1f1c857c0c4250e4"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> day(s) ago</source> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s11bc220e8fa9d797"> | ||||
|         <source>Authorizations</source> | ||||
|         <target>Autoryzacje</target> | ||||
| @ -5957,9 +5951,6 @@ Bindings to groups/users are checked against the user of the event.</source> | ||||
| <trans-unit id="s1455753daa00f1bc"> | ||||
|   <source>User doesn't have view permission so description cannot be retrieved.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sa3a3e09b88ed9791"> | ||||
|   <source>Assigned permissions</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s9cc631505c17b028"> | ||||
|   <source>Assigned global permissions</source> | ||||
| </trans-unit> | ||||
| @ -6495,6 +6486,30 @@ Bindings to groups/users are checked against the user of the event.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sb2275335377069aa"> | ||||
|   <source>This feature requires an enterprise license.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s6d3f81dc4bcacbda"> | ||||
|   <source>Last used</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s96b2703420bfbd0c"> | ||||
|   <source>OAuth Access Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sd99e668c54f78f6e"> | ||||
|   <source>Credentials / Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="saada50e84c7c646d"> | ||||
|   <source>Permissions set on users which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s37d1b74df205b528"> | ||||
|   <source>Permissions set on roles which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sc443bfff8a5dd106"> | ||||
|   <source>Permissions assigned to this user which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s3eba09a350b7d6c9"> | ||||
|   <source>Permissions assigned to this user affecting specific object instances.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s17032e57ba222d2f"> | ||||
|   <source>Permissions assigned to this role which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
|     </body> | ||||
|   </file> | ||||
|  | ||||
| @ -531,16 +531,6 @@ | ||||
|         <source>No workers connected. Background tasks will not run.</source> | ||||
|   <target>Ńō ŵōŕķēŕś ćōńńēćţēď. ßàćķĝŕōũńď ţàśķś ŵĩĺĺ ńōţ ŕũń.</target> | ||||
|  | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s2ed8eb02525a920a"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> hour(s) ago</source> | ||||
|   <target><x id="0" equiv-text="${ago}"/> ĥōũŕ(ś) àĝō</target> | ||||
|  | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s1f1c857c0c4250e4"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> day(s) ago</source> | ||||
|   <target><x id="0" equiv-text="${ago}"/> ďàŷ(ś) àĝō</target> | ||||
|  | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s11bc220e8fa9d797"> | ||||
|         <source>Authorizations</source> | ||||
| @ -7609,10 +7599,6 @@ Bindings to groups/users are checked against the user of the event.</source> | ||||
|   <source>User doesn't have view permission so description cannot be retrieved.</source> | ||||
|   <target>Ũśēŕ ďōēśń'ţ ĥàvē vĩēŵ ƥēŕmĩśśĩōń śō ďēśćŕĩƥţĩōń ćàńńōţ ƀē ŕēţŕĩēvēď.</target> | ||||
| </trans-unit> | ||||
| <trans-unit id="sa3a3e09b88ed9791"> | ||||
|   <source>Assigned permissions</source> | ||||
|   <target>Àśśĩĝńēď ƥēŕmĩśśĩōńś</target> | ||||
| </trans-unit> | ||||
| <trans-unit id="s9cc631505c17b028"> | ||||
|   <source>Assigned global permissions</source> | ||||
|   <target>Àśśĩĝńēď ĝĺōƀàĺ ƥēŕmĩśśĩōńś</target> | ||||
| @ -8220,4 +8206,28 @@ Bindings to groups/users are checked against the user of the event.</source> | ||||
| <trans-unit id="sb2275335377069aa"> | ||||
|   <source>This feature requires an enterprise license.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s6d3f81dc4bcacbda"> | ||||
|   <source>Last used</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s96b2703420bfbd0c"> | ||||
|   <source>OAuth Access Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sd99e668c54f78f6e"> | ||||
|   <source>Credentials / Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="saada50e84c7c646d"> | ||||
|   <source>Permissions set on users which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s37d1b74df205b528"> | ||||
|   <source>Permissions set on roles which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sc443bfff8a5dd106"> | ||||
|   <source>Permissions assigned to this user which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s3eba09a350b7d6c9"> | ||||
|   <source>Permissions assigned to this user affecting specific object instances.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s17032e57ba222d2f"> | ||||
|   <source>Permissions assigned to this role which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
| </body></file></xliff> | ||||
|  | ||||
| @ -420,12 +420,6 @@ | ||||
|         <source>No workers connected. Background tasks will not run.</source> | ||||
|         <target>İşçi bağlantısı yok. Arka plan görevleri çalışmaz.</target> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s2ed8eb02525a920a"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> hour(s) ago</source> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s1f1c857c0c4250e4"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> day(s) ago</source> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s11bc220e8fa9d797"> | ||||
|         <source>Authorizations</source> | ||||
|         <target>Yetkilendirmeler</target> | ||||
| @ -5743,9 +5737,6 @@ Bindings to groups/users are checked against the user of the event.</source> | ||||
| <trans-unit id="s1455753daa00f1bc"> | ||||
|   <source>User doesn't have view permission so description cannot be retrieved.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sa3a3e09b88ed9791"> | ||||
|   <source>Assigned permissions</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s9cc631505c17b028"> | ||||
|   <source>Assigned global permissions</source> | ||||
| </trans-unit> | ||||
| @ -6281,6 +6272,30 @@ Bindings to groups/users are checked against the user of the event.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sb2275335377069aa"> | ||||
|   <source>This feature requires an enterprise license.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s6d3f81dc4bcacbda"> | ||||
|   <source>Last used</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s96b2703420bfbd0c"> | ||||
|   <source>OAuth Access Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sd99e668c54f78f6e"> | ||||
|   <source>Credentials / Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="saada50e84c7c646d"> | ||||
|   <source>Permissions set on users which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s37d1b74df205b528"> | ||||
|   <source>Permissions set on roles which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sc443bfff8a5dd106"> | ||||
|   <source>Permissions assigned to this user which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s3eba09a350b7d6c9"> | ||||
|   <source>Permissions assigned to this user affecting specific object instances.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s17032e57ba222d2f"> | ||||
|   <source>Permissions assigned to this role which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
|     </body> | ||||
|   </file> | ||||
|  | ||||
| @ -344,15 +344,9 @@ | ||||
| <trans-unit id="s341ab68d4130de20"> | ||||
|   <source>No workers connected. Background tasks will not run.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s2ed8eb02525a920a"> | ||||
|   <source><x id="0" equiv-text="${ago}"/> hour(s) ago</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s98327528f00365a7"> | ||||
|   <source>Failed to fetch data.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s1f1c857c0c4250e4"> | ||||
|   <source><x id="0" equiv-text="${ago}"/> day(s) ago</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s11bc220e8fa9d797"> | ||||
|   <source>Authorizations</source> | ||||
| </trans-unit> | ||||
| @ -3169,9 +3163,6 @@ doesn't pass when either or both of the selected options are equal or above the | ||||
| <trans-unit id="s28b3de1561da72b3"> | ||||
|   <source>MFA Authenticators</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sa3a3e09b88ed9791"> | ||||
|   <source>Assigned permissions</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s9cc631505c17b028"> | ||||
|   <source>Assigned global permissions</source> | ||||
| </trans-unit> | ||||
| @ -5191,6 +5182,30 @@ Bindings to groups/users are checked against the user of the event.</source> | ||||
| <trans-unit id="sb2275335377069aa"> | ||||
|   <source>This feature requires an enterprise license.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s6d3f81dc4bcacbda"> | ||||
|   <source>Last used</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s96b2703420bfbd0c"> | ||||
|   <source>OAuth Access Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sd99e668c54f78f6e"> | ||||
|   <source>Credentials / Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="saada50e84c7c646d"> | ||||
|   <source>Permissions set on users which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s37d1b74df205b528"> | ||||
|   <source>Permissions set on roles which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sc443bfff8a5dd106"> | ||||
|   <source>Permissions assigned to this user which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s3eba09a350b7d6c9"> | ||||
|   <source>Permissions assigned to this user affecting specific object instances.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s17032e57ba222d2f"> | ||||
|   <source>Permissions assigned to this role which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
| </body> | ||||
| </file> | ||||
| </xliff> | ||||
|  | ||||
| @ -537,18 +537,6 @@ | ||||
|         <source>No workers connected. Background tasks will not run.</source> | ||||
|         <target>没有 Workers 连接,后台任务将无法运行。</target> | ||||
|  | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s2ed8eb02525a920a"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> hour(s) ago</source> | ||||
|         <target> | ||||
|         <x id="0" equiv-text="${ago}"/>小时前</target> | ||||
|  | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s1f1c857c0c4250e4"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> day(s) ago</source> | ||||
|         <target> | ||||
|         <x id="0" equiv-text="${ago}"/>天前</target> | ||||
|  | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s11bc220e8fa9d797"> | ||||
|         <source>Authorizations</source> | ||||
| @ -7668,10 +7656,6 @@ Bindings to groups/users are checked against the user of the event.</source> | ||||
|   <source>User doesn't have view permission so description cannot be retrieved.</source> | ||||
|   <target>用户不具有查看权限,所以无法获取描述。</target> | ||||
| </trans-unit> | ||||
| <trans-unit id="sa3a3e09b88ed9791"> | ||||
|   <source>Assigned permissions</source> | ||||
|   <target>分配的权限</target> | ||||
| </trans-unit> | ||||
| <trans-unit id="s9cc631505c17b028"> | ||||
|   <source>Assigned global permissions</source> | ||||
|   <target>分配的全局权限</target> | ||||
| @ -8388,6 +8372,42 @@ Bindings to groups/users are checked against the user of the event.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sb2275335377069aa"> | ||||
|   <source>This feature requires an enterprise license.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s6d3f81dc4bcacbda"> | ||||
|   <source>Last used</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s96b2703420bfbd0c"> | ||||
|   <source>OAuth Access Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sd99e668c54f78f6e"> | ||||
|   <source>Credentials / Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sb2275335377069aa"> | ||||
|   <source>This feature requires an enterprise license.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s6d3f81dc4bcacbda"> | ||||
|   <source>Last used</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s96b2703420bfbd0c"> | ||||
|   <source>OAuth Access Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sd99e668c54f78f6e"> | ||||
|   <source>Credentials / Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="saada50e84c7c646d"> | ||||
|   <source>Permissions set on users which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s37d1b74df205b528"> | ||||
|   <source>Permissions set on roles which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sc443bfff8a5dd106"> | ||||
|   <source>Permissions assigned to this user which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s3eba09a350b7d6c9"> | ||||
|   <source>Permissions assigned to this user affecting specific object instances.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s17032e57ba222d2f"> | ||||
|   <source>Permissions assigned to this role which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
|     </body> | ||||
|   </file> | ||||
|  | ||||
| @ -427,12 +427,6 @@ | ||||
|         <source>No workers connected. Background tasks will not run.</source> | ||||
|         <target>没有 workers 连接。后台任务将无法运行。</target> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s2ed8eb02525a920a"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> hour(s) ago</source> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s1f1c857c0c4250e4"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> day(s) ago</source> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s11bc220e8fa9d797"> | ||||
|         <source>Authorizations</source> | ||||
|         <target>授权</target> | ||||
| @ -5791,9 +5785,6 @@ Bindings to groups/users are checked against the user of the event.</source> | ||||
| <trans-unit id="s1455753daa00f1bc"> | ||||
|   <source>User doesn't have view permission so description cannot be retrieved.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sa3a3e09b88ed9791"> | ||||
|   <source>Assigned permissions</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s9cc631505c17b028"> | ||||
|   <source>Assigned global permissions</source> | ||||
| </trans-unit> | ||||
| @ -6329,6 +6320,30 @@ Bindings to groups/users are checked against the user of the event.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sb2275335377069aa"> | ||||
|   <source>This feature requires an enterprise license.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s6d3f81dc4bcacbda"> | ||||
|   <source>Last used</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s96b2703420bfbd0c"> | ||||
|   <source>OAuth Access Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sd99e668c54f78f6e"> | ||||
|   <source>Credentials / Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="saada50e84c7c646d"> | ||||
|   <source>Permissions set on users which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s37d1b74df205b528"> | ||||
|   <source>Permissions set on roles which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sc443bfff8a5dd106"> | ||||
|   <source>Permissions assigned to this user which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s3eba09a350b7d6c9"> | ||||
|   <source>Permissions assigned to this user affecting specific object instances.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s17032e57ba222d2f"> | ||||
|   <source>Permissions assigned to this role which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
|     </body> | ||||
|   </file> | ||||
|  | ||||
| @ -530,16 +530,6 @@ | ||||
|         <source>No workers connected. Background tasks will not run.</source> | ||||
|         <target>沒有已連線的 workers,無法執行背景工作。</target> | ||||
|  | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s2ed8eb02525a920a"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> hour(s) ago</source> | ||||
|         <target><x id="0" equiv-text="${ago}"/> 小時以前</target> | ||||
|  | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s1f1c857c0c4250e4"> | ||||
|         <source><x id="0" equiv-text="${ago}"/> day(s) ago</source> | ||||
|         <target><x id="0" equiv-text="${ago}"/> 天以前</target> | ||||
|  | ||||
|       </trans-unit> | ||||
|       <trans-unit id="s11bc220e8fa9d797"> | ||||
|         <source>Authorizations</source> | ||||
| @ -7602,10 +7592,6 @@ Bindings to groups/users are checked against the user of the event.</source> | ||||
|   <source>User doesn't have view permission so description cannot be retrieved.</source> | ||||
|   <target>使用者沒有讀取權限,所以無法取得描述。</target> | ||||
| </trans-unit> | ||||
| <trans-unit id="sa3a3e09b88ed9791"> | ||||
|   <source>Assigned permissions</source> | ||||
|   <target>已分配的權限</target> | ||||
| </trans-unit> | ||||
| <trans-unit id="s9cc631505c17b028"> | ||||
|   <source>Assigned global permissions</source> | ||||
|   <target>已分配的全域權限</target> | ||||
| @ -8204,6 +8190,30 @@ Bindings to groups/users are checked against the user of the event.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sb2275335377069aa"> | ||||
|   <source>This feature requires an enterprise license.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s6d3f81dc4bcacbda"> | ||||
|   <source>Last used</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s96b2703420bfbd0c"> | ||||
|   <source>OAuth Access Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sd99e668c54f78f6e"> | ||||
|   <source>Credentials / Tokens</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="saada50e84c7c646d"> | ||||
|   <source>Permissions set on users which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s37d1b74df205b528"> | ||||
|   <source>Permissions set on roles which affect this object.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="sc443bfff8a5dd106"> | ||||
|   <source>Permissions assigned to this user which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s3eba09a350b7d6c9"> | ||||
|   <source>Permissions assigned to this user affecting specific object instances.</source> | ||||
| </trans-unit> | ||||
| <trans-unit id="s17032e57ba222d2f"> | ||||
|   <source>Permissions assigned to this role which affect all object instances of a given type.</source> | ||||
| </trans-unit> | ||||
|     </body> | ||||
|   </file> | ||||
|  | ||||
| @ -9,22 +9,20 @@ Refer to the following topics for instructions to view and manage permissions. | ||||
|  | ||||
| You can view all permissions that are assigned to a user, group, role, flow, or stage. | ||||
|  | ||||
| ### View user, group, and role permissions | ||||
| ### View user and role permissions | ||||
|  | ||||
| To view _object_ permissions for a specific user, role, or group: | ||||
| To view _object_ permissions for a specific user or role: | ||||
|  | ||||
| 1. Go to the Admin interface and navigate to **Directory**. | ||||
| 2. Select either **Users**, **Groups**, or **Roles** | ||||
| 3. Select a specific user/group/role by clicking on the name (this opens the details page). | ||||
| 4. Click the **Assigned Permissions** tab at the top of the page (to the right of the **Permissions** tab). | ||||
| 5. Scroll down to see both the global and object-level permissions. | ||||
|  | ||||
| :::info | ||||
| Note that groups do not have global permissions. | ||||
| ::: | ||||
| 2. Select either **Users** or **Roles** | ||||
| 3. Select a specific user/role by clicking on the name (this opens the details page). | ||||
| 4. Click the **Permissions** tab at the top of the page | ||||
| 5. Select the **Assigned global permissions** sub-tab to see global permissions and the **Assigned object permissions** sub-tab to see the object-level permissions. | ||||
|  | ||||
| ### View flow permissions | ||||
|  | ||||
| \_These instructions apply to all objects that have a detail page, which can be accessed by clicking on the name in the list page.\_\_ | ||||
|  | ||||
| 1. Go to the Admin interface and navigate to **Flows and Stages -> Flows**. | ||||
| 2. Click the name of the flow (this opens the details page). | ||||
| 3. Click the **Permissions** tab at the top of the page. | ||||
| @ -32,6 +30,8 @@ Note that groups do not have global permissions. | ||||
|  | ||||
| ### View stage permissions | ||||
|  | ||||
| \_These instructions apply to all objects that **do not** have a detail page.\_\_ | ||||
|  | ||||
| 1. Go to the Admin interface and navigate to **Flows and Stages -> Stagess**. | ||||
| 2. On the row for the specific stage whose permissions you want to view, click the lock icon. | ||||
| 3. On the **Update Permissions** tab, you can view the assigned permissions using the **User Object Permissions** and the **Role Object Permissions** tabs. | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Jens L
					Jens L