Compare commits

...

17 Commits

Author SHA1 Message Date
Teffen Ellis
65f279827a Update about modal. 2025-11-19 16:22:15 +01:00
Teffen Ellis
b782770199 Update sidebar items. 2025-11-19 16:21:58 +01:00
Teffen Ellis
14eacd459d Fix plural. 2025-11-19 16:01:53 +01:00
Teffen Ellis
7a744d2530 Update column labels. 2025-11-19 16:01:53 +01:00
Teffen Ellis
e32baca745 Update name labels. 2025-11-19 16:01:52 +01:00
Teffen Ellis
2216463391 Update labels. 2025-11-19 16:01:52 +01:00
Teffen Ellis
3efecd276e Clean up code mirror helper. 2025-11-19 16:01:51 +01:00
Teffen Ellis
7d8be1e68d Fix placeholders, bad labels. 2025-11-19 16:01:51 +01:00
Teffen Ellis
520466e37d Better warnings. 2025-11-19 16:01:51 +01:00
Teffen Ellis
4e9fbdf5c2 Add IDs. 2025-11-19 16:01:51 +01:00
Teffen Ellis
1a43829eed Use message IDs. 2025-11-19 16:01:50 +01:00
Teffen Ellis
0fb6d1ee9f Fix grouping. 2025-11-19 16:01:50 +01:00
Teffen Ellis
c1aca5920a Fix runtime translations. 2025-11-19 16:01:49 +01:00
Teffen Ellis
d86d180ed2 web: Clean up stale labels. 2025-11-19 16:01:49 +01:00
Teffen Ellis
449a7193fd web: Use entity action labels. 2025-11-19 16:01:48 +01:00
Teffen Ellis
b33f9517a0 web: Use entity label as search placeholder. 2025-11-19 16:01:48 +01:00
Teffen Ellis
ac9b1aa5f5 web: Prepare label helpers. 2025-11-19 16:01:46 +01:00
211 changed files with 2812 additions and 958 deletions

View File

@@ -28,7 +28,8 @@ import { RuntimeLitLocalizer } from "@lit/localize-tools/lib/modes/runtime.js";
//#region Setup
const missingMessagePattern = /([\w_-]+)\smessage\s(?:[\w_-]+)\sis\smissing/;
const missingMessagePattern = /([\w_-]+)\smessage\s(?:[\w_.-]+)\sis\smissing/;
const outdatedMessagePattern = /([\w_-]+)\smessage\s(?:[\w_.-]+)\sdoes\snot\sexist/;
const logger = ConsoleLogger.child({ name: "Locales" });
const localizeRules = readConfigFileAndWriteSchema(path.join(PackageRoot, "lit-localize.json"));
@@ -153,7 +154,12 @@ export async function generateLocaleModules() {
/**
* @type {Map<string, number>}
*/
const localeWarnings = new Map();
const missingTranslationWarnings = new Map();
/**
* @type {Map<string, number>}
*/
const outdatedTranslationWarnings = new Map();
const initialConsoleWarn = console.warn;
@@ -163,12 +169,26 @@ export async function generateLocaleModules() {
return;
}
const [, matchedLocale] = arg0.match(missingMessagePattern) || [];
const [, matchedMissingTranslation] = arg0.match(missingMessagePattern) || [];
if (matchedLocale) {
const count = localeWarnings.get(matchedLocale) || 0;
if (matchedMissingTranslation) {
const count = missingTranslationWarnings.get(matchedMissingTranslation) || 0;
localeWarnings.set(matchedLocale, count + 1);
missingTranslationWarnings.set(matchedMissingTranslation, count + 1);
logger.debug(arg0);
return;
}
const [, matchedOutdatedTranslation] = arg0.match(outdatedMessagePattern) || [];
if (matchedOutdatedTranslation) {
const count = outdatedTranslationWarnings.get(matchedOutdatedTranslation) || 0;
outdatedTranslationWarnings.set(matchedOutdatedTranslation, count + 1);
logger.debug(arg0);
return;
}
@@ -181,7 +201,7 @@ export async function generateLocaleModules() {
await localizer.build();
const report = Array.from(localeWarnings)
const missingTranslationsReport = Array.from(missingTranslationWarnings)
.filter(([, count]) => count)
.sort(([, totalsA], [, totalsB]) => {
return totalsB - totalsA;
@@ -189,7 +209,17 @@ export async function generateLocaleModules() {
.map(([locale, count]) => `${locale}: ${count.toLocaleString()}`)
.join("\n");
logger.info(`Missing translations:\n${report}`);
logger.info(`Missing translations:\n${missingTranslationsReport}`);
const outdatedTranslationsReport = Array.from(outdatedTranslationWarnings)
.filter(([, count]) => count)
.sort(([, totalsA], [, totalsB]) => {
return totalsB - totalsA;
})
.map(([locale, count]) => `${locale}: ${count.toLocaleString()}`)
.join("\n");
logger.info(`Outdated translations:\n${outdatedTranslationsReport}`);
localizer.assertTranslationsAreValid();

View File

@@ -48,12 +48,12 @@ export class AboutModal extends WithLicenseSummary(WithBrandConfig(ModalButton))
>`;
}
return [
[msg("Version"), version.versionCurrent],
[msg("UI Version"), import.meta.env.AK_VERSION],
[msg("Build"), build],
[msg("Python version"), status.runtime.pythonVersion],
[msg("Platform"), status.runtime.platform],
[msg("Kernel"), status.runtime.uname],
[msg("Version", { id: "label.version" }), version.versionCurrent],
[msg("UI Version", { id: "label.ui-version" }), import.meta.env.AK_VERSION],
[msg("Build", { id: "label.build" }), build],
[msg("Python version", { id: "label.python-version" }), status.runtime.pythonVersion],
[msg("Platform", { id: "label.platform" }), status.runtime.platform],
[msg("Kernel", { id: "label.kernel" }), status.runtime.uname],
[
msg("OpenSSL"),
`${status.runtime.opensslVersion} ${status.runtime.opensslFipsEnabled ? "FIPS" : ""}`,

View File

@@ -51,54 +51,149 @@ export function renderSidebarItems(entries: readonly SidebarEntry[]) {
return repeat(entries, ([path, label]) => path || label, renderSidebarItem);
}
// prettier-ignore
export const createAdminSidebarEntries = (): readonly SidebarEntry[] => [
[null, msg("Dashboards"), { "?expanded": true }, [
["/administration/overview", msg("Overview")],
["/administration/dashboard/users", msg("User Statistics")],
["/administration/system-tasks", msg("System Tasks")]]
[
null,
msg("Dashboards", { id: "sidebar.category.dashboards" }),
{ "?expanded": true },
[
["/administration/overview", msg("Overview", { id: "sidebar.item.overview" })],
[
"/administration/dashboard/users",
msg("User Statistics", { id: "sidebar.item.user-statistics" }),
],
[
"/administration/system-tasks",
msg("System Tasks", { id: "sidebar.item.system-tasks" }),
],
],
],
[null, msg("Applications"), null, [
["/core/applications", msg("Applications"), [`^/core/applications/(?<slug>${SLUG_REGEX})$`]],
["/core/providers", msg("Providers"), [`^/core/providers/(?<id>${ID_REGEX})$`]],
["/outpost/outposts", msg("Outposts")]]
[
null,
msg("Applications", { id: "sidebar.category.applications" }),
null,
[
[
"/core/applications",
msg("Applications", { id: "sidebar.item.applications" }),
[`^/core/applications/(?<slug>${SLUG_REGEX})$`],
],
[
"/core/providers",
msg("Providers", { id: "sidebar.item.providers" }),
[`^/core/providers/(?<id>${ID_REGEX})$`],
],
["/outpost/outposts", msg("Outposts", { id: "sidebar.item.outposts" })],
],
],
[null, msg("Events"), null, [
["/events/log", msg("Logs"), [`^/events/log/(?<id>${UUID_REGEX})$`]],
["/events/rules", msg("Notification Rules")],
["/events/transports", msg("Notification Transports")]]
[
null,
msg("Events", { id: "sidebar.category.events" }),
null,
[
["/events/log", msg("Logs"), [`^/events/log/(?<id>${UUID_REGEX})$`]],
["/events/rules", msg("Notification Rules", { id: "sidebar.item.system-tasks" })],
[
"/events/transports",
msg("Notification Transports", { id: "sidebar.item.notification-transports" }),
],
],
],
[null, msg("Customization"), null, [
["/policy/policies", msg("Policies")],
["/core/property-mappings", msg("Property Mappings")],
["/blueprints/instances", msg("Blueprints")],
["/policy/reputation", msg("Reputation scores")]]
[
null,
msg("Customization", { id: "sidebar.category.customization" }),
null,
[
["/policy/policies", msg("Policies", { id: "sidebar.item.policies" })],
[
"/core/property-mappings",
msg("Property Mappings", { id: "sidebar.item.property-mappings" }),
],
["/blueprints/instances", msg("Blueprints", { id: "sidebar.item.blueprints" })],
[
"/policy/reputation",
msg("Reputation scores", { id: "sidebar.item.reputation-scores" }),
],
],
],
[null, msg("Flows and Stages"), null, [
["/flow/flows", msg("Flows"), [`^/flow/flows/(?<slug>${SLUG_REGEX})$`]],
["/flow/stages", msg("Stages")],
["/flow/stages/prompts", msg("Prompts")]]
[
null,
msg("Flows and Stages", { id: "sidebar.category.flows-and-stages" }),
null,
[
["/flow/flows", msg("Flows"), [`^/flow/flows/(?<slug>${SLUG_REGEX})$`]],
["/flow/stages", msg("Stages", { id: "sidebar.item.stages" })],
["/flow/stages/prompts", msg("Prompts", { id: "sidebar.item.prompts" })],
],
],
[null, msg("Directory"), null, [
["/identity/users", msg("Users"), [`^/identity/users/(?<id>${ID_REGEX})$`]],
["/identity/groups", msg("Groups"), [`^/identity/groups/(?<id>${UUID_REGEX})$`]],
["/identity/roles", msg("Roles"), [`^/identity/roles/(?<id>${UUID_REGEX})$`]],
["/identity/initial-permissions", msg("Initial Permissions"), [`^/identity/initial-permissions/(?<id>${ID_REGEX})$`]],
["/core/sources", msg("Federation and Social login"), [`^/core/sources/(?<slug>${SLUG_REGEX})$`]],
["/core/tokens", msg("Tokens and App passwords")],
["/flow/stages/invitations", msg("Invitations")]]
[
null,
msg("Directory", { id: "sidebar.category.directory" }),
null,
[
[
"/identity/users",
msg("Users", { id: "sidebar.item.users" }),
[`^/identity/users/(?<id>${ID_REGEX})$`],
],
[
"/identity/groups",
msg("Groups", { id: "sidebar.item.groups" }),
[`^/identity/groups/(?<id>${UUID_REGEX})$`],
],
[
"/identity/roles",
msg("Roles", { id: "sidebar.item.roles" }),
[`^/identity/roles/(?<id>${UUID_REGEX})$`],
],
[
"/identity/initial-permissions",
msg("Initial Permissions", { id: "sidebar.item.initial-permissions" }),
[`^/identity/initial-permissions/(?<id>${ID_REGEX})$`],
],
[
"/core/sources",
msg("Federation and Social login", {
id: "sidebar.item.federation-and-social-login",
}),
[`^/core/sources/(?<slug>${SLUG_REGEX})$`],
],
[
"/core/tokens",
msg("Tokens and App passwords", { id: "sidebar.item.tokens-and-app-passwords" }),
],
["/flow/stages/invitations", msg("Invitations", { id: "sidebar.item.invitations" })],
],
],
[null, msg("System"), null, [
["/core/brands", msg("Brands")],
["/crypto/certificates", msg("Certificates")],
["/outpost/integrations", msg("Outpost Integrations")],
["/admin/settings", msg("Settings")]]
[
null,
msg("System", { id: "sidebar.category.system" }),
null,
[
["/core/brands", msg("Brands", { id: "sidebar.item.brands" })],
["/crypto/certificates", msg("Certificates", { id: "sidebar.item.certificates" })],
[
"/outpost/integrations",
msg("Outpost Integrations", { id: "sidebar.item.outpost-integrations" }),
],
["/admin/settings", msg("Settings", { id: "sidebar.item.settings" })],
],
],
];
// prettier-ignore
export const createAdminSidebarEnterpriseEntries = (): readonly SidebarEntry[] => [
[null, msg("Enterprise"), null, [
["/enterprise/licenses", msg("Licenses"), null]
[
null,
msg("Enterprise", { id: "sidebar.category.enterprise" }),
null,
[
[
"/enterprise/licenses",
msg("Licenses", {
id: "sidebar.item.licenses",
}),
null,
],
],
],
]]
];

View File

@@ -7,6 +7,7 @@ import "#elements/buttons/SpinnerButton/index";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EventWithContext } from "#common/events";
import { EntityLabel } from "#common/i18n/nouns";
import { actionToLabel } from "#common/labels";
import { PaginatedResponse, Table, TableColumn } from "#elements/table/Table";
@@ -17,7 +18,7 @@ import { EventGeo, renderEventUser } from "#admin/events/utils";
import { Event, EventsApi } from "@goauthentik/api";
import { msg } from "@lit/localize";
import { msg, str } from "@lit/localize";
import { CSSResult, html, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators.js";
@@ -26,8 +27,13 @@ import PFCard from "@patternfly/patternfly/components/Card/card.css";
@customElement("ak-recent-events")
export class RecentEventsCard extends Table<Event> {
public override role = "region";
public override ariaLabel = msg("Recent events");
public override label = msg("Events");
public override ariaLabel = msg("Recent events", { id: "aria.label.recent-events" });
public override label = msg("Events", { id: "card.label.recent-events" });
protected override entityLabel: EntityLabel = {
singular: msg("Event", { id: "entity.event.singular" }),
plural: msg("Events", { id: "entity.event.plural" }),
};
@property()
order = "-created";
@@ -54,10 +60,10 @@ export class RecentEventsCard extends Table<Event> {
}
protected columns: TableColumn[] = [
[msg("Action"), "action"],
[msg("User"), "user"],
[msg("Creation Date"), "created"],
[msg("Client IP"), "client_ip"],
[msg("Action", { id: "column.action" }), "action"],
[msg("User", { id: "column.user" }), "user"],
[msg("Creation Date", { id: "column.creation-date" }), "created"],
[msg("Client IP", { id: "column.client-ip" }), "client_ip"],
];
renderToolbar(): TemplateResult {
@@ -83,10 +89,20 @@ export class RecentEventsCard extends Table<Event> {
return super.renderEmpty(inner);
}
const entityLabel = this.entityLabel.plural.toLowerCase();
return super.renderEmpty(
html`<ak-empty-state
><span>${msg("No Events found.")}</span>
<div slot="body">${msg("No matching events could be found.")}</div>
><span
>${msg(str`No ${entityLabel} found.`, {
id: "empty-state.heading",
})}</span
>
<div slot="body">
${msg(str`No matching ${entityLabel} could be found.`, {
id: "empty-state.body",
})}
</div>
</ak-empty-state>`,
);
}

View File

@@ -16,7 +16,9 @@ import { customElement } from "lit/decorators.js";
@customElement("ak-admin-status-chart-outpost")
export class OutpostStatusChart extends AKChart<SummarizedSyncStatus[]> {
public override ariaLabel = msg("Outpost status chart");
public override ariaLabel = msg("Outpost status chart", {
id: "aria.label.outpost-status-chart",
});
getChartType(): string {
return "doughnut";

View File

@@ -29,7 +29,9 @@ export interface SummarizedSyncStatus {
@customElement("ak-admin-status-chart-sync")
export class SyncStatusChart extends AKChart<SummarizedSyncStatus[]> {
public override ariaLabel = msg("Synchronization status chart");
public override ariaLabel = msg("Synchronization status chart", {
id: "aria.label.sync-status-chart",
});
getChartType(): string {
return "doughnut";

View File

@@ -46,9 +46,8 @@ export class AdminSettingsForm extends Form<SettingsRequest> {
@property({ attribute: false })
public settings!: Settings;
getSuccessMessage(): string {
return msg("Successfully updated settings.");
}
protected override readonly actionName = "save";
protected override entityLabel = msg("Settings");
async send(settingsRequest: SettingsRequest): Promise<Settings> {
const result = await new AdminApi(DEFAULT_CONFIG).adminSettingsUpdate({

View File

@@ -32,9 +32,9 @@ export class ApplicationCheckAccessForm extends Form<{ forUser: number }> {
@property({ attribute: false })
request?: number;
getSuccessMessage(): string {
return msg("Successfully sent test-request.");
}
protected override readonly actionName = "send";
protected override entityLabel = msg("Test Request");
async send(data: { forUser: number }): Promise<PolicyTestResult> {
this.request = data.forUser;

View File

@@ -57,11 +57,7 @@ export class ApplicationForm extends WithCapabilitiesConfig(ModelForm<Applicatio
@property({ type: Boolean })
public clearIcon = false;
protected override getSuccessMessage(): string {
return this.instance
? msg("Successfully updated application.")
: msg("Successfully created application.");
}
protected override entityLabel = msg("Application");
public override async send(applicationRequest: Application): Promise<Application | void> {
applicationRequest.backchannelProviders = this.backchannelProviders.map((p) => p.pk);
@@ -138,12 +134,18 @@ export class ApplicationForm extends WithCapabilitiesConfig(ModelForm<Applicatio
<ak-text-input
name="name"
autocomplete="off"
placeholder=${msg("Type an application name...")}
placeholder=${msg("Type an application name...", {
id: "application.form.name.placeholder",
})}
value=${ifDefined(this.instance?.name)}
label=${msg("Application Name")}
label=${msg("Application Name", {
id: "application.form.name.label",
})}
spellcheck="false"
required
help=${msg("The name displayed in the application library.")}
help=${msg("The name displayed in the application library.", {
id: "application.form.name.help",
})}
></ak-text-input>
<ak-slug-input
name="slug"
@@ -151,16 +153,26 @@ export class ApplicationForm extends WithCapabilitiesConfig(ModelForm<Applicatio
value=${ifDefined(this.instance?.slug)}
label=${msg("Slug")}
required
help=${msg("Internal application name used in URLs.")}
help=${msg("Internal application name used in URLs.", {
id: "application.form.slug.help",
desc: "Help text for the slug field in the application form",
})}
input-hint="code"
></ak-slug-input>
<ak-text-input
name="group"
value=${ifDefined(this.instance?.group)}
label=${msg("Group")}
placeholder=${msg("e.g. Collaboration, Communication, Internal, etc.")}
placeholder=${msg("e.g. Collaboration, Communication, Internal, etc.", {
id: "application.form.group.placeholder",
desc: "Placeholder text for the group field in the application form",
})}
help=${msg(
"Optionally enter a group name. Applications with identical groups are shown grouped together.",
{
id: "application.form.group.help",
desc: "Help text for the group field in the application form",
},
)}
input-hint="code"
></ak-text-input>
@@ -168,7 +180,10 @@ export class ApplicationForm extends WithCapabilitiesConfig(ModelForm<Applicatio
name="provider"
label=${msg("Provider")}
value=${ifPresent(this.instance?.provider)}
help=${msg("Select a provider that this application should use.")}
help=${msg("Select a provider that this application should use.", {
id: "application.form.provider.help",
desc: "Help text for the provider field in the application form",
})}
blankable
></ak-provider-search-input>
<ak-backchannel-providers-input
@@ -176,18 +191,26 @@ export class ApplicationForm extends WithCapabilitiesConfig(ModelForm<Applicatio
label=${msg("Backchannel Providers")}
help=${msg(
"Select backchannel providers which augment the functionality of the main provider.",
{
id: "application.form.backchannel-providers.help",
desc: "Help text for the backchannel providers field in the application form",
},
)}
.providers=${this.backchannelProviders}
.confirm=${this.#handleConfirmBackchannelProviders}
.remover=${this.#makeRemoveBackchannelProviderHandler}
.tooltip=${html`<pf-tooltip
position="top"
content=${msg("Add provider")}
content=${msg("Add provider", {
id: "application.form.backchannel-providers.add-provider.tooltip",
})}
></pf-tooltip>`}
>
</ak-backchannel-providers-input>
<ak-radio-input
label=${msg("Policy engine mode")}
label=${msg("Policy engine mode", {
id: "application.form.policy-engine-mode.label",
})}
required
name="policyEngineMode"
.options=${policyEngineModes}
@@ -208,9 +231,14 @@ export class ApplicationForm extends WithCapabilitiesConfig(ModelForm<Applicatio
<ak-switch-input
name="openInNewTab"
?checked=${this.instance?.openInNewTab ?? false}
label=${msg("Open in new tab")}
label=${msg("Open in new tab", {
id: "application.form.open-in-new-tab.label",
})}
help=${msg(
"If checked, the launch URL will open in a new browser tab or window from the user's application library.",
{
id: "application.form.open-in-new-tab.help",
},
)}
>
</ak-switch-input>
@@ -219,32 +247,44 @@ export class ApplicationForm extends WithCapabilitiesConfig(ModelForm<Applicatio
label="${msg("Icon")}"
name="metaIcon"
value=${ifPresent(this.instance?.metaIcon)}
current=${msg("Currently set to:")}
current=${msg("Currently set to:", {
id: "application.form.icon.current",
})}
></ak-file-input>
${this.instance?.metaIcon
? html`
<ak-switch-input
name=""
label=${msg("Clear icon")}
help=${msg("Delete currently set icon.")}
label=${msg("Clear icon", {
id: "application.form.clear-icon.label",
})}
help=${msg("Delete currently set icon.", {
id: "application.form.clear-icon.help",
})}
@change=${this.handleClearIcon}
></ak-switch-input>
`
: nothing}`
: html` <ak-text-input
label=${msg("Icon")}
label=${msg("Icon", {
id: "application.form.icon.label",
})}
name="metaIcon"
value=${this.instance?.metaIcon ?? ""}
help=${iconHelperText}
>
</ak-text-input>`}
<ak-text-input
label=${msg("Publisher")}
label=${msg("Publisher", {
id: "application.form.publisher.label",
})}
name="metaPublisher"
value="${ifDefined(this.instance?.metaPublisher)}"
></ak-text-input>
<ak-textarea-input
label=${msg("Description")}
label=${msg("Description", {
id: "application.form.description.label",
})}
name="metaDescription"
value=${ifDefined(this.instance?.metaDescription)}
></ak-textarea-input>

View File

@@ -45,7 +45,17 @@ export const applicationListStyle = css`
@customElement("ak-application-list")
export class ApplicationListPage extends WithBrandConfig(TablePage<Application>) {
protected override searchEnabled = true;
public pageTitle = msg("Applications");
protected override entityLabel = {
singular: msg("Application", { id: "entity.application.singular" }),
plural: msg("Applications", { id: "entity.application.plural" }),
};
protected override get searchPlaceholder() {
return msg("Search for an application by name or group...", {
id: "search.placeholder.application-list",
});
}
public get pageDescription() {
return msg(
str`External applications that use ${this.brandingTitle} as an identity provider via protocols like OAuth2 and SAML. All applications are shown here, even ones you cannot access.`,
@@ -69,12 +79,16 @@ export class ApplicationListPage extends WithBrandConfig(TablePage<Application>)
static styles: CSSResult[] = [...TablePage.styles, PFCard, applicationListStyle];
protected columns: TableColumn[] = [
["", undefined, msg("Application Icon")],
[msg("Name"), "name"],
[msg("Group"), "group"],
[msg("Provider")],
[msg("Provider Type")],
[msg("Actions"), null, msg("Row Actions")],
["", undefined, msg("Application Icon", { id: "column.application-icon" })],
[msg("Name", { id: "column.name" }), "name"],
[msg("Group", { id: "column.group" }), "group"],
[msg("Provider", { id: "column.provider" })],
[msg("Provider Type", { id: "column.provider-type" })],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
protected renderSidebarAfter(): TemplateResult {
@@ -132,7 +146,7 @@ export class ApplicationListPage extends WithBrandConfig(TablePage<Application>)
html`${item.providerObj?.verboseName || msg("-")}`,
html`<div>
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="submit">${this.updateEntityLabel}</span>
<span slot="header">${msg("Update Application")}</span>
<ak-application-form slot="form" .instancePk=${item.slug}>
</ak-application-form>
@@ -173,18 +187,20 @@ export class ApplicationListPage extends WithBrandConfig(TablePage<Application>)
</button>
</ak-application-wizard>
<ak-forms-modal .open=${getURLParam("createForm", false)}>
<span slot="submit">${msg("Create")}</span>
<span slot="header">${msg("Create Application")}</span>
<span slot="submit">${this.createEntityLabel}</span>
<span slot="header">${this.newEntityActionLabel}</span>
<ak-application-form slot="form"> </ak-application-form>
<button slot="trigger" class="pf-c-button pf-m-primary">${msg("Create")}</button>
<button slot="trigger" class="pf-c-button pf-m-primary">
${this.newEntityActionLabel}
</button>
</ak-forms-modal>`;
}
renderToolbar(): TemplateResult {
return html` ${super.renderToolbar()}
<ak-forms-confirm
successMessage=${msg("Successfully cleared application cache")}
errorMessage=${msg("Failed to delete application cache")}
success-message=${msg("Successfully cleared application cache")}
error-message=${msg("Failed to delete application cache")}
action=${msg("Clear cache")}
.onConfirm=${() => {
return new PoliciesApi(DEFAULT_CONFIG).policiesAllCacheClearCreate();

View File

@@ -12,6 +12,9 @@ import "#elements/buttons/SpinnerButton/ak-spinner-button";
import { DEFAULT_CONFIG } from "#common/api/config";
import { APIError, parseAPIResponseError, pluckErrorDetail } from "#common/errors/network";
import { formatEditMessage } from "#common/i18n/actions";
import { EntityLabel } from "#common/i18n/nouns";
import { ActionTenseRecord } from "#common/i18n/verbs";
import { AKElement } from "#elements/Base";
@@ -60,6 +63,11 @@ export class ApplicationViewPage extends AKElement {
//#region State
protected entityLabel: EntityLabel = {
singular: msg("Application", { id: "entity.application.singular" }),
plural: msg("Applications", { id: "entity.application.plural" }),
};
@state()
protected application?: Application;
@@ -219,9 +227,11 @@ export class ApplicationViewPage extends AKElement {
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="submit"
>${ActionTenseRecord.apply.present()}</span
>
<span slot="header">
${msg("Update Application")}
${formatEditMessage(this.entityLabel)}
</span>
<ak-application-form
slot="form"
@@ -232,7 +242,7 @@ export class ApplicationViewPage extends AKElement {
slot="trigger"
class="pf-c-button pf-m-secondary"
>
${msg("Edit")}
${formatEditMessage(this.entityLabel)}
</button>
</ak-forms-modal>
</div>

View File

@@ -1,6 +1,7 @@
import "#elements/buttons/SpinnerButton/index";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EntityLabel } from "#common/i18n/nouns";
import { PaginatedResponse, TableColumn } from "#elements/table/Table";
import { TableModal } from "#elements/table/TableModal";
@@ -17,6 +18,11 @@ export class ProviderSelectModal extends TableModal<Provider> {
checkbox = true;
checkboxChip = true;
protected override entityLabel: EntityLabel = {
singular: msg("Provider", { id: "entity.provider.singular" }),
plural: msg("Providers", { id: "entity.provider.plural" }),
};
protected override searchEnabled = true;
@property({ type: Boolean })
@@ -36,8 +42,8 @@ export class ProviderSelectModal extends TableModal<Provider> {
protected columns: TableColumn[] = [
// ---
[msg("Name"), "username"],
[msg("Type")],
[msg("Name", { id: "column.name" }), "username"],
[msg("Type", { id: "column.type" })],
];
row(item: Provider): SlottedTemplateResult[] {

View File

@@ -5,7 +5,7 @@ import "#elements/forms/SearchSelect/index";
import { DEFAULT_CONFIG } from "#common/api/config";
import { CodeMirrorMode } from "#elements/CodeMirror";
import { CodeMirrorHelperText, CodeMirrorMode } from "#elements/CodeMirror";
import { ModelForm } from "#elements/forms/ModelForm";
import { ApplicationEntitlement, CoreApi } from "@goauthentik/api";
@@ -29,12 +29,7 @@ export class ApplicationEntitlementForm extends ModelForm<ApplicationEntitlement
@property()
targetPk?: string;
getSuccessMessage(): string {
if (this.instance?.pbmUuid) {
return msg("Successfully updated entitlement.");
}
return msg("Successfully created entitlement.");
}
protected override entityLabel = msg("Entitlement");
static styles: CSSResult[] = [...super.styles, PFContent];
@@ -54,7 +49,13 @@ export class ApplicationEntitlementForm extends ModelForm<ApplicationEntitlement
}
renderForm(): TemplateResult {
return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">
return html` <ak-form-element-horizontal
label=${msg("Entitlement Name", {
id: "label.entitlement-name",
})}
required
name="name"
>
<input
type="text"
value="${this.instance?.name ?? ""}"
@@ -62,15 +63,18 @@ export class ApplicationEntitlementForm extends ModelForm<ApplicationEntitlement
required
/>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${msg("Attributes")} name="attributes">
<ak-form-element-horizontal
label=${msg("Attributes", {
id: "label.attributes",
})}
name="attributes"
>
<ak-codemirror
mode=${CodeMirrorMode.YAML}
value="${YAML.stringify(this.instance?.attributes ?? {})}"
>
</ak-codemirror>
<p class="pf-c-form__helper-text">
${msg("Set custom attributes using YAML or JSON.")}
</p>
${CodeMirrorHelperText()}
</ak-form-element-horizontal>`;
}
}

View File

@@ -9,6 +9,7 @@ import "#elements/forms/ProxyForm";
import { DEFAULT_CONFIG } from "#common/api/config";
import { PFSize } from "#common/enums";
import { EntityLabel } from "#common/i18n/nouns";
import { PaginatedResponse, Table, TableColumn } from "#elements/table/Table";
import { SlottedTemplateResult } from "#elements/types";
@@ -37,6 +38,11 @@ export class ApplicationEntitlementsPage extends Table<ApplicationEntitlement> {
order = "order";
protected override entityLabel: EntityLabel = {
singular: msg("Entitlement", { id: "entity.entitlement.singular" }),
plural: msg("Entitlements", { id: "entity.entitlement.plural" }),
};
async apiEndpoint(): Promise<PaginatedResponse<ApplicationEntitlement>> {
return new CoreApi(DEFAULT_CONFIG).coreApplicationEntitlementsList({
...(await this.defaultEndpointConfig()),
@@ -46,8 +52,12 @@ export class ApplicationEntitlementsPage extends Table<ApplicationEntitlement> {
protected columns: TableColumn[] = [
// ---
[msg("Name"), "name"],
[msg("Actions"), null, msg("Row Actions")],
[msg("Name", { id: "column.name" }), "name"],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
renderToolbarSelected(): TemplateResult {
@@ -76,8 +86,8 @@ export class ApplicationEntitlementsPage extends Table<ApplicationEntitlement> {
return [
html`${item.name}`,
html`<ak-forms-modal size=${PFSize.Medium}>
<span slot="submit">${msg("Update")}</span>
<span slot="header">${msg("Update Entitlement")}</span>
<span slot="submit">${this.updateEntityLabel}</span>
<span slot="header">${this.editEntityLabel}</span>
<ak-application-entitlement-form
slot="form"
.instancePk=${item.pbmUuid}
@@ -85,7 +95,7 @@ export class ApplicationEntitlementsPage extends Table<ApplicationEntitlement> {
>
</ak-application-entitlement-form>
<button slot="trigger" class="pf-c-button pf-m-plain">
<pf-tooltip position="top" content=${msg("Edit")}>
<pf-tooltip position="top" content=${this.editEntityLabel}>
<i class="fas fa-edit" aria-hidden="true"></i>
</pf-tooltip>
</button>
@@ -126,12 +136,12 @@ export class ApplicationEntitlementsPage extends Table<ApplicationEntitlement> {
renderToolbar(): TemplateResult {
return html`<ak-forms-modal size=${PFSize.Medium}>
<span slot="submit">${msg("Create")}</span>
<span slot="header">${msg("Create Entitlement")}</span>
<span slot="submit">${this.createEntityLabel}</span>
<span slot="header">${this.newEntityActionLabel}</span>
<ak-application-entitlement-form slot="form" targetPk=${ifDefined(this.app)}>
</ak-application-entitlement-form>
<button slot="trigger" class="pf-c-button pf-m-primary">
${msg("Create entitlement")}
${this.newEntityActionLabel}
</button>
</ak-forms-modal> `;
}

View File

@@ -23,9 +23,26 @@ import { msg } from "@lit/localize";
import { html } from "lit";
const renderSummary = (type: string, name: string, fields: DescriptionPair[]) =>
renderDescriptionList([[msg("Type"), type], [msg("Name"), name], ...fields], {
threecolumn: true,
});
renderDescriptionList(
[
[
msg("Type", {
id: "label.type",
}),
type,
],
[
msg("Name", {
id: "label.name",
}),
name,
],
...fields,
],
{
threecolumn: true,
},
);
function renderSAMLOverview(rawProvider: OneOfProvider) {
const provider = rawProvider as SAMLProvider;
@@ -39,22 +56,36 @@ function renderSAMLOverview(rawProvider: OneOfProvider) {
function renderSCIMOverview(rawProvider: OneOfProvider) {
const provider = rawProvider as SCIMProvider;
return renderSummary("SCIM", provider.name, [[msg("URL"), provider.url]]);
return renderSummary("SCIM", provider.name, [
[
msg("URL", {
id: "label.url",
}),
provider.url,
],
]);
}
function renderRadiusOverview(rawProvider: OneOfProvider) {
const provider = rawProvider as RadiusProvider;
return renderSummary("Radius", provider.name, [
[msg("Client Networks"), provider.clientNetworks],
[msg("Client Networks", { id: "label.client-networks" }), provider.clientNetworks],
]);
}
function renderRACOverview(rawProvider: OneOfProvider) {
const provider = rawProvider as RACProvider;
return renderSummary("RAC", provider.name, [
[msg("Connection expiry"), provider.connectionExpiry ?? "-"],
[
msg("Property mappings"),
msg("Connection expiry", {
id: "label.connection-expiry",
}),
provider.connectionExpiry ?? msg("-"),
],
[
msg("Property mappings", {
id: "label.property-mappings",
}),
Array.isArray(provider.propertyMappings) && provider.propertyMappings.length
? provider.propertyMappings.join(", ")
: msg("None"),
@@ -70,45 +101,88 @@ function formatRedirectUris(uris: RedirectURI[] = []) {
html`<li>
${uri.url}
(${uri.matchingMode === MatchingModeEnum.Strict
? msg("strict")
: msg("regexp")})
? msg("strict", { id: "matching-mode.strict" })
: msg("regexp", { id: "matching-mode.regexp" })})
</li>`,
)}
</ul>`
: "-";
}
const proxyModeToLabel = new Map([
[ProxyMode.Proxy, msg("Proxy")],
[ProxyMode.ForwardSingle, msg("Forward auth (single application)")],
[ProxyMode.ForwardDomain, msg("Forward auth (domain-level)")],
[ProxyMode.UnknownDefaultOpenApi, msg("Unknown proxy mode")],
]);
function createProxyModeLabelRecord(): Record<ProxyMode, string> {
return {
[ProxyMode.Proxy]: msg("Proxy", {
id: "label.proxy-mode.proxy",
}),
[ProxyMode.ForwardSingle]: msg("Forward auth (single application)", {
id: "label.proxy-mode.forward-single",
}),
[ProxyMode.ForwardDomain]: msg("Forward auth (domain-level)", {
id: "label.proxy-mode.forward-domain",
}),
[ProxyMode.UnknownDefaultOpenApi]: msg("Unknown proxy mode", {
id: "label.proxy-mode.unknown",
}),
};
}
function renderProxyOverview(rawProvider: OneOfProvider) {
const provider = rawProvider as ProxyProvider;
const proxyModeToLabel = createProxyModeLabelRecord();
const mode = provider.mode ?? ProxyMode.Proxy;
const modeLabel = proxyModeToLabel[mode];
return renderSummary("Proxy", provider.name, [
[msg("Mode"), proxyModeToLabel.get(provider.mode ?? ProxyMode.Proxy)],
[msg("Mode", { id: "label.proxy-mode" }), modeLabel],
...match(provider.mode)
.with(
ProxyMode.Proxy,
() =>
[
[msg("Internal Host"), provider.internalHost],
[msg("External Host"), provider.externalHost],
] as DescriptionPair[],
[
msg("Internal Host", {
id: "label.internal-host",
}),
provider.internalHost,
],
[
msg("External Host", {
id: "label.external-host",
}),
provider.externalHost,
],
] satisfies DescriptionPair[],
)
.with(
ProxyMode.ForwardSingle,
() => [[msg("External Host"), provider.externalHost]] as DescriptionPair[],
() =>
[
[
msg("External Host", {
id: "label.external-host",
}),
provider.externalHost,
],
] satisfies DescriptionPair[],
)
.with(
ProxyMode.ForwardDomain,
() =>
[
[msg("Authentication URL"), provider.externalHost],
[msg("Cookie domain"), provider.cookieDomain],
] as DescriptionPair[],
[
msg("Authentication URL", {
id: "label.authentication-url",
}),
provider.externalHost,
],
[
msg("Cookie domain", {
id: "label.cookie-domain",
}),
provider.cookieDomain,
],
] satisfies DescriptionPair[],
)
.otherwise(() => {
throw new Error(
@@ -125,24 +199,57 @@ function renderProxyOverview(rawProvider: OneOfProvider) {
]);
}
const clientTypeToLabel = new Map<ClientTypeEnum, string>([
[ClientTypeEnum.Confidential, msg("Confidential")],
[ClientTypeEnum.Public, msg("Public")],
[ClientTypeEnum.UnknownDefaultOpenApi, msg("Unknown type")],
]);
function createClientTypeLabelRecord(): Record<ClientTypeEnum, string> {
return {
[ClientTypeEnum.Confidential]: msg("Confidential", {
id: "label.oauth2.client.type.confidential",
}),
[ClientTypeEnum.Public]: msg("Public", {
id: "label.oauth2.client.type.public",
}),
[ClientTypeEnum.UnknownDefaultOpenApi]: msg("Unknown type", {
id: "label.oauth2.client.type.unknown",
}),
};
}
function renderOAuth2Overview(rawProvider: OneOfProvider) {
const provider = rawProvider as OAuth2Provider;
const clientTypeToLabel = createClientTypeLabelRecord();
const clientTypeLabel = provider.clientType ? clientTypeToLabel[provider.clientType] : "";
return renderSummary("OAuth2", provider.name, [
[msg("Client type"), provider.clientType ? clientTypeToLabel.get(provider.clientType) : ""],
[msg("Client ID"), provider.clientId],
[msg("Redirect URIs"), formatRedirectUris(provider.redirectUris)],
[
msg("Client type", {
id: "label.oauth2.client.type",
}),
clientTypeLabel,
],
[
msg("Client ID", {
id: "label.oauth2.client.id",
}),
provider.clientId,
],
[
msg("Redirect URIs", {
id: "label.oauth2.redirect.uris",
}),
formatRedirectUris(provider.redirectUris),
],
]);
}
function renderLDAPOverview(rawProvider: OneOfProvider) {
const provider = rawProvider as LDAPProvider;
return renderSummary("Proxy", provider.name, [[msg("Base DN"), provider.baseDn]]);
return renderSummary("Proxy", provider.name, [
[
msg("Base DN", {
id: "label.ldap.base.dn",
}),
provider.baseDn,
],
]);
}
const providerName = (p: ProviderModelEnum): string => p.toString().split(".")[1];

View File

@@ -30,7 +30,11 @@ const COLUMNS = [
[msg("Binding")],
[msg("Enabled"), "enabled"],
[msg("Timeout"), "timeout"],
[msg("Actions"), null, msg("Row Actions")],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
@customElement("ak-application-wizard-bindings-step")

View File

@@ -29,7 +29,7 @@ export class ApplicationWizardRACProviderForm extends ApplicationWizardProviderF
<form id="providerform" class="pf-c-form pf-m-horizontal" slot="form">
<ak-text-input
name="name"
label=${msg("Name")}
label=${msg("Provider Name", { id: "label.provider-name" })}
value=${ifDefined(provider.name)}
.errorMessages=${this.errorMessages("name")}
required
@@ -61,17 +61,24 @@ export class ApplicationWizardRACProviderForm extends ApplicationWizardProviderF
input-hint="code"
></ak-text-input>
<ak-form-group open label="${msg("Protocol settings")}">
<ak-form-group
open
label="${msg("Protocol settings", { id: "label.protocol-settings" })}"
>
<div class="pf-c-form">
<ak-form-element-horizontal
label=${msg("Property mappings")}
label=${msg("Property mappings", { id: "label.property-mappings" })}
name="propertyMappings"
>
<ak-dual-select-dynamic-selected
.provider=${propertyMappingsProvider}
.selector=${propertyMappingsSelector(provider?.propertyMappings)}
available-label="${msg("Available Property Mappings")}"
selected-label="${msg("Selected Property Mappings")}"
available-label=${msg("Available Property Mappings", {
id: "label.available-property-mappings",
})}
selected-label=${msg("Selected Property Mappings", {
id: "label.selected-property-mappings",
})}
></ak-dual-select-dynamic-selected>
</ak-form-element-horizontal>
</div>

View File

@@ -46,11 +46,7 @@ export class BlueprintForm extends ModelForm<BlueprintInstance, string> {
return inst;
}
getSuccessMessage(): string {
return this.instance
? msg("Successfully updated instance.")
: msg("Successfully created instance.");
}
protected override entityLabel = msg("Instance");
static styles: CSSResult[] = [...super.styles, PFContent];
@@ -67,7 +63,13 @@ export class BlueprintForm extends ModelForm<BlueprintInstance, string> {
}
renderForm(): TemplateResult {
return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">
return html` <ak-form-element-horizontal
label=${msg("Blueprint Name", {
id: "label.blueprint-name",
})}
required
name="name"
>
<input
type="text"
value="${ifDefined(this.instance?.name)}"

View File

@@ -58,7 +58,10 @@ export function formatBlueprintDescription(item: BlueprintInstance): string | nu
@customElement("ak-blueprint-list")
export class BlueprintListPage extends TablePage<BlueprintInstance> {
protected override searchEnabled = true;
public pageTitle = msg("Blueprints");
protected override entityLabel = {
singular: msg("Blueprint Instance", { id: "entity.blueprint-instance.singular" }),
plural: msg("Blueprint Instances", { id: "entity.blueprint-instance.plural" }),
};
public pageDescription = msg("Automate and template configuration within authentik.");
public pageIcon = "pf-icon pf-icon-blueprint";
@@ -78,11 +81,15 @@ export class BlueprintListPage extends TablePage<BlueprintInstance> {
}
protected columns: TableColumn[] = [
[msg("Name"), "name"],
[msg("Status"), "status"],
[msg("Last applied"), "last_applied"],
[msg("Enabled"), "enabled"],
[msg("Actions"), null, msg("Row Actions")],
[msg("Name", { id: "column.name" }), "name"],
[msg("Status", { id: "column.status" }), "status"],
[msg("Last applied", { id: "column.last-applied" }), "last_applied"],
[msg("Enabled", { id: "column.enabled" }), "enabled"],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
renderToolbarSelected(): TemplateResult {
@@ -156,7 +163,7 @@ export class BlueprintListPage extends TablePage<BlueprintInstance> {
html`<ak-status-label ?good=${item.enabled}></ak-status-label>`,
html`<div>
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="submit">${this.updateEntityLabel}</span>
<span slot="header">${msg("Update Blueprint")}</span>
<ak-blueprint-form slot="form" .instancePk=${item.pk}> </ak-blueprint-form>
<button
@@ -204,10 +211,12 @@ export class BlueprintListPage extends TablePage<BlueprintInstance> {
renderObjectCreate(): TemplateResult {
return html`
<ak-forms-modal>
<span slot="submit">${msg("Create")}</span>
<span slot="header">${msg("Create Blueprint Instance")}</span>
<span slot="submit">${this.createEntityLabel}</span>
<span slot="header">${this.newEntityActionLabel}</span>
<ak-blueprint-form slot="form"> </ak-blueprint-form>
<button slot="trigger" class="pf-c-button pf-m-primary">${msg("Create")}</button>
<button slot="trigger" class="pf-c-button pf-m-primary">
${this.newEntityActionLabel}
</button>
</ak-forms-modal>
`;
}

View File

@@ -41,11 +41,7 @@ export class BrandForm extends ModelForm<Brand, string> {
});
}
getSuccessMessage(): string {
return this.instance
? msg("Successfully updated brand.")
: msg("Successfully created brand.");
}
protected override entityLabel = msg("Brand");
async send(data: Brand): Promise<Brand> {
data.attributes ??= {};

View File

@@ -21,8 +21,16 @@ import { customElement, property } from "lit/decorators.js";
@customElement("ak-brand-list")
export class BrandListPage extends TablePage<Brand> {
protected override searchEnabled = true;
public override searchPlaceholder = msg("Search by domain or brand name...");
public pageTitle = msg("Brands");
protected override entityLabel = {
singular: msg("Brand", { id: "entity.brand.singular" }),
plural: msg("Brands", { id: "entity.brand.plural" }),
};
protected get searchPlaceholder() {
return msg("Search by domain or brand name...", {
id: "search.placeholder.brand-list",
});
}
public pageDescription = msg("Configure visual settings and defaults for different domains.");
public pageIcon = "pf-icon pf-icon-tenant";
@@ -41,10 +49,14 @@ export class BrandListPage extends TablePage<Brand> {
}
protected columns: TableColumn[] = [
[msg("Domain"), "domain"],
[msg("Brand name"), "branding_title"],
[msg("Default?"), "default"],
[msg("Actions"), null, msg("Row Actions")],
[msg("Domain", { id: "column.domain" }), "domain"],
[msg("Brand name", { id: "column.brand-name" }), "branding_title"],
[msg("Default?", { id: "column.default-question-mark" }), "default"],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
renderToolbarSelected(): TemplateResult {
@@ -79,7 +91,7 @@ export class BrandListPage extends TablePage<Brand> {
html`<ak-status-label ?good=${item._default}></ak-status-label>`,
html`<div>
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="submit">${this.updateEntityLabel}</span>
<span slot="header">${msg("Update Brand")}</span>
<ak-brand-form slot="form" .instancePk=${item.brandUuid}> </ak-brand-form>
<button slot="trigger" class="pf-c-button pf-m-plain">
@@ -101,10 +113,12 @@ export class BrandListPage extends TablePage<Brand> {
renderObjectCreate(): TemplateResult {
return html`
<ak-forms-modal>
<span slot="submit">${msg("Create Brand")}</span>
<span slot="header">${msg("New Brand")}</span>
<span slot="submit">${this.createEntityLabel}</span>
<span slot="header">${this.newEntityActionLabel}</span>
<ak-brand-form slot="form"> </ak-brand-form>
<button slot="trigger" class="pf-c-button pf-m-primary">${msg("New Brand")}</button>
<button slot="trigger" class="pf-c-button pf-m-primary">
${this.newEntityActionLabel}
</button>
</ak-forms-modal>
`;
}

View File

@@ -17,9 +17,10 @@ import { customElement } from "lit/decorators.js";
@customElement("ak-crypto-certificate-generate-form")
export class CertificateKeyPairForm extends Form<CertificateGenerationRequest> {
getSuccessMessage(): string {
return msg("Successfully generated certificate-key pair.");
}
protected override readonly actionName = "generate";
protected override entityLabel = msg("Certificate Key Pair", {
id: "entity.certificate-key-pair.singular",
});
async send(data: CertificateGenerationRequest): Promise<CertificateKeyPair> {
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsGenerateCreate({

View File

@@ -21,11 +21,9 @@ export class CertificateKeyPairForm extends ModelForm<CertificateKeyPair, string
});
}
getSuccessMessage(): string {
return this.instance
? msg("Successfully updated certificate-key pair.")
: msg("Successfully created certificate-key pair.");
}
protected override entityLabel = msg("Certificate Key Pair", {
id: "entity.certificate-key-pair.singular",
});
async send(data: CertificateKeyPair): Promise<CertificateKeyPair> {
if (this.instance) {
@@ -40,7 +38,11 @@ export class CertificateKeyPairForm extends ModelForm<CertificateKeyPair, string
}
renderForm(): TemplateResult {
return html` <ak-form-element-horizontal label=${msg("Name")} name="name" required>
return html` <ak-form-element-horizontal
label=${msg("Certificate Key Pair Name", { id: "label.certificate-key-pair-name" })}
name="name"
required
>
<input
type="text"
value="${ifDefined(this.instance?.name)}"

View File

@@ -33,9 +33,15 @@ export class CertificateKeyPairListPage extends TablePage<CertificateKeyPair> {
clearOnRefresh = true;
protected override searchEnabled = true;
public pageTitle = msg("Certificate-Key Pairs");
protected override entityLabel = {
singular: msg("Certificate Key Pair", { id: "entity.certificate-key-pair.singular" }),
plural: msg("Certificate Key Pairs", { id: "entity.certificate-key-pair.plural" }),
};
public pageDescription = msg(
"Import certificates of external providers or create certificates to sign requests with.",
{
id: "page.description.certificate-key-pair-list",
},
);
public pageIcon = "pf-icon pf-icon-key";
@@ -51,10 +57,14 @@ export class CertificateKeyPairListPage extends TablePage<CertificateKeyPair> {
}
protected columns: TableColumn[] = [
[msg("Name"), "name"],
[msg("Private key available?")],
[msg("Expiry date")],
[msg("Actions"), null, msg("Row Actions")],
[msg("Name", { id: "column.name" }), "name"],
[msg("Private key available?", { id: "column.private-key-available-question-mark" })],
[msg("Expiry date", { id: "column.expiry-date" })],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
renderToolbarSelected(): TemplateResult {
@@ -114,7 +124,7 @@ export class CertificateKeyPairListPage extends TablePage<CertificateKeyPair> {
html`<ak-label color=${color}> ${item.certExpiry?.toLocaleString()} </ak-label>`,
html`<div>
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="submit">${this.updateEntityLabel}</span>
<span slot="header">${msg("Update Certificate-Key Pair")}</span>
<ak-crypto-certificate-form slot="form" .instancePk=${item.pk}>
</ak-crypto-certificate-form>

View File

@@ -25,11 +25,7 @@ export class EnterpriseLicenseForm extends ModelForm<License, string> {
});
}
getSuccessMessage(): string {
return this.instance
? msg("Successfully updated license.")
: msg("Successfully created license.");
}
protected override entityLabel = msg("License");
async load(): Promise<void> {
this.installID = (

View File

@@ -41,7 +41,10 @@ export class EnterpriseLicenseListPage extends TablePage<License> {
clearOnRefresh = true;
protected override searchEnabled = true;
public pageTitle = msg("Licenses");
protected override entityLabel = {
singular: msg("License", { id: "entity.license.singular" }),
plural: msg("Licenses", { id: "entity.license.plural" }),
};
public pageDescription = msg("Manage enterprise licenses");
public pageIcon = "pf-icon pf-icon-key";
@@ -88,10 +91,14 @@ export class EnterpriseLicenseListPage extends TablePage<License> {
}
protected columns: TableColumn[] = [
[msg("Name"), "name"],
[msg("Users")],
[msg("Expiry date")],
[msg("Actions"), null, msg("Row Actions")],
[msg("Name", { id: "column.name" }), "name"],
[msg("Users", { id: "column.users" })],
[msg("Expiry date", { id: "column.expiry-date" })],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
// TODO: Make this more generic, maybe automatically get the plural name
@@ -221,7 +228,7 @@ export class EnterpriseLicenseListPage extends TablePage<License> {
html`<ak-label color=${color}> ${item.expiry?.toLocaleString()} </ak-label>`,
html`<div>
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="submit">${this.updateEntityLabel}</span>
<span slot="header">${msg("Update License")}</span>
<ak-enterprise-license-form slot="form" .instancePk=${item.licenseUuid}>
</ak-enterprise-license-form>

View File

@@ -28,7 +28,17 @@ export class EventListPage extends WithLicenseSummary(TablePage<Event>) {
expandable = true;
supportsQL = true;
public pageTitle = msg("Event Log");
protected override entityLabel = {
singular: msg("Event Log", { id: "entity.event-log.singular" }),
plural: msg("Event Log", { id: "entity.plural.event-log" }),
};
protected override get searchPlaceholder() {
return msg("Search for an event by action or user...", {
id: "search.placeholder.event-list",
});
}
public pageDescription = "";
public pageIcon = "pf-icon pf-icon-catalog";
@@ -52,12 +62,16 @@ export class EventListPage extends WithLicenseSummary(TablePage<Event>) {
}
protected columns: TableColumn[] = [
[msg("Action"), "action"],
[msg("User"), "user"],
[msg("Creation Date"), "created"],
[msg("Client IP"), "client_ip"],
[msg("Brand"), "brand_name"],
[msg("Actions"), null, msg("Row Actions")],
[msg("Action", { id: "column.action" }), "action"],
[msg("User", { id: "column.user" }), "user"],
[msg("Creation Date", { id: "column.creation-date" }), "created"],
[msg("Client IP", { id: "column.client-ip" }), "client_ip"],
[msg("Brand", { id: "column.brand" }), "brand_name"],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
protected override rowLabel(item: Event): string | null {

View File

@@ -41,11 +41,7 @@ export class RuleForm extends ModelForm<NotificationRule, string> {
});
}
getSuccessMessage(): string {
return this.instance
? msg("Successfully updated rule.")
: msg("Successfully created rule.");
}
protected override entityLabel = msg("Rule");
async send(data: NotificationRule): Promise<NotificationRule> {
if (this.instance) {
@@ -60,7 +56,11 @@ export class RuleForm extends ModelForm<NotificationRule, string> {
}
renderForm(): TemplateResult {
return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">
return html` <ak-form-element-horizontal
label=${msg("Rule Name", { id: "label.rule-name" })}
required
name="name"
>
<input
type="text"
value="${ifDefined(this.instance?.name)}"

View File

@@ -33,9 +33,15 @@ export class RuleListPage extends TablePage<NotificationRule> {
clearOnRefresh = true;
protected override searchEnabled = true;
public pageTitle = msg("Notification Rules");
protected override entityLabel = {
singular: msg("Notification Rule", { id: "entity.notification-rule.singular" }),
plural: msg("Notification Rules", { id: "entity.notification-rule.plural" }),
};
public pageDescription = msg(
"Send notifications whenever a specific Event is created and matched by policies.",
{
id: "page.description.event-rule-list",
},
);
public pageIcon = "pf-icon pf-icon-attention-bell";
@@ -47,11 +53,15 @@ export class RuleListPage extends TablePage<NotificationRule> {
}
protected columns: TableColumn[] = [
[msg("Enabled")],
[msg("Name"), "name"],
[msg("Severity"), "severity"],
[msg("Sent to group"), "group"],
[msg("Actions"), null, msg("Row Actions")],
[msg("Enabled", { id: "column.enabled" })],
[msg("Name", { id: "column.name" }), "name"],
[msg("Severity", { id: "column.severity" }), "severity"],
[msg("Sent to group", { id: "column.send-to-group" }), "group"],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
renderToolbarSelected(): TemplateResult {
@@ -89,7 +99,7 @@ export class RuleListPage extends TablePage<NotificationRule> {
: msg("-")}`,
html`<div>
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="submit">${this.updateEntityLabel}</span>
<span slot="header">${msg("Update Notification Rule")}</span>
<ak-event-rule-form slot="form" .instancePk=${item.pk}> </ak-event-rule-form>
<button slot="trigger" class="pf-c-button pf-m-plain">
@@ -111,10 +121,12 @@ export class RuleListPage extends TablePage<NotificationRule> {
renderObjectCreate(): TemplateResult {
return html`
<ak-forms-modal>
<span slot="submit">${msg("Create")}</span>
<span slot="header">${msg("Create Notification Rule")}</span>
<span slot="submit">${this.createEntityLabel}</span>
<span slot="header">${this.newEntityActionLabel}</span>
<ak-event-rule-form slot="form"> </ak-event-rule-form>
<button slot="trigger" class="pf-c-button pf-m-primary">${msg("Create")}</button>
<button slot="trigger" class="pf-c-button pf-m-primary">
${this.newEntityActionLabel}
</button>
</ak-forms-modal>
`;
}

View File

@@ -47,11 +47,7 @@ export class TransportForm extends ModelForm<NotificationTransport, string> {
@property({ type: Boolean })
showEmail = false;
getSuccessMessage(): string {
return this.instance
? msg("Successfully updated transport.")
: msg("Successfully created transport.");
}
protected override entityLabel = msg("Transport");
async send(data: NotificationTransport): Promise<NotificationTransport> {
if (this.instance) {
@@ -87,7 +83,11 @@ export class TransportForm extends ModelForm<NotificationTransport, string> {
renderForm(): TemplateResult {
return html`
<ak-form-element-horizontal label=${msg("Name")} required name="name">
<ak-form-element-horizontal
label=${msg("Transport Name", { id: "label.transport-name" })}
required
name="name"
>
<input
type="text"
value="${ifDefined(this.instance?.name)}"

View File

@@ -27,9 +27,15 @@ import { customElement, property } from "lit/decorators.js";
@customElement("ak-event-transport-list")
export class TransportListPage extends TablePage<NotificationTransport> {
protected override searchEnabled = true;
public pageTitle = msg("Notification Transports");
protected override entityLabel = {
singular: msg("Notification Transport", { id: "entity.notification-transport.singular" }),
plural: msg("Notification Transports", { id: "entity.notification-transport.plural" }),
};
public pageDescription = msg(
"Define how notifications are sent to users, like Email or Webhook.",
{
id: "page.description.event-transport-list",
},
);
public pageIcon = "pf-icon pf-icon-export";
@@ -47,9 +53,13 @@ export class TransportListPage extends TablePage<NotificationTransport> {
}
protected columns: TableColumn[] = [
[msg("Name"), "name"],
[msg("Mode"), "mode"],
[msg("Actions"), null, msg("Row Actions")],
[msg("Name", { id: "column.name" }), "name"],
[msg("Mode", { id: "column.mode" }), "mode"],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
renderToolbarSelected(): TemplateResult {
@@ -80,7 +90,7 @@ export class TransportListPage extends TablePage<NotificationTransport> {
html`${item.modeVerbose}`,
html`<div>
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="submit">${this.updateEntityLabel}</span>
<span slot="header">${msg("Update Notification Transport")}</span>
<ak-event-transport-form slot="form" .instancePk=${item.pk}>
</ak-event-transport-form>
@@ -135,10 +145,12 @@ export class TransportListPage extends TablePage<NotificationTransport> {
renderObjectCreate(): TemplateResult {
return html`
<ak-forms-modal>
<span slot="submit">${msg("Create")}</span>
<span slot="header">${msg("Create Notification Transport")}</span>
<span slot="submit">${this.createEntityLabel}</span>
<span slot="header">${this.newEntityActionLabel}</span>
<ak-event-transport-form slot="form"> </ak-event-transport-form>
<button slot="trigger" class="pf-c-button pf-m-primary">${msg("Create")}</button>
<button slot="trigger" class="pf-c-button pf-m-primary">
${this.newEntityActionLabel}
</button>
</ak-forms-modal>
`;
}

View File

@@ -8,6 +8,7 @@ import "#elements/forms/ModalForm";
import "#elements/forms/ProxyForm";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EntityLabel } from "#common/i18n/nouns";
import { PaginatedResponse, Table, TableColumn } from "#elements/table/Table";
import { SlottedTemplateResult } from "#elements/types";
@@ -31,6 +32,11 @@ export class BoundStagesList extends Table<FlowStageBinding> {
order = "order";
protected override entityLabel: EntityLabel = {
singular: msg("Stage Binding", { id: "entity.stage-binding.singular" }),
plural: msg("Stage Bindings", { id: "entity.stage-binding.plural" }),
};
@property()
target?: string;
@@ -46,10 +52,14 @@ export class BoundStagesList extends Table<FlowStageBinding> {
}
protected columns: TableColumn[] = [
[msg("Order"), "order"],
[msg("Name"), "stage__name"],
[msg("Type")],
[msg("Actions"), null, msg("Row Actions")],
[msg("Order", { id: "column.order" }), "order"],
[msg("Name", { id: "column.name" }), "stage__name"],
[msg("Type", { id: "column.type" })],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
renderToolbarSelected(): TemplateResult {
@@ -86,7 +96,7 @@ export class BoundStagesList extends Table<FlowStageBinding> {
html`${item.stageObj?.name}`,
html`${item.stageObj?.verboseName}`,
html` <ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="submit">${this.updateEntityLabel}</span>
<span slot="header">${msg(str`Update ${item.stageObj?.verboseName}`)}</span>
<ak-proxy-form
slot="form"
@@ -97,11 +107,11 @@ export class BoundStagesList extends Table<FlowStageBinding> {
>
</ak-proxy-form>
<button slot="trigger" class="pf-c-button pf-m-secondary">
${msg("Edit Stage")}
${this.editEntityLabel}
</button>
</ak-forms-modal>
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="submit">${this.updateEntityLabel}</span>
<span slot="header">${msg("Update Stage binding")}</span>
<ak-stage-binding-form slot="form" .instancePk=${item.pk}>
</ak-stage-binding-form>
@@ -140,8 +150,8 @@ export class BoundStagesList extends Table<FlowStageBinding> {
bindingTarget=${ifDefined(this.target)}
></ak-stage-wizard>
<ak-forms-modal>
<span slot="submit">${msg("Create")}</span>
<span slot="header">${msg("Create Stage binding")}</span>
<span slot="submit">${this.createEntityLabel}</span>
<span slot="header">${this.newEntityActionLabel}</span>
<ak-stage-binding-form slot="form" targetPk=${ifDefined(this.target)}>
</ak-stage-binding-form>
<button slot="trigger" class="pf-c-button pf-m-primary">
@@ -161,8 +171,8 @@ export class BoundStagesList extends Table<FlowStageBinding> {
bindingTarget=${ifDefined(this.target)}
></ak-stage-wizard>
<ak-forms-modal>
<span slot="submit">${msg("Create")}</span>
<span slot="header">${msg("Create Stage binding")}</span>
<span slot="submit">${this.createEntityLabel}</span>
<span slot="header">${this.newEntityActionLabel}</span>
<ak-stage-binding-form slot="form" targetPk=${ifDefined(this.target)}>
</ak-stage-binding-form>
<button slot="trigger" class="pf-c-button pf-m-primary">

View File

@@ -35,11 +35,7 @@ export class FlowForm extends WithCapabilitiesConfig(ModelForm<Flow, string>) {
return flow;
}
getSuccessMessage(): string {
return this.instance
? msg("Successfully updated flow.")
: msg("Successfully created flow.");
}
protected override entityLabel = msg("Flow");
@property({ type: Boolean })
clearBackground = false;
@@ -78,7 +74,11 @@ export class FlowForm extends WithCapabilitiesConfig(ModelForm<Flow, string>) {
}
renderForm(): TemplateResult {
return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">
return html` <ak-form-element-horizontal
label=${msg("Flow Name", { id: "label.flow-name" })}
required
name="name"
>
<input
type="text"
value="${ifDefined(this.instance?.name)}"

View File

@@ -21,9 +21,9 @@ export class FlowImportForm extends Form<Flow> {
@state()
result?: FlowImportResult;
getSuccessMessage(): string {
return msg("Successfully imported flow.");
}
protected override readonly actionName = "import";
protected override entityLabel = msg("Flow");
static styles: CSSResult[] = [...super.styles, PFDescriptionList];

View File

@@ -24,12 +24,22 @@ import { customElement, property } from "lit/decorators.js";
@customElement("ak-flow-list")
export class FlowListPage extends TablePage<Flow> {
protected override searchEnabled = true;
public pageTitle = msg("Flows");
protected override entityLabel = {
singular: msg("Flow", { id: "entity.flow.singular" }),
plural: msg("Flows", { id: "entity.flow.plural" }),
};
public pageDescription = msg(
"Flows describe a chain of Stages to authenticate, enroll or recover a user. Stages are chosen based on policies applied to them.",
{
id: "page.description.flow-list",
},
);
public pageIcon = "pf-icon pf-icon-process-automation";
protected override get searchPlaceholder(): string {
return msg("Search by flow name or identifier...");
}
checkbox = true;
clearOnRefresh = true;
@@ -48,10 +58,14 @@ export class FlowListPage extends TablePage<Flow> {
protected columns: TableColumn[] = [
[msg("Identifier"), "slug"],
[msg("Name"), "name"],
[msg("Stages")],
[msg("Policies")],
[msg("Actions"), null, msg("Row Actions")],
[msg("Name", { id: "column.name" }), "name"],
[msg("Stages", { id: "column.stages" })],
[msg("Policies", { id: "column.policies" })],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
renderToolbarSelected(): TemplateResult {
@@ -86,7 +100,7 @@ export class FlowListPage extends TablePage<Flow> {
html`${Array.from(item.stages || []).length}`,
html`${Array.from(item.policies || []).length}`,
html` <ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="submit">${this.updateEntityLabel}</span>
<span slot="header">${msg("Update Flow")}</span>
<ak-flow-form slot="form" .instancePk=${item.slug}> </ak-flow-form>
<button
@@ -128,16 +142,24 @@ export class FlowListPage extends TablePage<Flow> {
renderObjectCreate(): TemplateResult {
return html`
<ak-forms-modal>
<span slot="submit">${msg("Create")}</span>
<span slot="header">${msg("Create Flow")}</span>
<span slot="submit">${this.createEntityLabel}</span>
<span slot="header">${this.newEntityActionLabel}</span>
<ak-flow-form slot="form"> </ak-flow-form>
<button slot="trigger" class="pf-c-button pf-m-primary">${msg("Create")}</button>
<button slot="trigger" class="pf-c-button pf-m-primary">
${this.newEntityActionLabel}
</button>
</ak-forms-modal>
<ak-forms-modal>
<span slot="submit">${msg("Import")}</span>
<span slot="header">${msg("Import Flow")}</span>
<ak-flow-import-form slot="form"> </ak-flow-import-form>
<button slot="trigger" class="pf-c-button pf-m-primary">${msg("Import")}</button>
<button
slot="trigger"
class="pf-c-button pf-m-primary"
aria-label=${msg("Import Flow")}
>
${msg("Import")}
</button>
</ak-forms-modal>
`;
}
@@ -146,8 +168,8 @@ export class FlowListPage extends TablePage<Flow> {
return html`
${super.renderToolbar()}
<ak-forms-confirm
successMessage=${msg("Successfully cleared flow cache")}
errorMessage=${msg("Failed to delete flow cache")}
success-message=${msg("Successfully cleared flow cache")}
error-message=${msg("Failed to delete flow cache")}
action=${msg("Clear cache")}
.onConfirm=${() => {
return new FlowsApi(DEFAULT_CONFIG).flowsInstancesCacheClearCreate();

View File

@@ -123,13 +123,13 @@ export class FlowViewPage extends AKElement {
</dd>
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text"
>${msg("Related actions")}</span
>${msg("Actions")}</span
>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">
<ak-forms-modal>
<span slot="submit"> ${msg("Update")} </span>
<span slot="submit">${msg("Update")}</span>
<span slot="header">
${msg("Update Flow")}
</span>
@@ -147,6 +147,16 @@ export class FlowViewPage extends AKElement {
</ak-forms-modal>
</div>
</dd>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">
<a
class="pf-c-button pf-m-block pf-m-secondary"
href=${this.flow.exportUrl}
>
${msg("Export")}
</a>
</div>
</dd>
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text"
>${msg("Execute flow")}</span
@@ -222,21 +232,6 @@ export class FlowViewPage extends AKElement {
</button>
</div>
</dd>
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text"
>${msg("Export flow")}</span
>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">
<a
class="pf-c-button pf-m-block pf-m-secondary"
href=${this.flow.exportUrl}
>
${msg("Export")}
</a>
</div>
</dd>
</div>
</dl>
</div>

View File

@@ -40,12 +40,7 @@ export class StageBindingForm extends ModelForm<FlowStageBinding, string> {
@state()
defaultOrder = 0;
getSuccessMessage(): string {
if (this.instance?.pk) {
return msg("Successfully updated binding.");
}
return msg("Successfully created binding.");
}
protected override entityLabel = msg("Binding");
send(data: FlowStageBinding): Promise<unknown> {
if (this.instance?.pk) {

View File

@@ -11,7 +11,7 @@ import "#components/ak-switch-input";
import { DEFAULT_CONFIG } from "#common/api/config";
import { DataProvision, DualSelectPair } from "#elements/ak-dual-select/types";
import { CodeMirrorMode } from "#elements/CodeMirror";
import { CodeMirrorHelperText, CodeMirrorMode } from "#elements/CodeMirror";
import { ModelForm } from "#elements/forms/ModelForm";
import { CoreApi, CoreGroupsListRequest, Group, RbacApi, Role } from "@goauthentik/api";
@@ -48,11 +48,7 @@ export class GroupForm extends ModelForm<Group, string> {
});
}
getSuccessMessage(): string {
return this.instance
? msg("Successfully updated group.")
: msg("Successfully created group.");
}
protected override entityLabel = msg("Group");
async send(data: Group): Promise<Group> {
data.attributes ??= {};
@@ -147,9 +143,7 @@ export class GroupForm extends ModelForm<Group, string> {
value="${YAML.stringify(this.instance?.attributes ?? {})}"
>
</ak-codemirror>
<p class="pf-c-form__helper-text">
${msg("Set custom attributes using YAML or JSON.")}
</p>
${CodeMirrorHelperText()}
</ak-form-element-horizontal>`;
}
}

View File

@@ -6,6 +6,7 @@ import "#elements/forms/ModalForm";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EntityLabel } from "#common/i18n/nouns";
import { PaginatedResponse, TableColumn } from "#elements/table/Table";
import { TablePage } from "#elements/table/TablePage";
@@ -22,11 +23,22 @@ export class GroupListPage extends TablePage<Group> {
checkbox = true;
clearOnRefresh = true;
protected override searchEnabled = true;
public searchPlaceholder = msg("Search for a group by name…");
public searchLabel = msg("Group Search");
public pageTitle = msg("Groups");
protected override entityLabel: EntityLabel = {
singular: msg("Group", { id: "entity.group.singular" }),
plural: msg("Groups", { id: "entity.group.plural" }),
};
protected override get searchPlaceholder() {
return msg("Search for a group by name...", {
id: "search.placeholder.groups-list",
});
}
public pageDescription = msg(
"Group users together and give them permissions based on the membership.",
{
id: "page.description.groups-list",
},
);
public pageIcon = "pf-icon pf-icon-users";
public supportsQL = true;
@@ -42,11 +54,15 @@ export class GroupListPage extends TablePage<Group> {
}
protected columns: TableColumn[] = [
[msg("Name"), "name"],
[msg("Parent"), "parent"],
[msg("Members")],
[msg("Superuser privileges?")],
[msg("Actions"), null, msg("Row Actions")],
[msg("Name", { id: "column.name" }), "name"],
[msg("Parent", { id: "column.parent" }), "parent"],
[msg("Members", { id: "column.members" })],
[msg("Superuser privileges?", { id: "column.superuser-privileges-question-mark" })],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
renderToolbarSelected(): TemplateResult {
@@ -83,11 +99,11 @@ export class GroupListPage extends TablePage<Group> {
html`<ak-status-label type="neutral" ?good=${item.isSuperuser}></ak-status-label>`,
html`<div>
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="header">${msg("Update Group")}</span>
<span slot="submit">${this.updateEntityLabel}</span>
<span slot="header">${this.editEntityLabel}</span>
<ak-group-form slot="form" .instancePk=${item.pk}> </ak-group-form>
<button slot="trigger" class="pf-c-button pf-m-plain">
<pf-tooltip position="top" content=${msg("Edit")}>
<pf-tooltip position="top" content=${this.editEntityLabel}>
<i class="fas fa-edit" aria-hidden="true"></i>
</pf-tooltip>
</button>
@@ -99,10 +115,12 @@ export class GroupListPage extends TablePage<Group> {
renderObjectCreate(): TemplateResult {
return html`
<ak-forms-modal>
<span slot="submit">${msg("Create Group")}</span>
<span slot="header">${msg("New Group")}</span>
<span slot="submit">${this.createEntityLabel}</span>
<span slot="header">${this.newEntityActionLabel}</span>
<ak-group-form slot="form"> </ak-group-form>
<button slot="trigger" class="pf-c-button pf-m-primary">${msg("New Group")}</button>
<button slot="trigger" class="pf-c-button pf-m-primary">
${this.newEntityActionLabel}
</button>
</ak-forms-modal>
`;
}

View File

@@ -12,6 +12,9 @@ import "#elements/ak-mdx/ak-mdx";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EVENT_REFRESH } from "#common/constants";
import { formatEditMessage } from "#common/i18n/actions";
import { EntityLabel } from "#common/i18n/nouns";
import { ActionTenseRecord } from "#common/i18n/verbs";
import { AKElement } from "#elements/Base";
import { SlottedTemplateResult } from "#elements/types";
@@ -37,6 +40,11 @@ import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css";
@customElement("ak-group-view")
export class GroupViewPage extends AKElement {
protected entityLabel: EntityLabel = {
singular: msg("Group", { id: "entity.group.singular" }),
plural: msg("Groups", { id: "entity.group.plural" }),
};
@property({ type: String })
set groupId(id: string) {
new CoreApi(DEFAULT_CONFIG)
@@ -145,12 +153,16 @@ export class GroupViewPage extends AKElement {
</div>
<div class="pf-c-card__footer">
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="header">${msg("Update Group")}</span>
<span slot="submit">
${ActionTenseRecord.apply.present()}
</span>
<span slot="header">
${formatEditMessage(this.entityLabel)}
</span>
<ak-group-form slot="form" .instancePk=${this.group.pk}>
</ak-group-form>
<button slot="trigger" class="pf-m-primary pf-c-button">
${msg("Edit")}
${formatEditMessage(this.entityLabel)}
</button>
</ak-forms-modal>
</div>

View File

@@ -2,6 +2,7 @@ import "#components/ak-status-label";
import "#elements/buttons/SpinnerButton/index";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EntityLabel } from "#common/i18n/nouns";
import { PaginatedResponse, TableColumn, Timestamp } from "#elements/table/Table";
import { TableModal } from "#elements/table/TableModal";
@@ -22,8 +23,17 @@ type UserListRequestFilter = Partial<Pick<CoreUsersListRequest, "isActive">>;
@customElement("ak-group-member-select-table")
export class MemberSelectTable extends TableModal<User> {
public override searchPlaceholder = msg("Search for users by username or display name...");
public override searchLabel = msg("Search Users");
protected override entityLabel: EntityLabel = {
singular: msg("User", { id: "entity.user.singular" }),
plural: msg("Users", { id: "entity.user.plural" }),
};
protected override get searchPlaceholder() {
return msg("Search for users by username or display name...", {
id: "search.placeholder.user-select-modal",
});
}
public override label = msg("Select Users");
static styles = [
...super.styles,
@@ -72,9 +82,9 @@ export class MemberSelectTable extends TableModal<User> {
}
protected columns: TableColumn[] = [
[msg("Name"), "username"],
[msg("Active"), "is_active"],
[msg("Last login"), "last_login"],
[msg("Name", { id: "column.name" }), "username"],
[msg("Active", { id: "column.active" }), "is_active"],
[msg("Last login", { id: "column.last-login" }), "last_login"],
];
renderToolbarAfter() {

View File

@@ -8,6 +8,7 @@ import "#elements/forms/ModalForm";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EntityLabel } from "#common/i18n/nouns";
import { Form } from "#elements/forms/Form";
import { PaginatedResponse, Table, TableColumn } from "#elements/table/Table";
@@ -28,9 +29,9 @@ export class RelatedGroupAdd extends Form<{ groups: string[] }> {
@state()
groupsToAdd: Group[] = [];
getSuccessMessage(): string {
return msg("Successfully added user to group(s).");
}
protected override readonly actionName = "add";
protected override entityLabel = msg("User To Group", { id: "entity.user-to-group.singular" });
async send(data: { groups: string[] }): Promise<unknown> {
await Promise.all(
@@ -90,6 +91,11 @@ export class RelatedGroupList extends Table<Group> {
clearOnRefresh = true;
protected override searchEnabled = true;
protected override entityLabel: EntityLabel = {
singular: msg("Group", { id: "entity.group.singular" }),
plural: msg("Groups", { id: "entity.group.plural" }),
};
@property()
order = "name";
@@ -105,10 +111,14 @@ export class RelatedGroupList extends Table<Group> {
}
protected columns: TableColumn[] = [
[msg("Name"), "name"],
[msg("Parent"), "parent"],
[msg("Superuser privileges?")],
[msg("Actions"), null, msg("Row Actions")],
[msg("Name", { id: "column.name" }), "name"],
[msg("Parent", { id: "column.parent" }), "parent"],
[msg("Superuser privileges?", { id: "column.superuser-privileges-question-mark" })],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
renderToolbarSelected(): TemplateResult {
@@ -143,8 +153,8 @@ export class RelatedGroupList extends Table<Group> {
html`${item.parentName || msg("-")}`,
html`<ak-status-label type="neutral" ?good=${item.isSuperuser}></ak-status-label>`,
html` <ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="header">${msg("Update Group")}</span>
<span slot="submit">${this.updateEntityLabel}</span>
<span slot="header">${this.editEntityLabel}</span>
<ak-group-form slot="form" .instancePk=${item.pk}> </ak-group-form>
<button slot="trigger" class="pf-c-button pf-m-plain">
<pf-tooltip position="top" content=${msg("Edit")}>
@@ -169,8 +179,8 @@ export class RelatedGroupList extends Table<Group> {
</ak-forms-modal>`
: nothing}
<ak-forms-modal>
<span slot="submit">${msg("Create")}</span>
<span slot="header">${msg("Create Group")}</span>
<span slot="submit">${this.createEntityLabel}</span>
<span slot="header">${this.newEntityActionLabel}</span>
<ak-group-form slot="form"> </ak-group-form>
<button slot="trigger" class="pf-c-button pf-m-secondary">
${msg("Add new group")}

View File

@@ -15,6 +15,7 @@ import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { DEFAULT_CONFIG } from "#common/api/config";
import { PFSize } from "#common/enums";
import { parseAPIResponseError, pluckErrorDetail } from "#common/errors/network";
import { EntityLabel } from "#common/i18n/nouns";
import { MessageLevel } from "#common/messages";
import { me } from "#common/users";
@@ -48,9 +49,9 @@ export class RelatedUserAdd extends Form<{ users: number[] }> {
@state()
usersToAdd: User[] = [];
getSuccessMessage(): string {
return msg("Successfully added user(s).");
}
protected override readonly actionName = "add";
protected override entityLabel = msg("Users", { id: "entity.user.plural" });
async send(data: { users: number[] }): Promise<{ users: number[] }> {
await Promise.all(
@@ -123,10 +124,19 @@ export class RelatedUserAdd extends Form<{ users: number[] }> {
@customElement("ak-user-related-list")
export class RelatedUserList extends WithBrandConfig(WithCapabilitiesConfig(Table<User>)) {
public override searchPlaceholder = msg("Search for users by username or display name...");
public override searchLabel = msg("Group User Search");
protected override get searchPlaceholder() {
return msg("Search for users by username or display name...", {
id: "search.placeholder.user-related-list",
});
}
public override label = msg("Group Users");
public override entityLabel: EntityLabel = {
singular: msg("User", { id: "entity.user.singular" }),
plural: msg("Users", { id: "entity.user.plural" }),
};
expandable = true;
checkbox = true;
clearOnRefresh = true;
@@ -165,10 +175,14 @@ export class RelatedUserList extends WithBrandConfig(WithCapabilitiesConfig(Tabl
}
protected columns: TableColumn[] = [
[msg("Name"), "username"],
[msg("Active"), "is_active"],
[msg("Last login"), "last_login"],
[msg("Actions"), null, msg("Row Actions")],
[msg("Name", { id: "column.name" }), "username"],
[msg("Active", { id: "column.active" }), "is_active"],
[msg("Last login", { id: "column.last-login" }), "last_login"],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
renderToolbarSelected(): TemplateResult {
@@ -216,8 +230,8 @@ export class RelatedUserList extends WithBrandConfig(WithCapabilitiesConfig(Tabl
html`<div>
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="header">${msg("Update User")}</span>
<span slot="submit">${this.updateEntityLabel}</span>
<span slot="header">${this.editEntityLabel}</span>
<ak-user-form slot="form" .instancePk=${item.pk}> </ak-user-form>
<button slot="trigger" class="pf-c-button pf-m-plain">
<pf-tooltip position="top" content=${msg("Edit")}>
@@ -343,7 +357,7 @@ export class RelatedUserList extends WithBrandConfig(WithCapabilitiesConfig(Tabl
</ak-action-button>
${item.email
? html`<ak-forms-modal .closeAfterSuccessfulSubmit=${false}>
<span slot="submit"> ${msg("Send link")} </span>
<span slot="submit">${msg("Send link")}</span>
<span slot="header">
${msg("Send recovery link to user")}
</span>
@@ -417,8 +431,8 @@ export class RelatedUserList extends WithBrandConfig(WithCapabilitiesConfig(Tabl
>
<li role="presentation">
<ak-forms-modal>
<span slot="submit">${msg("Create User")}</span>
<span slot="header">${msg("New User")}</span>
<span slot="submit">${this.createEntityLabel}</span>
<span slot="header">${this.newEntityActionLabel}</span>
${this.targetGroup
? html`
<div class="pf-c-banner pf-m-info" slot="above-form">
@@ -430,7 +444,7 @@ export class RelatedUserList extends WithBrandConfig(WithCapabilitiesConfig(Tabl
: nothing}
<ak-user-form .group=${this.targetGroup} slot="form"> </ak-user-form>
<a role="menuitem" slot="trigger" class="pf-c-dropdown__menu-item">
${msg("New user...")}
${this.newEntityActionLabel}
</a>
</ak-forms-modal>
</li>
@@ -453,7 +467,7 @@ export class RelatedUserList extends WithBrandConfig(WithCapabilitiesConfig(Tabl
<ak-user-service-account-form .group=${this.targetGroup} slot="form">
</ak-user-service-account-form>
<a role="menuitem" slot="trigger" class="pf-c-dropdown__menu-item">
${msg("New service account...")}
${msg("New Service Account")}
</a>
</ak-forms-modal>
</li>

View File

@@ -9,7 +9,7 @@ import { docLink } from "#common/global";
import { groupBy } from "#common/utils";
import { DataProvider, DualSelectPair } from "#elements/ak-dual-select/types";
import { CodeMirrorMode } from "#elements/CodeMirror";
import { CodeMirrorHelperText, CodeMirrorMode } from "#elements/CodeMirror";
import { ModelForm } from "#elements/forms/ModelForm";
import { PaginatedResponse } from "#elements/table/Table";
@@ -120,11 +120,7 @@ export class OutpostForm extends ModelForm<Outpost, string> {
this.providers = providerProvider(this.type);
}
getSuccessMessage(): string {
return this.instance
? msg("Successfully updated outpost.")
: msg("Successfully created outpost.");
}
protected override entityLabel = msg("Outpost", { id: "entity.outpost.singular" });
async send(data: Outpost): Promise<Outpost> {
if (this.instance) {
@@ -146,7 +142,11 @@ export class OutpostForm extends ModelForm<Outpost, string> {
[OutpostTypeEnum.Rac, msg("RAC")],
];
return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">
return html` <ak-form-element-horizontal
label=${msg("Outpost Name", { id: "label.outpost-name" })}
required
name="name"
>
<input
type="text"
value="${ifDefined(this.instance?.name)}"
@@ -243,9 +243,7 @@ export class OutpostForm extends ModelForm<Outpost, string> {
this.instance ? this.instance.config : this.defaultConfig?.config,
)}"
></ak-codemirror>
<p class="pf-c-form__helper-text">
${msg("Set custom attributes using YAML or JSON.")}
</p>
${CodeMirrorHelperText()}
<p class="pf-c-form__helper-text">
${msg("See more here:")}&nbsp;
<a

View File

@@ -54,9 +54,15 @@ export function TypeToLabel(type?: OutpostTypeEnum): string {
export class OutpostListPage extends TablePage<Outpost> {
expandable = true;
public pageTitle = msg("Outposts");
protected override entityLabel = {
singular: msg("Outpost", { id: "entity.outpost.singular" }),
plural: msg("Outposts", { id: "entity.outpost.plural" }),
};
public pageDescription = msg(
"Outposts are deployments of authentik components to support different environments and protocols, like reverse proxies.",
{
id: "page.description.outpost-list",
},
);
public pageIcon = "pf-icon pf-icon-zone";
@@ -84,12 +90,16 @@ export class OutpostListPage extends TablePage<Outpost> {
health: { [key: string]: OutpostHealth[] } = {};
protected columns: TableColumn[] = [
[msg("Name"), "name"],
[msg("Type"), "type"],
[msg("Providers")],
[msg("Integration"), "service_connection__name"],
[msg("Health and Version")],
[msg("Actions"), null, msg("Row Actions")],
[msg("Name", { id: "column.name" }), "name"],
[msg("Type", { id: "column.type" }), "type"],
[msg("Providers", { id: "column.providers" })],
[msg("Integration", { id: "column.integration" }), "service_connection__name"],
[msg("Health and Version", { id: "column.health-and-version" })],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
static styles: CSSResult[] = [...super.styles, PFDescriptionList];
@@ -126,7 +136,7 @@ export class OutpostListPage extends TablePage<Outpost> {
></ak-outpost-health-simple>`,
html`<div>
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="submit">${this.updateEntityLabel}</span>
<span slot="header">${msg("Update Outpost")}</span>
<ak-outpost-form
slot="form"
@@ -233,10 +243,12 @@ export class OutpostListPage extends TablePage<Outpost> {
renderObjectCreate(): TemplateResult {
return html`
<ak-forms-modal>
<span slot="submit">${msg("Create")}</span>
<span slot="header">${msg("Create Outpost")}</span>
<span slot="submit">${this.createEntityLabel}</span>
<span slot="header">${this.newEntityActionLabel}</span>
<ak-outpost-form slot="form"> </ak-outpost-form>
<button slot="trigger" class="pf-c-button pf-m-primary">${msg("Create")}</button>
<button slot="trigger" class="pf-c-button pf-m-primary">
${this.newEntityActionLabel}
</button>
</ak-forms-modal>
`;
}

View File

@@ -21,11 +21,7 @@ export class ServiceConnectionDockerForm extends ModelForm<DockerServiceConnecti
});
}
getSuccessMessage(): string {
return this.instance
? msg("Successfully updated integration.")
: msg("Successfully created integration.");
}
protected override entityLabel = msg("Integration", { id: "entity.integration.singular" });
async send(data: DockerServiceConnection): Promise<DockerServiceConnection> {
if (this.instance) {
@@ -40,7 +36,13 @@ export class ServiceConnectionDockerForm extends ModelForm<DockerServiceConnecti
}
renderForm(): TemplateResult {
return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">
return html` <ak-form-element-horizontal
label=${msg("Service Connection Docker Name", {
id: "label.service-connection-docker-name",
})}
required
name="name"
>
<input
type="text"
value="${ifDefined(this.instance?.name)}"

View File

@@ -3,7 +3,7 @@ import "#elements/forms/HorizontalFormElement";
import { DEFAULT_CONFIG } from "#common/api/config";
import { CodeMirrorMode } from "#elements/CodeMirror";
import { CodeMirrorHelperText, CodeMirrorMode } from "#elements/CodeMirror";
import { ModelForm } from "#elements/forms/ModelForm";
import { KubernetesServiceConnection, OutpostsApi } from "@goauthentik/api";
@@ -26,11 +26,7 @@ export class ServiceConnectionKubernetesForm extends ModelForm<
});
}
getSuccessMessage(): string {
return this.instance
? msg("Successfully updated integration.")
: msg("Successfully created integration.");
}
protected override entityLabel = msg("Integration", { id: "entity.integration.singular" });
async send(data: KubernetesServiceConnection): Promise<KubernetesServiceConnection> {
if (this.instance) {
@@ -45,7 +41,13 @@ export class ServiceConnectionKubernetesForm extends ModelForm<
}
renderForm(): TemplateResult {
return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">
return html` <ak-form-element-horizontal
label=${msg("Service Connection Kubernetes Name", {
id: "label.service-connection-kubernetes-name",
})}
required
name="name"
>
<input
type="text"
value="${ifDefined(this.instance?.name)}"
@@ -79,9 +81,7 @@ export class ServiceConnectionKubernetesForm extends ModelForm<
value="${YAML.stringify(this.instance?.kubeconfig ?? {})}"
>
</ak-codemirror>
<p class="pf-c-form__helper-text">
${msg("Set custom attributes using YAML or JSON.")}
</p>
${CodeMirrorHelperText()}
</ak-form-element-horizontal>
<ak-form-element-horizontal name="verifySsl">
<label class="pf-c-switch">

View File

@@ -28,9 +28,15 @@ import { ifDefined } from "lit/directives/if-defined.js";
@customElement("ak-outpost-service-connection-list")
export class OutpostServiceConnectionListPage extends TablePage<ServiceConnection> {
public pageTitle = msg("Outpost integrations");
protected override entityLabel = {
singular: msg("Outpost Integration", { id: "entity.outpost-integration.singular" }),
plural: msg("Outpost Integrations", { id: "entity.outpost-integration.plural" }),
};
public pageDescription = msg(
"Outpost integrations define how authentik connects to external platforms to manage and deploy Outposts.",
{
id: "page.description.outpost-service-connection-list",
},
);
public pageIcon = "pf-icon pf-icon-integration";
@@ -62,11 +68,15 @@ export class OutpostServiceConnectionListPage extends TablePage<ServiceConnectio
state: { [key: string]: ServiceConnectionState } = {};
protected columns: TableColumn[] = [
[msg("Name"), "name"],
[msg("Type")],
[msg("Local"), "local"],
[msg("State")],
[msg("Actions"), null, msg("Row Actions")],
[msg("Name", { id: "column.name" }), "name"],
[msg("Type", { id: "column.type" })],
[msg("Local", { id: "column.local" }), "local"],
[msg("State", { id: "column.state" })],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
@property()
@@ -83,7 +93,7 @@ export class OutpostServiceConnectionListPage extends TablePage<ServiceConnectio
: html`<ak-label color=${PFColor.Red}>${msg("Unhealthy")}</ak-label>`}`,
html`
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="submit">${this.updateEntityLabel}</span>
<span slot="header">${msg(str`Update ${item.verboseName}`)}</span>
<ak-proxy-form
slot="form"

View File

@@ -6,6 +6,7 @@ import "#elements/wizard/TypeCreateWizardPage";
import "#elements/wizard/Wizard";
import { DEFAULT_CONFIG } from "#common/api/config";
import { formatNewMessage } from "#common/i18n/actions";
import { AKElement } from "#elements/Base";
import type { Wizard } from "#elements/wizard/Wizard";
@@ -25,7 +26,7 @@ export class ServiceConnectionWizard extends AKElement {
static styles: CSSResult[] = [PFBase, PFButton];
@property()
createText = msg("Create");
createText = formatNewMessage(msg("Service Connection"));
@property({ attribute: false })
connectionTypes: TypeCreate[] = [];

View File

@@ -3,9 +3,5 @@ import { ModelForm } from "#elements/forms/ModelForm";
import { msg } from "@lit/localize";
export abstract class BasePolicyForm<T> extends ModelForm<T, string> {
getSuccessMessage(): string {
return this.instance
? msg("Successfully updated policy.")
: msg("Successfully created policy.");
}
protected override entityLabel = msg("Policy", { id: "entity.policy.singular" });
}

View File

@@ -11,6 +11,9 @@ import "#elements/forms/ProxyForm";
import { DEFAULT_CONFIG } from "#common/api/config";
import { PFSize } from "#common/enums";
import { formatEditMessage } from "#common/i18n/actions";
import { EntityLabel } from "#common/i18n/nouns";
import { ActionTenseRecord } from "#common/i18n/verbs";
import { PaginatedResponse, Table, TableColumn } from "#elements/table/Table";
import { SlottedTemplateResult } from "#elements/types";
@@ -55,6 +58,11 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
order = "order";
protected entityLabel: EntityLabel = {
singular: msg("Policy Binding", { id: "entity.policy-binding.singular" }),
plural: msg("Policy Bindings", { id: "entity.policy-binding.plural" }),
};
static get styles(): CSSResult[] {
return super.styles.concat(PFSpacing);
}
@@ -75,11 +83,15 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
}
protected columns: TableColumn[] = [
[msg("Order"), "order"],
[msg("Order", { id: "column.order" }), "order"],
[this.allowedTypesLabel],
[msg("Enabled"), "enabled"],
[msg("Timeout"), "timeout"],
[msg("Actions"), null, msg("Row Actions")],
[msg("Enabled", { id: "column.enabled" }), "enabled"],
[msg("Timeout", { id: "column.timeout" }), "timeout"],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
getPolicyUserGroupRowLabel(item: PolicyBinding): string {
@@ -107,7 +119,7 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
getObjectEditButton(item: PolicyBinding): SlottedTemplateResult {
if (item.policy) {
return html`<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="submit">${this.updateEntityLabel}</span>
<span slot="header">${msg(str`Update ${item.policyObj?.name}`)}</span>
<ak-proxy-form
slot="form"
@@ -123,20 +135,20 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
</ak-forms-modal>`;
} else if (item.group) {
return html`<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="header">${msg("Update Group")}</span>
<span slot="submit">${ActionTenseRecord.apply.present()}</span>
<span slot="header">${formatEditMessage(msg("Group"))}</span>
<ak-group-form slot="form" .instancePk=${item.groupObj?.pk}> </ak-group-form>
<button slot="trigger" class="pf-c-button pf-m-secondary">
${msg("Edit Group")}
${formatEditMessage(msg("Group"))}
</button>
</ak-forms-modal>`;
} else if (item.user) {
return html`<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="header">${msg("Update User")}</span>
<span slot="submit">${ActionTenseRecord.apply.present()}</span>
<span slot="header">${formatEditMessage(msg("User"))}</span>
<ak-user-form slot="form" .instancePk=${item.userObj?.pk}> </ak-user-form>
<button slot="trigger" class="pf-c-button pf-m-secondary">
${msg("Edit User")}
${formatEditMessage(msg("User"))}
</button>
</ak-forms-modal>`;
}
@@ -182,8 +194,8 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
html`${item.timeout}`,
html` ${this.getObjectEditButton(item)}
<ak-forms-modal size=${PFSize.Medium}>
<span slot="submit">${msg("Update")}</span>
<span slot="header">${msg("Update Binding")}</span>
<span slot="submit">${this.updateEntityLabel}</span>
<span slot="header">${this.editEntityLabel}</span>
<ak-policy-binding-form
slot="form"
.instancePk=${item.pk}
@@ -193,7 +205,7 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
>
</ak-policy-binding-form>
<button slot="trigger" class="pf-c-button pf-m-secondary">
${msg("Edit Binding")}
${this.updateEntityLabel}
</button>
</ak-forms-modal>
<ak-rbac-object-permission-modal
@@ -217,8 +229,8 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
bindingTarget=${ifDefined(this.target)}
></ak-policy-wizard>
<ak-forms-modal size=${PFSize.Medium}>
<span slot="submit">${msg("Create")}</span>
<span slot="header">${msg("Create Binding")}</span>
<span slot="submit">${this.createEntityLabel}</span>
<span slot="header">${this.newEntityActionLabel}</span>
<ak-policy-binding-form
slot="form"
targetPk=${ifDefined(this.target)}
@@ -244,8 +256,8 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
></ak-policy-wizard>`
: nothing}
<ak-forms-modal size=${PFSize.Medium}>
<span slot="submit">${msg("Create")}</span>
<span slot="header">${msg("Create Binding")}</span>
<span slot="submit">${this.createEntityLabel}</span>
<span slot="header">${this.newEntityActionLabel}</span>
<ak-policy-binding-form
slot="form"
targetPk=${ifDefined(this.target)}

View File

@@ -68,12 +68,9 @@ export class PolicyBindingForm extends ModelForm<PolicyBinding, string> {
@state()
defaultOrder = 0;
getSuccessMessage(): string {
if (this.instance?.pk) {
return msg("Successfully updated binding.");
}
return msg("Successfully created binding.");
}
protected override entityLabel = msg("Policy Binding", {
id: "entity.policy.binding.singular",
});
static styles: CSSResult[] = [...super.styles, PFContent];

View File

@@ -31,9 +31,15 @@ import { ifDefined } from "lit/directives/if-defined.js";
@customElement("ak-policy-list")
export class PolicyListPage extends TablePage<Policy> {
protected override searchEnabled = true;
public pageTitle = msg("Policies");
protected override entityLabel = {
singular: msg("Policy", { id: "entity.policy.singular" }),
plural: msg("Policies", { id: "entity.policy.plural" }),
};
public pageDescription = msg(
"Allow users to use Applications based on properties, enforce Password Criteria and selectively apply Stages.",
{
id: "page.description.policy-list",
},
);
public pageIcon = "pf-icon pf-icon-infrastructure";
@@ -49,9 +55,9 @@ export class PolicyListPage extends TablePage<Policy> {
protected columns: TableColumn[] = [
// ---
[msg("Name"), "name"],
[msg("Type")],
[msg("Actions")],
[msg("Name", { id: "column.name" }), "name"],
[msg("Type", { id: "column.type" })],
[msg("Actions", { id: "column.actions" })],
];
row(item: Policy): SlottedTemplateResult[] {
@@ -66,7 +72,7 @@ export class PolicyListPage extends TablePage<Policy> {
</ak-label>`}`,
html`${item.verboseName}`,
html` <ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="submit">${this.updateEntityLabel}</span>
<span slot="header">${msg(str`Update ${item.verboseName}`)}</span>
<ak-proxy-form
slot="form"
@@ -127,8 +133,8 @@ export class PolicyListPage extends TablePage<Policy> {
renderToolbar(): TemplateResult {
return html` ${super.renderToolbar()}
<ak-forms-confirm
successMessage=${msg("Successfully cleared policy cache")}
errorMessage=${msg("Failed to delete policy cache")}
success-message=${msg("Successfully cleared policy cache")}
error-message=${msg("Failed to delete policy cache")}
action=${msg("Clear cache")}
.onConfirm=${() => {
return new PoliciesApi(DEFAULT_CONFIG).policiesAllCacheClearCreate();

View File

@@ -6,7 +6,7 @@ import "#elements/forms/SearchSelect/index";
import { DEFAULT_CONFIG } from "#common/api/config";
import { CodeMirrorMode } from "#elements/CodeMirror";
import { CodeMirrorHelperText, CodeMirrorMode } from "#elements/CodeMirror";
import { Form } from "#elements/forms/Form";
import {
@@ -38,9 +38,11 @@ export class PolicyTestForm extends Form<PolicyTestRequest> {
@property({ attribute: false })
request?: PolicyTestRequest;
getSuccessMessage(): string {
return msg("Successfully sent test-request.");
}
protected override readonly actionName = "send";
protected override entityLabel = msg("Test Request", {
id: "entity.policy.test.request.singular",
});
async send(data: PolicyTestRequest): Promise<PolicyTestResult> {
this.request = data;
@@ -128,9 +130,7 @@ export class PolicyTestForm extends Form<PolicyTestRequest> {
value=${YAML.stringify(this.request?.context ?? {})}
>
</ak-codemirror>
<p class="pf-c-form__helper-text">
${msg("Set custom attributes using YAML or JSON.")}
</p>
${CodeMirrorHelperText()}
</ak-form-element-horizontal>
${this.result ? this.renderResult() : nothing}`;
}

View File

@@ -12,6 +12,7 @@ import "#elements/wizard/TypeCreateWizardPage";
import "#elements/wizard/Wizard";
import { DEFAULT_CONFIG } from "#common/api/config";
import { formatNewMessage } from "#common/i18n/actions";
import { AKElement } from "#elements/Base";
import { FormWizardPage } from "#elements/wizard/FormWizardPage";
@@ -34,7 +35,7 @@ export class PolicyWizard extends AKElement {
static styles: CSSResult[] = [PFBase, PFButton];
@property()
createText = msg("Create");
createText = formatNewMessage(msg("Policy"));
@property({ type: Boolean })
showBindingPage = false;

View File

@@ -38,7 +38,11 @@ export class DummyPolicyForm extends BasePolicyForm<DummyPolicy> {
"A policy used for testing. Always returns the same result as specified below after waiting a random duration.",
)}
</span>
<ak-form-element-horizontal label=${msg("Name")} required name="name">
<ak-form-element-horizontal
label=${msg("Dummy Policy Name", { id: "label.dummy-policy-name" })}
required
name="name"
>
<input
type="text"
value="${ifDefined(this.instance?.name || "")}"

View File

@@ -50,7 +50,11 @@ export class EventMatcherPolicyForm extends BasePolicyForm<EventMatcherPolicy> {
"Matches an event against a set of criteria. If any of the configured values match, the policy passes.",
)}
</span>
<ak-form-element-horizontal label=${msg("Name")} required name="name">
<ak-form-element-horizontal
label=${msg("Event Matcher Policy Name", { id: "label.event-matcher-policy-name" })}
required
name="name"
>
<input
type="text"
value="${ifDefined(this.instance?.name || "")}"

View File

@@ -38,7 +38,11 @@ export class PasswordExpiryPolicyForm extends BasePolicyForm<PasswordExpiryPolic
"Checks if the request's user's password has been changed in the last x days, and denys based on settings.",
)}
</span>
<ak-form-element-horizontal label=${msg("Name")} required name="name">
<ak-form-element-horizontal
label=${msg("Expiry Policy Name", { id: "label.expiry-policy-name" })}
required
name="name"
>
<input
type="text"
value="${ifDefined(this.instance?.name || "")}"

View File

@@ -42,7 +42,11 @@ export class ExpressionPolicyForm extends BasePolicyForm<ExpressionPolicy> {
"Executes the python snippet to determine whether to allow or deny a request.",
)}
</span>
<ak-form-element-horizontal label=${msg("Name")} required name="name">
<ak-form-element-horizontal
label=${msg("Expression Policy Name", { id: "label.expression-policy-name" })}
required
name="name"
>
<input
type="text"
value="${ifDefined(this.instance?.name || "")}"

View File

@@ -53,7 +53,11 @@ export class GeoIPPolicyForm extends BasePolicyForm<GeoIPPolicy> {
"Ensure the user satisfies requirements of geography or network topology, based on IP address. If any of the configured values match, the policy passes.",
)}
</span>
<ak-form-element-horizontal label=${msg("Name")} required name="name">
<ak-form-element-horizontal
label=${msg("GeoIP Policy Name", { id: "label.geoip-policy-name" })}
required
name="name"
>
<input
type="text"
value="${this.instance?.name ?? ""}"

View File

@@ -220,7 +220,11 @@ export class PasswordPolicyForm extends BasePolicyForm<PasswordPolicy> {
"Checks the value from the policy request against several rules, mostly used to ensure password strength.",
)}
</span>
<ak-form-element-horizontal label=${msg("Name")} required name="name">
<ak-form-element-horizontal
label=${msg("Password Policy Name", { id: "label.password-policy-name" })}
required
name="name"
>
<input
type="text"
value="${ifDefined(this.instance?.name || "")}"

View File

@@ -25,9 +25,15 @@ import { customElement, property } from "lit/decorators.js";
@customElement("ak-policy-reputation-list")
export class ReputationListPage extends TablePage<Reputation> {
protected override searchEnabled = true;
public pageTitle = msg("Reputation scores");
protected override entityLabel = {
singular: msg("Reputation Score", { id: "entity.reputation-score.singular" }),
plural: msg("Reputation Scores", { id: "entity.reputation-score.plural" }),
};
public pageDescription = msg(
"Reputation for IP and user identifiers. Scores are decreased for each failed login and increased for each successful login.",
{
id: "page.description.policy-reputation-list",
},
);
public pageIcon = "fa fa-ban";
@@ -48,11 +54,15 @@ export class ReputationListPage extends TablePage<Reputation> {
}
protected columns: TableColumn[] = [
[msg("Identifier"), "identifier"],
[msg("IP"), "ip"],
[msg("Score"), "score"],
[msg("Updated"), "updated"],
[msg("Actions"), null, msg("Row Actions")],
[msg("Identifier", { id: "column.identifier" }), "identifier"],
[msg("IP", { id: "column.ip" }), "ip"],
[msg("Score", { id: "column.score" }), "score"],
[msg("Updated", { id: "column.updated" }), "updated"],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
renderToolbarSelected(): TemplateResult {

View File

@@ -48,7 +48,11 @@ username they are attempting to login as, by one.`,
doesn't pass when either or both of the selected options are equal or above the threshold.`,
)}
</span>
<ak-form-element-horizontal label=${msg("Name")} required name="name">
<ak-form-element-horizontal
label=${msg("Reputation Policy Name", { id: "label.reputation-policy-name" })}
required
name="name"
>
<input
type="text"
value="${ifDefined(this.instance?.name || "")}"

View File

@@ -38,7 +38,13 @@ export class UniquePasswordPolicyForm extends BasePolicyForm<UniquePasswordPolic
"Ensure that the user's new password is different from their previous passwords. The number of past passwords to check is configurable.",
)}
</span>
<ak-form-element-horizontal label=${msg("Name")} required name="name">
<ak-form-element-horizontal
label=${msg("Unique Password Policy Name", {
id: "label.unique-password-policy-name",
})}
required
name="name"
>
<input
type="text"
value="${ifDefined(this.instance?.name || "")}"

View File

@@ -19,18 +19,18 @@ export abstract class BasePropertyMappingForm<T extends PropertyMapping> extends
> {
protected docLink: string | URL = "/add-secure-apps/providers/property-mappings/expression";
getSuccessMessage(): string {
return this.instance
? msg("Successfully updated mapping.")
: msg("Successfully created mapping.");
}
protected override entityLabel = msg("Mapping", { id: "entity.mapping.singular" });
renderExtraFields(): SlottedTemplateResult {
return nothing;
}
renderForm(): TemplateResult {
return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">
return html` <ak-form-element-horizontal
label=${msg("Property Mapping Name", { id: "label.property-mapping-name" })}
required
name="name"
>
<input
type="text"
value="${ifDefined(this.instance?.name)}"

View File

@@ -22,6 +22,7 @@ import "#elements/forms/ProxyForm";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EntityLabel } from "#common/i18n/nouns";
import { getURLParam, updateURLParams } from "#elements/router/RouteMatch";
import { PaginatedResponse, TableColumn } from "#elements/table/Table";
@@ -38,13 +39,17 @@ import { ifDefined } from "lit/directives/if-defined.js";
@customElement("ak-property-mapping-list")
export class PropertyMappingListPage extends TablePage<PropertyMapping> {
protected override searchEnabled = true;
public pageTitle = msg("Property Mappings");
public pageDescription = msg("Control how authentik exposes and interprets information.");
public pageIcon = "pf-icon pf-icon-blueprint";
checkbox = true;
clearOnRefresh = true;
protected override entityLabel: EntityLabel = {
singular: msg("Property Mapping", { id: "entity.property-mapping.singular" }),
plural: msg("Property Mappings", { id: "entity.property-mapping.plural" }),
};
@property()
order = "name";
@@ -59,9 +64,13 @@ export class PropertyMappingListPage extends TablePage<PropertyMapping> {
}
protected columns: TableColumn[] = [
[msg("Name"), "name"],
[msg("Type"), "type"],
[msg("Actions"), null, msg("Row Actions")],
[msg("Name", { id: "column.name" }), "name"],
[msg("Type", { id: "column.type" }), "type"],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
renderToolbarSelected(): TemplateResult {
@@ -91,7 +100,7 @@ export class PropertyMappingListPage extends TablePage<PropertyMapping> {
html`${item.name}`,
html`${item.verboseName}`,
html` <ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="submit">${this.updateEntityLabel}</span>
<span slot="header">${msg(str`Update ${item.verboseName}`)}</span>
<ak-proxy-form
slot="form"

View File

@@ -57,7 +57,11 @@ export class PropertyMappingProviderRACForm extends BasePropertyMappingForm<RACP
renderForm(): TemplateResult {
return html`
<ak-form-element-horizontal label=${msg("Name")} required name="name">
<ak-form-element-horizontal
label=${msg("RAC Property Mapping Name", { id: "label.rac-property-mapping-name" })}
required
name="name"
>
<input
type="text"
value="${ifDefined(this.instance?.name)}"

View File

@@ -38,9 +38,11 @@ export class PolicyTestForm extends Form<PropertyMappingTestRequest> {
@property({ attribute: false })
request?: PropertyMappingTestRequest;
getSuccessMessage(): string {
return msg("Successfully sent test-request.");
}
protected override readonly actionName = "send";
protected override entityLabel = msg("Test Request", {
id: "entity.policy.test.request.singular",
});
async send(data: PropertyMappingTestRequest): Promise<PropertyMappingTestResult> {
this.request = data;

View File

@@ -20,6 +20,7 @@ import "#elements/wizard/TypeCreateWizardPage";
import "#elements/wizard/Wizard";
import { DEFAULT_CONFIG } from "#common/api/config";
import { formatNewMessage } from "#common/i18n/actions";
import { AKElement } from "#elements/Base";
import type { Wizard } from "#elements/wizard/Wizard";
@@ -80,7 +81,9 @@ export class PropertyMappingWizard extends AKElement {
</ak-wizard-page-form>
`;
})}
<button slot="trigger" class="pf-c-button pf-m-primary">${msg("Create")}</button>
<button slot="trigger" class="pf-c-button pf-m-primary">
${formatNewMessage(msg("Property Mapping"))}
</button>
</ak-wizard>
`;
}

View File

@@ -7,11 +7,7 @@ import { APIMessage } from "#elements/messages/Message";
import { msg } from "@lit/localize";
export abstract class BaseProviderForm<T> extends ModelForm<T, number> {
public override getSuccessMessage(): string {
return this.instance
? msg("Successfully updated provider.")
: msg("Successfully created provider.");
}
protected override entityLabel = msg("Provider", { id: "entity.provider.singular" });
protected override formatAPIErrorMessage(error: APIError): APIMessage {
return {

View File

@@ -17,6 +17,7 @@ import "#elements/forms/ProxyForm";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { DEFAULT_CONFIG } from "#common/api/config";
import { ActionTenseRecord } from "#common/i18n/verbs";
import { PaginatedResponse, TableColumn } from "#elements/table/Table";
import { TablePage } from "#elements/table/TablePage";
@@ -32,10 +33,22 @@ import { customElement, property } from "lit/decorators.js";
export class ProviderListPage extends TablePage<Provider> {
protected override searchEnabled = true;
override pageTitle = msg("Providers");
protected override entityLabel = {
singular: msg("Provider", { id: "entity.provider.singular" }),
plural: msg("Providers", { id: "entity.provider.plural" }),
};
protected override get searchPlaceholder() {
return msg("Search for a provider by name or application...", {
id: "search.placeholder.provider-list",
});
}
public pageDescription = msg(
"Provide support for protocols like SAML and OAuth to assigned applications.",
{
id: "page.description.provider-list",
},
);
public pageIcon = "pf-icon pf-icon-integration";
@@ -46,9 +59,6 @@ export class ProviderListPage extends TablePage<Provider> {
@property()
public order = "name";
public searchLabel = msg("Provider Search");
public searchPlaceholder = msg("Search for providers…");
override async apiEndpoint(): Promise<PaginatedResponse<Provider>> {
return new ProvidersApi(DEFAULT_CONFIG).providersAllList(
await this.defaultEndpointConfig(),
@@ -56,10 +66,14 @@ export class ProviderListPage extends TablePage<Provider> {
}
protected override columns: TableColumn[] = [
[msg("Name"), "name"],
[msg("Application")],
[msg("Type")],
[msg("Actions"), null, msg("Row Actions")],
[msg("Name", { id: "column.name" }), "name"],
[msg("Application", { id: "column.application" })],
[msg("Type", { id: "column.type" })],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
override renderToolbarSelected(): TemplateResult {
@@ -113,7 +127,7 @@ export class ProviderListPage extends TablePage<Provider> {
html`${item.verboseName}`,
html`<div>
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="submit">${ActionTenseRecord.apply.present()}</span>
<span slot="header">${msg(str`Update ${item.verboseName}`)}</span>
<ak-proxy-form
slot="form"

View File

@@ -12,6 +12,7 @@ import "#elements/EmptyState";
import "#elements/buttons/SpinnerButton/ak-spinner-button";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EntityLabel } from "#common/i18n/nouns";
import { AKElement } from "#elements/Base";
@@ -21,6 +22,7 @@ import { Provider, ProvidersApi } from "@goauthentik/api";
import { spread } from "@open-wc/lit-helpers";
import { msg } from "@lit/localize";
import { css, CSSResult, html, PropertyValues, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators.js";
@@ -28,6 +30,11 @@ import PFPage from "@patternfly/patternfly/components/Page/page.css";
@customElement("ak-provider-view")
export class ProviderViewPage extends AKElement {
protected entityLabel: EntityLabel = {
singular: msg("Provider", { id: "entity.provider.singular" }),
plural: msg("Providers", { id: "entity.provider.plural" }),
};
@property({ type: Number })
set providerID(value: number) {
new ProvidersApi(DEFAULT_CONFIG)

View File

@@ -10,6 +10,7 @@ import "#elements/wizard/TypeCreateWizardPage";
import "#elements/wizard/Wizard";
import { DEFAULT_CONFIG } from "#common/api/config";
import { formatNewMessage } from "#common/i18n/actions";
import { AKElement } from "#elements/Base";
import { TypeCreateWizardPageLayouts } from "#elements/wizard/TypeCreateWizardPage";
@@ -30,7 +31,7 @@ export class ProviderWizard extends AKElement {
static styles: CSSResult[] = [PFBase, PFButton];
@property()
createText = msg("Create");
createText = formatNewMessage(msg("Provider"));
@property({ attribute: false })
providerTypes: TypeCreate[] = [];
@@ -79,14 +80,13 @@ export class ProviderWizard extends AKElement {
`;
})}
<button
aria-label=${msg("New Provider")}
aria-description="${msg("Open the wizard to create a new provider.")}"
type="button"
part="button trigger"
slot="trigger"
class="pf-c-button pf-m-primary"
>
${msg("Create")}
${formatNewMessage(msg("Provider"))}
</button>
</ak-wizard>
`;

View File

@@ -2,6 +2,9 @@ import "#admin/applications/ApplicationForm";
import "#elements/Spinner";
import "#elements/forms/ModalForm";
import { formatCreateMessage, formatNewMessage } from "#common/i18n/actions";
import { EntityLabel } from "#common/i18n/nouns";
import { AKElement } from "#elements/Base";
import { Provider } from "@goauthentik/api";
@@ -17,6 +20,11 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
export class RelatedApplicationButton extends AKElement {
static styles: CSSResult[] = [PFBase, PFButton];
protected entityLabel: EntityLabel = {
singular: msg("Application", { id: "entity.application.singular" }),
plural: msg("Applications", { id: "entity.application.plural" }),
};
@property({ attribute: false })
provider?: Provider;
@@ -37,10 +45,13 @@ export class RelatedApplicationButton extends AKElement {
</a>`;
}
return html`<ak-forms-modal>
<span slot="submit">${msg("Create")}</span>
<span slot="header">${msg("Create Application")}</span>
<span slot="submit">${formatCreateMessage(this.entityLabel)}</span>
<span slot="header">${formatNewMessage(this.entityLabel)}</span>
<ak-application-form slot="form" .provider=${this.provider?.pk}> </ak-application-form>
<button slot="trigger" class="pf-c-button pf-m-primary">${msg("Create")}</button>
<button slot="trigger" class="pf-c-button pf-m-primary">
${formatNewMessage(this.entityLabel)}
</button>
</ak-forms-modal>`;
}
}

View File

@@ -3,6 +3,7 @@ import "#elements/forms/ModalForm";
import "#elements/sync/SyncObjectForm";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EntityLabel } from "#common/i18n/nouns";
import { PaginatedResponse, Table, TableColumn } from "#elements/table/Table";
import { SlottedTemplateResult } from "#elements/types";
@@ -25,6 +26,11 @@ export class GoogleWorkspaceProviderGroupList extends Table<GoogleWorkspaceProvi
expandable = true;
protected override entityLabel: EntityLabel = {
singular: msg("Google Workspace Group", { id: "entity.google-workspace-group.singular" }),
plural: msg("Google Workspace Groups", { id: "entity.google-workspace-group.plural" }),
};
protected override searchEnabled = true;
checkbox = true;
@@ -79,9 +85,8 @@ export class GoogleWorkspaceProviderGroupList extends Table<GoogleWorkspaceProvi
}
protected columns: TableColumn[] = [
// ---
[msg("Name")],
[msg("ID")],
[msg("Name", { id: "column.name" })],
[msg("ID", { id: "column.id" })],
];
row(item: GoogleWorkspaceProviderGroup): SlottedTemplateResult[] {

View File

@@ -3,6 +3,7 @@ import "#elements/forms/ModalForm";
import "#elements/sync/SyncObjectForm";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EntityLabel } from "#common/i18n/nouns";
import { PaginatedResponse, Table, TableColumn } from "#elements/table/Table";
import { SlottedTemplateResult } from "#elements/types";
@@ -23,6 +24,11 @@ export class GoogleWorkspaceProviderUserList extends Table<GoogleWorkspaceProvid
@property({ type: Number })
providerId?: number;
protected override entityLabel: EntityLabel = {
singular: msg("Google Workspace User", { id: "entity.google-workspace-user.singular" }),
plural: msg("Google Workspace Users", { id: "entity.google-workspace-user.plural" }),
};
protected override searchEnabled = true;
expandable = true;
@@ -80,8 +86,8 @@ export class GoogleWorkspaceProviderUserList extends Table<GoogleWorkspaceProvid
protected columns: TableColumn[] = [
// ---
[msg("Username")],
[msg("ID")],
[msg("Username", { id: "column.username" })],
[msg("ID", { id: "column.id" })],
];
row(item: GoogleWorkspaceProviderUser): SlottedTemplateResult[] {

View File

@@ -13,6 +13,9 @@ import "#elements/tasks/TaskList";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EVENT_REFRESH } from "#common/constants";
import { formatEditMessage } from "#common/i18n/actions";
import { EntityLabel } from "#common/i18n/nouns";
import { ActionTenseRecord } from "#common/i18n/verbs";
import { AKElement } from "#elements/Base";
import { SlottedTemplateResult } from "#elements/types";
@@ -42,6 +45,15 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
@customElement("ak-provider-google-workspace-view")
export class GoogleWorkspaceProviderViewPage extends AKElement {
protected entityLabel: EntityLabel = {
singular: msg("Google Workspace Provider", {
id: "entity.google-workspace-provider.singular",
}),
plural: msg("Google Workspace Providers", {
id: "entity.google-workspace-provider.plural",
}),
};
@property({ type: Number })
providerID?: number;
@@ -206,15 +218,15 @@ export class GoogleWorkspaceProviderViewPage extends AKElement {
</div>
<div class="pf-c-card__footer">
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="header">${msg("Update Google Workspace Provider")}</span>
<span slot="submit">${ActionTenseRecord.apply.present()}</span>
<span slot="header">${formatEditMessage(this.entityLabel)}</span>
<ak-provider-google-workspace-form
slot="form"
.instancePk=${this.provider.pk}
>
</ak-provider-google-workspace-form>
<button slot="trigger" class="pf-c-button pf-m-primary">
${msg("Edit")}
${formatEditMessage(this.entityLabel)}
</button>
</ak-forms-modal>
</div>

View File

@@ -9,6 +9,9 @@ import "#elements/buttons/SpinnerButton/index";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EVENT_REFRESH } from "#common/constants";
import { formatEditMessage } from "#common/i18n/actions";
import { EntityLabel } from "#common/i18n/nouns";
import { ActionTenseRecord } from "#common/i18n/verbs";
import { AKElement } from "#elements/Base";
import { WithSession } from "#elements/mixins/session";
@@ -39,6 +42,11 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
@customElement("ak-provider-ldap-view")
export class LDAPProviderViewPage extends WithSession(AKElement) {
protected entityLabel: EntityLabel = {
singular: msg("Ldap Provider", { id: "entity.ldap-provider.singular" }),
plural: msg("Ldap Providers", { id: "entity.ldap-provider.plural" }),
};
@property({ type: Number })
providerID?: number;
@@ -130,14 +138,11 @@ export class LDAPProviderViewPage extends WithSession(AKElement) {
return nothing;
}
return html`
${
this.provider?.outpostSet.length < 1
? html`<div slot="header" class="pf-c-banner pf-m-warning">
${msg("Warning: Provider is not used by any Outpost.")}
</div>`
: nothing
}
return html`${!this.provider.outpostSet.length
? html`<div slot="header" class="pf-c-banner pf-m-warning">
${msg("Warning: Provider is not used by any Outpost.")}
</div>`
: nothing}
<div class="pf-c-page__main-section pf-m-no-padding-mobile pf-l-grid pf-m-gutter">
<div class="pf-c-card pf-l-grid__item pf-m-12-col">
<div class="pf-c-card__body">
@@ -182,24 +187,20 @@ export class LDAPProviderViewPage extends WithSession(AKElement) {
</div>
<div class="pf-c-card__footer">
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="header">${msg("Update LDAP Provider")}</span>
<span slot="submit">${ActionTenseRecord.apply.present()}</span>
<span slot="header">${formatEditMessage(this.entityLabel)}</span>
<ak-provider-ldap-form slot="form" .instancePk=${this.provider.pk}>
</ak-provider-ldap-form>
<button slot="trigger" class="pf-c-button pf-m-primary">
${msg("Edit")}
${formatEditMessage(this.entityLabel)}
</button>
</ak-forms-modal>
</div>
</div>
<div class="pf-c-card pf-l-grid__item pf-m-12-col">
<div class="pf-c-card__title">
${msg("How to connect")}
</div>
<div class="pf-c-card__title">${msg("How to connect")}</div>
<div class="pf-c-card__body">
<p>
${msg("Connect to the LDAP Server on port 389:")}
</p>
<p>${msg("Connect to the LDAP Server on port 389:")}</p>
<ul class="pf-c-list">
<li>${msg("Check the IP of the Kubernetes service, or")}</li>
<li>${msg("The Host IP of the docker host")}</li>
@@ -210,7 +211,7 @@ export class LDAPProviderViewPage extends WithSession(AKElement) {
<span class="pf-c-form__label-text">${msg("Bind DN")}</span>
</label>
<input
class="pf-c-form-control"
class="pf-c-form-control pf-m-monospace"
readonly
type="text"
value=${`cn=${this.currentUser?.username},ou=users,${this.provider?.baseDn?.toLowerCase()}`}
@@ -218,12 +219,12 @@ export class LDAPProviderViewPage extends WithSession(AKElement) {
</div>
<div class="pf-c-form__group">
<label class="pf-c-form__label">
<span class="pf-c-form__label-text">${msg(
"Bind Password",
)}</span>
<span class="pf-c-form__label-text"
>${msg("Bind Password")}</span
>
</label>
<input
class="pf-c-form-control"
class="pf-c-form-control pf-m-monospace"
readonly
type="text"
value=${msg("Your authentik password")}
@@ -234,7 +235,7 @@ export class LDAPProviderViewPage extends WithSession(AKElement) {
<span class="pf-c-form__label-text">${msg("Search base")}</span>
</label>
<input
class="pf-c-form-control"
class="pf-c-form-control pf-m-monospace"
readonly
type="text"
value=${ifDefined(this.provider?.baseDn?.toLowerCase())}
@@ -243,8 +244,7 @@ export class LDAPProviderViewPage extends WithSession(AKElement) {
</form>
</div>
</div>
</div>
</div>`;
</div>`;
}
}

View File

@@ -3,6 +3,7 @@ import "#elements/forms/ModalForm";
import "#elements/sync/SyncObjectForm";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EntityLabel } from "#common/i18n/nouns";
import { PaginatedResponse, Table, TableColumn } from "#elements/table/Table";
import { SlottedTemplateResult } from "#elements/types";
@@ -27,6 +28,11 @@ export class MicrosoftEntraProviderGroupList extends Table<MicrosoftEntraProvide
protected override searchEnabled = true;
protected override entityLabel: EntityLabel = {
singular: msg("Microsoft Entra Group", { id: "entity.microsoft-entra-group.singular" }),
plural: msg("Microsoft Entra Groups", { id: "entity.microsoft-entra-group.plural" }),
};
renderToolbar(): TemplateResult {
return html`<ak-forms-modal cancelText=${msg("Close")} ?closeAfterSuccessfulSubmit=${false}>
<span slot="submit">${msg("Sync")}</span>
@@ -76,9 +82,8 @@ export class MicrosoftEntraProviderGroupList extends Table<MicrosoftEntraProvide
}
protected columns: TableColumn[] = [
// ---
[msg("Name")],
[msg("ID")],
[msg("Name", { id: "column.name" })],
[msg("ID", { id: "column.id" })],
];
row(item: MicrosoftEntraProviderGroup): SlottedTemplateResult[] {

View File

@@ -3,6 +3,7 @@ import "#elements/forms/ModalForm";
import "#elements/sync/SyncObjectForm";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EntityLabel } from "#common/i18n/nouns";
import { PaginatedResponse, Table, TableColumn } from "#elements/table/Table";
import { SlottedTemplateResult } from "#elements/types";
@@ -25,6 +26,11 @@ export class MicrosoftEntraProviderUserList extends Table<MicrosoftEntraProvider
expandable = true;
protected override entityLabel: EntityLabel = {
singular: msg("Microsoft Entra User", { id: "entity.microsoft-entra-user.singular" }),
plural: msg("Microsoft Entra Users", { id: "entity.microsoft-entra-user.plural" }),
};
protected override searchEnabled = true;
checkbox = true;
@@ -80,8 +86,8 @@ export class MicrosoftEntraProviderUserList extends Table<MicrosoftEntraProvider
protected columns: TableColumn[] = [
// ---
[msg("Username")],
[msg("ID")],
[msg("Username", { id: "column.username" })],
[msg("ID", { id: "column.id" })],
];
row(item: MicrosoftEntraProviderUser): SlottedTemplateResult[] {

View File

@@ -13,6 +13,9 @@ import "#elements/tasks/TaskList";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EVENT_REFRESH } from "#common/constants";
import { formatEditMessage } from "#common/i18n/actions";
import { EntityLabel } from "#common/i18n/nouns";
import { ActionTenseRecord } from "#common/i18n/verbs";
import { AKElement } from "#elements/Base";
import { SlottedTemplateResult } from "#elements/types";
@@ -42,6 +45,13 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
@customElement("ak-provider-microsoft-entra-view")
export class MicrosoftEntraProviderViewPage extends AKElement {
protected entityLabel: EntityLabel = {
singular: msg("Microsoft Entra Provider", {
id: "entity.microsoft-entra-provider.singular",
}),
plural: msg("Microsoft Entra Providers", { id: "entity.microsoft-entra-provider.plural" }),
};
@property({ type: Number })
providerID?: number;
@@ -206,15 +216,15 @@ export class MicrosoftEntraProviderViewPage extends AKElement {
</div>
<div class="pf-c-card__footer">
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="header">${msg("Update Microsoft Entra Provider")}</span>
<span slot="submit">${ActionTenseRecord.apply.present()}</span>
<span slot="header">${formatEditMessage(this.entityLabel)}</span>
<ak-provider-microsoft-entra-form
slot="form"
.instancePk=${this.provider.pk}
>
</ak-provider-microsoft-entra-form>
<button slot="trigger" class="pf-c-button pf-m-primary">
${msg("Edit")}
${formatEditMessage(this.entityLabel)}
</button>
</ak-forms-modal>
</div>

View File

@@ -11,6 +11,9 @@ import "#elements/buttons/SpinnerButton/index";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EVENT_REFRESH } from "#common/constants";
import { formatEditMessage } from "#common/i18n/actions";
import { EntityLabel } from "#common/i18n/nouns";
import { ActionTenseRecord } from "#common/i18n/verbs";
import { AKElement } from "#elements/Base";
import { SlottedTemplateResult } from "#elements/types";
@@ -64,6 +67,11 @@ export function TypeToLabel(type?: ClientTypeEnum): string {
@customElement("ak-provider-oauth2-view")
export class OAuth2ProviderViewPage extends AKElement {
protected entityLabel: EntityLabel = {
singular: msg("O Auth2 Provider", { id: "entity.o-auth2-provider.singular" }),
plural: msg("O Auth2 Providers", { id: "entity.o-auth2-provider.plural" }),
};
@property({ type: Number })
set providerID(value: number) {
new ProvidersApi(DEFAULT_CONFIG)
@@ -298,15 +306,15 @@ export class OAuth2ProviderViewPage extends AKElement {
</div>
<div class="pf-c-card__footer">
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="header">${msg("Update OAuth2 Provider")}</span>
<span slot="submit">${ActionTenseRecord.apply.present()}</span>
<span slot="header">${formatEditMessage(this.entityLabel)}</span>
<ak-provider-oauth2-form
slot="form"
.instancePk=${this.provider.pk || 0}
>
</ak-provider-oauth2-form>
<button slot="trigger" class="pf-c-button pf-m-primary">
${msg("Edit")}
${formatEditMessage(this.entityLabel)}
</button>
</ak-forms-modal>
</div>

View File

@@ -11,6 +11,9 @@ import "#elements/buttons/SpinnerButton/index";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EVENT_REFRESH } from "#common/constants";
import { formatEditMessage } from "#common/i18n/actions";
import { EntityLabel } from "#common/i18n/nouns";
import { ActionTenseRecord } from "#common/i18n/verbs";
import type { Replacer } from "#elements/ak-mdx/index";
import { AKElement } from "#elements/Base";
@@ -78,6 +81,11 @@ export function isForward(mode: ProxyMode): boolean {
@customElement("ak-provider-proxy-view")
export class ProxyProviderViewPage extends AKElement {
protected entityLabel: EntityLabel = {
singular: msg("Proxy Provider", { id: "entity.proxy-provider.singular" }),
plural: msg("Proxy Providers", { id: "entity.proxy-provider.plural" }),
};
@property({ type: Number })
providerID?: number;
@@ -381,15 +389,15 @@ export class ProxyProviderViewPage extends AKElement {
</div>
<div class="pf-c-card__footer">
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="header">${msg("Update Proxy Provider")}</span>
<span slot="submit">${ActionTenseRecord.apply.present()}</span>
<span slot="header">${formatEditMessage(this.entityLabel)}</span>
<ak-provider-proxy-form
slot="form"
.instancePk=${this.provider.pk || 0}
>
</ak-provider-proxy-form>
<button slot="trigger" class="pf-c-button pf-m-primary">
${msg("Edit")}
${formatEditMessage(this.entityLabel)}
</button>
</ak-forms-modal>
</div>

View File

@@ -4,6 +4,7 @@ import "#elements/forms/ModalForm";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EntityLabel } from "#common/i18n/nouns";
import { PaginatedResponse, Table, TableColumn } from "#elements/table/Table";
import { SlottedTemplateResult } from "#elements/types";
@@ -23,6 +24,11 @@ export class ConnectionTokenListPage extends Table<ConnectionToken> {
protected override searchEnabled = true;
protected override entityLabel: EntityLabel = {
singular: msg("Connection Token", { id: "entity.connection-token.singular" }),
plural: msg("Connection Tokens", { id: "entity.connection-token.plural" }),
};
@property()
order = "name";

View File

@@ -30,11 +30,7 @@ export class EndpointForm extends ModelForm<Endpoint, string> {
});
}
getSuccessMessage(): string {
return this.instance
? msg("Successfully updated endpoint.")
: msg("Successfully created endpoint.");
}
protected override entityLabel = msg("Endpoint");
async send(data: Endpoint): Promise<Endpoint> {
data.authMode = EndpointAuthModeEnum.Prompt;

View File

@@ -7,6 +7,9 @@ import "#elements/forms/ModalForm";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { DEFAULT_CONFIG } from "#common/api/config";
import { formatCreateMessage, formatEditMessage, formatNewMessage } from "#common/i18n/actions";
import { EntityLabel } from "#common/i18n/nouns";
import { ActionTenseRecord } from "#common/i18n/verbs";
import { PaginatedResponse, Table, TableColumn } from "#elements/table/Table";
import { SlottedTemplateResult } from "#elements/types";
@@ -30,6 +33,11 @@ export class EndpointListPage extends Table<Endpoint> {
checkbox = true;
clearOnRefresh = true;
protected override entityLabel: EntityLabel = {
singular: msg("Endpoint", { id: "entity.endpoint.singular" }),
plural: msg("Endpoints", { id: "entity.endpoint.plural" }),
};
protected override searchEnabled = true;
@property()
@@ -49,9 +57,13 @@ export class EndpointListPage extends Table<Endpoint> {
}
protected columns: TableColumn[] = [
[msg("Name"), "name"],
[msg("Host"), "host"],
[msg("Actions"), null, msg("Row Actions")],
[msg("Name", { id: "column.name" }), "name"],
[msg("Host", { id: "column.host" }), "host"],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
renderToolbarSelected(): TemplateResult {
@@ -88,8 +100,8 @@ export class EndpointListPage extends Table<Endpoint> {
html`${item.host}`,
html`<div>
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="header">${msg("Update Endpoint")}</span>
<span slot="submit">${ActionTenseRecord.apply.present()}</span>
<span slot="header">${formatEditMessage(this.entityLabel)}</span>
<ak-rac-endpoint-form slot="form" .instancePk=${item.pk}>
</ak-rac-endpoint-form>
<button slot="trigger" class="pf-c-button pf-m-plain">
@@ -121,11 +133,13 @@ export class EndpointListPage extends Table<Endpoint> {
renderObjectCreate(): TemplateResult {
return html`
<ak-forms-modal>
<span slot="submit">${msg("Create")}</span>
<span slot="header">${msg("Create Endpoint")}</span>
<span slot="submit">${formatCreateMessage(this.entityLabel)}</span>
<span slot="header">${formatNewMessage(this.entityLabel)}</span>
<ak-rac-endpoint-form slot="form" .providerID=${this.provider?.pk}>
</ak-rac-endpoint-form>
<button slot="trigger" class="pf-c-button pf-m-primary">${msg("Create")}</button>
<button slot="trigger" class="pf-c-button pf-m-primary">
${formatNewMessage(this.entityLabel)}
</button>
</ak-forms-modal>
`;
}

View File

@@ -31,12 +31,7 @@ export class RACProviderFormPage extends ModelForm<RACProvider, number> {
});
}
getSuccessMessage(): string {
if (this.instance) {
return msg("Successfully updated provider.");
}
return msg("Successfully created provider.");
}
protected override entityLabel = msg("RAC provider");
async send(data: RACProvider): Promise<RACProvider> {
if (this.instance) {

View File

@@ -13,6 +13,9 @@ import "#elements/buttons/SpinnerButton/index";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EVENT_REFRESH } from "#common/constants";
import { formatEditMessage } from "#common/i18n/actions";
import { EntityLabel } from "#common/i18n/nouns";
import { ActionTenseRecord } from "#common/i18n/verbs";
import { AKElement } from "#elements/Base";
import { SlottedTemplateResult } from "#elements/types";
@@ -41,6 +44,11 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
@customElement("ak-provider-rac-view")
export class RACProviderViewPage extends AKElement {
protected entityLabel: EntityLabel = {
singular: msg("Rac Provider", { id: "entity.rac-provider.singular" }),
plural: msg("Rac Providers", { id: "entity.rac-provider.plural" }),
};
@property({ type: Number })
providerID?: number;
@@ -189,12 +197,12 @@ export class RACProviderViewPage extends AKElement {
</div>
<div class="pf-c-card__footer">
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="header">${msg("Update RAC Provider")}</span>
<span slot="submit">${ActionTenseRecord.apply.present()}</span>
<span slot="header">${formatEditMessage(this.entityLabel)}</span>
<ak-provider-rac-form slot="form" .instancePk=${this.provider.pk || 0}>
</ak-provider-rac-form>
<button slot="trigger" class="pf-c-button pf-m-primary">
${msg("Edit")}
${formatEditMessage(this.entityLabel)}
</button>
</ak-forms-modal>
</div>

View File

@@ -9,6 +9,9 @@ import "#elements/buttons/SpinnerButton/index";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EVENT_REFRESH } from "#common/constants";
import { formatEditMessage } from "#common/i18n/actions";
import { EntityLabel } from "#common/i18n/nouns";
import { ActionTenseRecord } from "#common/i18n/verbs";
import { AKElement } from "#elements/Base";
import { SlottedTemplateResult } from "#elements/types";
@@ -35,6 +38,11 @@ import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css";
@customElement("ak-provider-radius-view")
export class RadiusProviderViewPage extends AKElement {
protected entityLabel: EntityLabel = {
singular: msg("Radius Provider", { id: "entity.radius-provider.singular" }),
plural: msg("Radius Providers", { id: "entity.radius-provider.plural" }),
};
@property({ type: Number })
providerID?: number;
@@ -139,7 +147,9 @@ export class RadiusProviderViewPage extends AKElement {
</div>
<div class="pf-c-card__footer">
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="submit"
>${ActionTenseRecord.apply.present()}</span
>
<span slot="header">
${msg("Update Radius Provider")}
</span>
@@ -149,7 +159,7 @@ export class RadiusProviderViewPage extends AKElement {
>
</ak-provider-radius-form>
<button slot="trigger" class="pf-c-button pf-m-primary">
${msg("Edit")}
${formatEditMessage(this.entityLabel)}
</button>
</ak-forms-modal>
</div>

View File

@@ -139,7 +139,7 @@ export function renderForm({
return html` <ak-text-input
name="name"
value=${ifDefined(provider.name)}
label=${msg("Name")}
label=${msg("SAML Provider Name", { id: "label.saml-provider-name" })}
required
.errorMessages=${errors.name}
></ak-text-input>

View File

@@ -15,9 +15,9 @@ import { customElement } from "lit/decorators.js";
@customElement("ak-provider-saml-import-form")
export class SAMLProviderImportForm extends Form<SAMLProvider> {
getSuccessMessage(): string {
return msg("Successfully imported provider.");
}
protected override readonly actionName = "import";
protected override entityLabel = msg("Provider", { id: "entity.provider.singular" });
async send(data: SAMLProvider): Promise<void> {
const file = this.files().get("metadata");
@@ -33,7 +33,11 @@ export class SAMLProviderImportForm extends Form<SAMLProvider> {
}
renderForm(): TemplateResult {
return html`<ak-form-element-horizontal label=${msg("Name")} required name="name">
return html`<ak-form-element-horizontal
label=${msg("SAML Provider Name", { id: "label.saml-provider-name" })}
required
name="name"
>
<input type="text" class="pf-c-form-control" required />
</ak-form-element-horizontal>
<ak-form-element-horizontal

View File

@@ -11,6 +11,9 @@ import "#elements/buttons/SpinnerButton/index";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EVENT_REFRESH } from "#common/constants";
import { formatEditMessage } from "#common/i18n/actions";
import { EntityLabel } from "#common/i18n/nouns";
import { ActionTenseRecord } from "#common/i18n/verbs";
import { MessageLevel } from "#common/messages";
import { AKElement } from "#elements/Base";
@@ -59,6 +62,11 @@ interface SAMLPreviewAttribute {
@customElement("ak-provider-saml-view")
export class SAMLProviderViewPage extends AKElement {
protected entityLabel: EntityLabel = {
singular: msg("Saml Provider", { id: "entity.saml-provider.singular" }),
plural: msg("Saml Providers", { id: "entity.saml-provider.plural" }),
};
@property({ type: Number })
providerID?: number;
@@ -363,12 +371,12 @@ export class SAMLProviderViewPage extends AKElement {
</div>
<div class="pf-c-card__footer">
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="header">${msg("Update SAML Provider")}</span>
<span slot="submit">${ActionTenseRecord.apply.present()}</span>
<span slot="header">${formatEditMessage(this.entityLabel)}</span>
<ak-provider-saml-form slot="form" .instancePk=${this.provider.pk || 0}>
</ak-provider-saml-form>
<button slot="trigger" class="pf-c-button pf-m-primary">
${msg("Edit")}
${formatEditMessage(this.entityLabel)}
</button>
</ak-forms-modal>
</div>

View File

@@ -3,6 +3,7 @@ import "#elements/forms/ModalForm";
import "#elements/sync/SyncObjectForm";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EntityLabel } from "#common/i18n/nouns";
import { PaginatedResponse, Table, TableColumn } from "#elements/table/Table";
import { SlottedTemplateResult } from "#elements/types";
@@ -23,6 +24,11 @@ export class SCIMProviderGroupList extends Table<SCIMProviderGroup> {
@property({ type: Number })
providerId?: number;
protected override entityLabel: EntityLabel = {
singular: msg("Scim Group", { id: "entity.scim-group.singular" }),
plural: msg("Scim Groups", { id: "entity.scim-group.plural" }),
};
protected override searchEnabled = true;
expandable = true;
@@ -76,9 +82,8 @@ export class SCIMProviderGroupList extends Table<SCIMProviderGroup> {
}
protected columns: TableColumn[] = [
// ---
[msg("Name")],
[msg("ID")],
[msg("Name", { id: "column.name" })],
[msg("ID", { id: "column.id" })],
];
row(item: SCIMProviderGroup): SlottedTemplateResult[] {

View File

@@ -3,6 +3,7 @@ import "#elements/forms/ModalForm";
import "#elements/sync/SyncObjectForm";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EntityLabel } from "#common/i18n/nouns";
import { PaginatedResponse, Table, TableColumn } from "#elements/table/Table";
import { SlottedTemplateResult } from "#elements/types";
@@ -23,6 +24,11 @@ export class SCIMProviderUserList extends Table<SCIMProviderUser> {
@property({ type: Number })
providerId?: number;
protected override entityLabel: EntityLabel = {
singular: msg("Scim User", { id: "entity.scim-user.singular" }),
plural: msg("Scim Users", { id: "entity.scim-user.plural" }),
};
protected override searchEnabled = true;
expandable = true;
@@ -77,8 +83,8 @@ export class SCIMProviderUserList extends Table<SCIMProviderUser> {
protected columns: TableColumn[] = [
// ---
[msg("Username")],
[msg("ID")],
[msg("Username", { id: "column.username" })],
[msg("ID", { id: "column.id" })],
];
row(item: SCIMProviderUser): SlottedTemplateResult[] {

View File

@@ -15,6 +15,9 @@ import "#elements/tasks/TaskList";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EVENT_REFRESH } from "#common/constants";
import { formatEditMessage } from "#common/i18n/actions";
import { EntityLabel } from "#common/i18n/nouns";
import { ActionTenseRecord } from "#common/i18n/verbs";
import { AKElement } from "#elements/Base";
import { SlottedTemplateResult } from "#elements/types";
@@ -47,6 +50,11 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
@customElement("ak-provider-scim-view")
export class SCIMProviderViewPage extends AKElement {
protected entityLabel: EntityLabel = {
singular: msg("Scim Provider", { id: "entity.scim-provider.singular" }),
plural: msg("Scim Providers", { id: "entity.scim-provider.plural" }),
};
@property({ type: Number })
providerID?: number;
@@ -236,12 +244,12 @@ export class SCIMProviderViewPage extends AKElement {
</div>
<div class="pf-c-card__footer">
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="header">${msg("Update SCIM Provider")}</span>
<span slot="submit">${ActionTenseRecord.apply.present()}</span>
<span slot="header">${formatEditMessage(this.entityLabel)}</span>
<ak-provider-scim-form slot="form" .instancePk=${this.provider.pk}>
</ak-provider-scim-form>
<button slot="trigger" class="pf-c-button pf-m-primary">
${msg("Edit")}
${formatEditMessage(this.entityLabel)}
</button>
</ak-forms-modal>
</div>

View File

@@ -11,6 +11,9 @@ import "#elements/tasks/TaskList";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EVENT_REFRESH } from "#common/constants";
import { formatEditMessage } from "#common/i18n/actions";
import { EntityLabel } from "#common/i18n/nouns";
import { ActionTenseRecord } from "#common/i18n/verbs";
import { AKElement } from "#elements/Base";
import { SlottedTemplateResult } from "#elements/types";
@@ -40,6 +43,11 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
@customElement("ak-provider-ssf-view")
export class SSFProviderViewPage extends AKElement {
protected entityLabel: EntityLabel = {
singular: msg("Ssf Provider", { id: "entity.ssf-provider.singular" }),
plural: msg("Ssf Providers", { id: "entity.ssf-provider.plural" }),
};
@property({ type: Number })
set providerID(value: number) {
new ProvidersApi(DEFAULT_CONFIG)
@@ -169,12 +177,12 @@ export class SSFProviderViewPage extends AKElement {
</div>
<div class="pf-c-card__footer">
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="header">${msg("Update SSF Provider")}</span>
<span slot="submit">${ActionTenseRecord.apply.present()}</span>
<span slot="header">${formatEditMessage(this.entityLabel)}</span>
<ak-provider-ssf-form slot="form" .instancePk=${this.provider.pk || 0}>
</ak-provider-ssf-form>
<button slot="trigger" class="pf-c-button pf-m-primary">
${msg("Edit")}
${formatEditMessage(this.entityLabel)}
</button>
</ak-forms-modal>
</div>

View File

@@ -5,6 +5,7 @@ import "#elements/forms/ProxyForm";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EntityLabel } from "#common/i18n/nouns";
import { PaginatedResponse, Table, TableColumn } from "#elements/table/Table";
import { SlottedTemplateResult } from "#elements/types";
@@ -17,6 +18,11 @@ import { customElement, property } from "lit/decorators.js";
@customElement("ak-provider-ssf-stream-list")
export class SSFProviderStreamList extends Table<SSFStream> {
protected override entityLabel: EntityLabel = {
singular: msg("Ssf Stream", { id: "entity.ssf-stream.singular" }),
plural: msg("Ssf Streams", { id: "entity.ssf-stream.plural" }),
};
protected override searchEnabled = true;
checkbox = true;
clearOnRefresh = true;
@@ -40,7 +46,7 @@ export class SSFProviderStreamList extends Table<SSFStream> {
protected columns: TableColumn[] = [
// ---
[msg("Audience"), "aud"],
[msg("Audience", { id: "column.audience" }), "aud"],
];
row(item: SSFStream): SlottedTemplateResult[] {

View File

@@ -37,11 +37,9 @@ export class InitialPermissionsForm extends ModelForm<InitialPermissions, string
});
}
getSuccessMessage(): string {
return this.instance
? msg("Successfully updated initial permissions.")
: msg("Successfully created initial permissions.");
}
protected override entityLabel = msg("Initial Permissions", {
id: "entity.initial.permissions.singular",
});
async send(data: InitialPermissions): Promise<InitialPermissions> {
if (this.instance?.pk) {
@@ -57,15 +55,33 @@ export class InitialPermissionsForm extends ModelForm<InitialPermissions, string
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<ak-form-element-horizontal label=${msg("Name")} required name="name">
<ak-form-element-horizontal
label=${msg("Permission Name", {
id: "label.initial.permissions.name",
desc: "Label for initial permissions name input",
})}
required
name="name"
>
<input
type="text"
value="${ifDefined(this.instance?.name)}"
placeholder=${msg("Type a descriptive name...", {
id: "placeholder.initial.permissions.name",
desc: "Placeholder text for initial permissions name input",
})}
class="pf-c-form-control"
required
/>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${msg("Role")} required name="role">
<ak-form-element-horizontal
label=${msg("Role", {
id: "label.initial.permissions.role",
desc: "Label for initial permissions role mode",
})}
required
name="role"
>
<ak-search-select
.fetchObjects=${async (query?: string): Promise<Role[]> => {
const args: RbacRolesListRequest = {

View File

@@ -5,6 +5,7 @@ import "#elements/forms/ModalForm";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EntityLabel } from "#common/i18n/nouns";
import { PaginatedResponse, TableColumn } from "#elements/table/Table";
import { TablePage } from "#elements/table/TablePage";
@@ -23,7 +24,12 @@ export class InitialPermissionsListPage extends TablePage<InitialPermissions> {
checkbox = true;
clearOnRefresh = true;
protected override searchEnabled = true;
public pageTitle = msg("Initial Permissions");
protected override entityLabel: EntityLabel = {
singular: msg("Initial Permission", { id: "entity.initial-permission.singular" }),
plural: msg("Initial Permissions", { id: "entity.initial-permission.plural" }),
};
public pageDescription = msg("Set initial permissions for newly created objects.");
public pageIcon = "fa fa-lock";
@@ -38,8 +44,12 @@ export class InitialPermissionsListPage extends TablePage<InitialPermissions> {
protected columns: TableColumn[] = [
// ---
[msg("Name"), "name"],
[msg("Actions"), null, msg("Row Actions")],
[msg("Name", { id: "column.name" }), "name"],
[
msg("Actions", { id: "column.actions" }),
null,
msg("Row Actions", { id: "column.row-actions" }),
],
];
renderToolbarSelected(): TemplateResult {
@@ -75,12 +85,12 @@ export class InitialPermissionsListPage extends TablePage<InitialPermissions> {
html`${item.name}`,
html`<div>
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="header">${msg("Update Initial Permissions")}</span>
<span slot="submit">${this.updateEntityLabel}</span>
<span slot="header">${this.editEntityLabel}</span>
<ak-initial-permissions-form slot="form" .instancePk=${item.pk}>
</ak-initial-permissions-form>
<button slot="trigger" class="pf-c-button pf-m-plain">
<pf-tooltip position="top" content=${msg("Edit")}>
<pf-tooltip position="top" content=${this.editEntityLabel}>
<i class="fas fa-edit" aria-hidden="true"></i>
</pf-tooltip>
</button>
@@ -92,10 +102,12 @@ export class InitialPermissionsListPage extends TablePage<InitialPermissions> {
renderObjectCreate(): TemplateResult {
return html`
<ak-forms-modal>
<span slot="submit">${msg("Create")}</span>
<span slot="header">${msg("Create Initial Permissions")}</span>
<span slot="submit">${this.createEntityLabel}</span>
<span slot="header">${this.newEntityActionLabel}</span>
<ak-initial-permissions-form slot="form"> </ak-initial-permissions-form>
<button slot="trigger" class="pf-c-button pf-m-primary">${msg("Create")}</button>
<button slot="trigger" class="pf-c-button pf-m-primary">
${this.newEntityActionLabel}
</button>
</ak-forms-modal>
`;
}

View File

@@ -1,6 +1,7 @@
import "#elements/buttons/SpinnerButton/index";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EntityLabel } from "#common/i18n/nouns";
import { groupBy } from "#common/utils";
import { PaginatedResponse, TableColumn } from "#elements/table/Table";
@@ -20,6 +21,11 @@ export class PermissionSelectModal extends TableModal<Permission> {
checkbox = true;
checkboxChip = true;
protected override entityLabel: EntityLabel = {
singular: msg("Permission", { id: "entity.permission.singular" }),
plural: msg("Permissions", { id: "entity.permission.plural" }),
};
protected override searchEnabled = true;
@property()
@@ -40,8 +46,8 @@ export class PermissionSelectModal extends TableModal<Permission> {
}
protected columns: TableColumn[] = [
[msg("Name"), "codename"],
[msg("Model"), ""],
[msg("Name", { id: "column.name" }), "codename"],
[msg("Model", { id: "column.model" }), ""],
];
row(item: Permission): SlottedTemplateResult[] {

Some files were not shown because too many files have changed in this diff Show More