Fixed some issues
This commit is contained in:
parent
9f68929b34
commit
86bd5fb545
@ -13,11 +13,11 @@ class MutationABC(QueryABC):
|
||||
QueryABC.__init__(self, f"{name}Mutation")
|
||||
|
||||
def add_mutation_type(
|
||||
self,
|
||||
name: str,
|
||||
mutation_name: str,
|
||||
require_any_permission: list[Permissions] = None,
|
||||
public: bool = False,
|
||||
self,
|
||||
name: str,
|
||||
mutation_name: str,
|
||||
require_any_permission=None,
|
||||
public: bool = False,
|
||||
):
|
||||
"""
|
||||
Add mutation type (sub mutation) to the mutation object
|
||||
@ -27,6 +27,8 @@ class MutationABC(QueryABC):
|
||||
:param bool public: Define if the field can resolve without authentication
|
||||
:return:
|
||||
"""
|
||||
if require_any_permission is None:
|
||||
require_any_permission = []
|
||||
from api_graphql.definition import QUERIES
|
||||
|
||||
self.field(
|
||||
|
@ -7,4 +7,8 @@ type Mutation {
|
||||
group: GroupMutation
|
||||
domain: DomainMutation
|
||||
shortUrl: ShortUrlMutation
|
||||
|
||||
setting: SettingMutation
|
||||
userSetting: UserSettingMutation
|
||||
featureFlag: FeatureFlagMutation
|
||||
}
|
18
api/src/api_graphql/input/feature_flag_input.py
Normal file
18
api/src/api_graphql/input/feature_flag_input.py
Normal file
@ -0,0 +1,18 @@
|
||||
from api_graphql.abc.input_abc import InputABC
|
||||
|
||||
|
||||
class FeatureFlagInput(InputABC):
|
||||
|
||||
def __init__(self, src: dict):
|
||||
InputABC.__init__(self, src)
|
||||
|
||||
self._key = self.option("key", str, required=True)
|
||||
self._value = self.option("value", bool, required=True)
|
||||
|
||||
@property
|
||||
def key(self) -> str:
|
||||
return self._key
|
||||
|
||||
@property
|
||||
def value(self) -> bool:
|
||||
return self._value
|
18
api/src/api_graphql/input/setting_input.py
Normal file
18
api/src/api_graphql/input/setting_input.py
Normal file
@ -0,0 +1,18 @@
|
||||
from api_graphql.abc.input_abc import InputABC
|
||||
|
||||
|
||||
class SettingInput(InputABC):
|
||||
|
||||
def __init__(self, src: dict):
|
||||
InputABC.__init__(self, src)
|
||||
|
||||
self._key = self.option("key", str, required=True)
|
||||
self._value = self.option("value", str, required=True)
|
||||
|
||||
@property
|
||||
def key(self) -> str:
|
||||
return self._key
|
||||
|
||||
@property
|
||||
def value(self) -> str:
|
||||
return self._value
|
18
api/src/api_graphql/input/user_setting_input.py
Normal file
18
api/src/api_graphql/input/user_setting_input.py
Normal file
@ -0,0 +1,18 @@
|
||||
from api_graphql.abc.input_abc import InputABC
|
||||
|
||||
|
||||
class UserSettingInput(InputABC):
|
||||
|
||||
def __init__(self, src: dict):
|
||||
InputABC.__init__(self, src)
|
||||
|
||||
self._key = self.option("key", str, required=True)
|
||||
self._value = self.option("value", str, required=True)
|
||||
|
||||
@property
|
||||
def key(self) -> str:
|
||||
return self._key
|
||||
|
||||
@property
|
||||
def value(self) -> str:
|
||||
return self._value
|
@ -60,3 +60,22 @@ class Mutation(MutationABC):
|
||||
Permissions.short_urls_delete,
|
||||
],
|
||||
)
|
||||
|
||||
self.add_mutation_type(
|
||||
"setting",
|
||||
"Setting",
|
||||
require_any_permission=[
|
||||
Permissions.settings_update,
|
||||
],
|
||||
)
|
||||
self.add_mutation_type(
|
||||
"userSetting",
|
||||
"UserSetting",
|
||||
)
|
||||
self.add_mutation_type(
|
||||
"featureFlag",
|
||||
"FeatureFlag",
|
||||
require_any_permission=[
|
||||
Permissions.administrator,
|
||||
],
|
||||
)
|
||||
|
32
api/src/api_graphql/mutations/feature_flag_mutation.py
Normal file
32
api/src/api_graphql/mutations/feature_flag_mutation.py
Normal file
@ -0,0 +1,32 @@
|
||||
from api_graphql.abc.mutation_abc import MutationABC
|
||||
from api_graphql.input.feature_flag_input import FeatureFlagInput
|
||||
from core.logger import APILogger
|
||||
from data.schemas.system.feature_flag import FeatureFlag
|
||||
from data.schemas.system.feature_flag_dao import featureFlagDao
|
||||
from service.permission.permissions_enum import Permissions
|
||||
|
||||
logger = APILogger(__name__)
|
||||
|
||||
|
||||
class FeatureFlagMutation(MutationABC):
|
||||
def __init__(self):
|
||||
MutationABC.__init__(self, "FeatureFlag")
|
||||
self.mutation(
|
||||
"change",
|
||||
self.resolve_change,
|
||||
FeatureFlagInput,
|
||||
require_any_permission=[Permissions.administrator],
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
async def resolve_change(obj: FeatureFlagInput, *_):
|
||||
logger.debug(f"create new feature flag: {input}")
|
||||
|
||||
setting = await featureFlagDao.find_single_by({FeatureFlag.key: obj.key})
|
||||
if setting is None:
|
||||
raise ValueError(f"FeatureFlag {obj.key} not found")
|
||||
|
||||
setting.value = obj.value
|
||||
await featureFlagDao.update(setting)
|
||||
|
||||
return await featureFlagDao.get_by_id(setting.id)
|
32
api/src/api_graphql/mutations/setting_mutation.py
Normal file
32
api/src/api_graphql/mutations/setting_mutation.py
Normal file
@ -0,0 +1,32 @@
|
||||
from api_graphql.abc.mutation_abc import MutationABC
|
||||
from api_graphql.input.setting_input import SettingInput
|
||||
from core.logger import APILogger
|
||||
from data.schemas.system.setting import Setting
|
||||
from data.schemas.system.setting_dao import settingsDao
|
||||
from service.permission.permissions_enum import Permissions
|
||||
|
||||
logger = APILogger(__name__)
|
||||
|
||||
|
||||
class SettingMutation(MutationABC):
|
||||
def __init__(self):
|
||||
MutationABC.__init__(self, "Setting")
|
||||
self.mutation(
|
||||
"change",
|
||||
self.resolve_change,
|
||||
SettingInput,
|
||||
require_any_permission=[Permissions.settings_update],
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
async def resolve_change(obj: SettingInput, *_):
|
||||
logger.debug(f"create new setting: {input}")
|
||||
|
||||
setting = await settingsDao.find_single_by({Setting.key: obj.key})
|
||||
if setting is None:
|
||||
raise ValueError(f"Setting with key {obj.key} not found")
|
||||
|
||||
setting.value = obj.value
|
||||
await settingsDao.update(setting)
|
||||
|
||||
return await settingsDao.get_by_id(setting.id)
|
40
api/src/api_graphql/mutations/user_setting_mutation.py
Normal file
40
api/src/api_graphql/mutations/user_setting_mutation.py
Normal file
@ -0,0 +1,40 @@
|
||||
from api.route import Route
|
||||
from api_graphql.abc.mutation_abc import MutationABC
|
||||
from api_graphql.input.user_setting_input import UserSettingInput
|
||||
from core.logger import APILogger
|
||||
from data.schemas.public.user_setting import UserSetting
|
||||
from data.schemas.public.user_setting_dao import userSettingsDao
|
||||
from data.schemas.system.setting_dao import settingsDao
|
||||
from service.permission.permissions_enum import Permissions
|
||||
|
||||
logger = APILogger(__name__)
|
||||
|
||||
|
||||
class UserSettingMutation(MutationABC):
|
||||
def __init__(self):
|
||||
MutationABC.__init__(self, "UserSetting")
|
||||
self.mutation(
|
||||
"change",
|
||||
self.resolve_change,
|
||||
UserSettingInput,
|
||||
require_any_permission=[Permissions.settings_update],
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
async def resolve_change(obj: UserSettingInput, *_):
|
||||
logger.debug(f"create new setting: {input}")
|
||||
user = await Route.get_user_or_default()
|
||||
if user is None:
|
||||
logger.debug("user not authorized")
|
||||
return None
|
||||
|
||||
setting = await userSettingsDao.find_single_by(
|
||||
[{UserSetting.user_id: user.id}, {UserSetting.key: obj.key}]
|
||||
)
|
||||
if setting is None:
|
||||
await userSettingsDao.create(UserSetting(0, user.id, obj.key, obj.value))
|
||||
else:
|
||||
setting.value = obj.value
|
||||
await userSettingsDao.update(setting)
|
||||
|
||||
return await userSettingsDao.find_by_key(user, obj.key)
|
@ -5,7 +5,7 @@ CREATE TABLE IF NOT EXISTS public.user_settings
|
||||
Id SERIAL PRIMARY KEY,
|
||||
Key TEXT NOT NULL,
|
||||
Value TEXT NOT NULL,
|
||||
UserId INT NOT NULL REFERENCES public.user_settings (Id) ON DELETE CASCADE,
|
||||
UserId INT NOT NULL REFERENCES administration.users (Id) ON DELETE CASCADE,
|
||||
-- for history
|
||||
Deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
EditorId INT NULL REFERENCES administration.users (Id),
|
||||
|
@ -8,8 +8,9 @@ import { User } from 'src/app/model/auth/user';
|
||||
import { AuthService } from 'src/app/service/auth.service';
|
||||
import { MenuElement } from 'src/app/model/view/menu-element';
|
||||
import { SidebarService } from 'src/app/service/sidebar.service';
|
||||
import { SettingsService } from 'src/app/service/settings.service';
|
||||
import { ConfigService } from 'src/app/service/config.service';
|
||||
import { UserSettingsService } from 'src/app/service/user_settings.service';
|
||||
import { SettingsService } from 'src/app/service/settings.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-header',
|
||||
@ -33,7 +34,9 @@ export class HeaderComponent implements OnInit, OnDestroy {
|
||||
private guiService: GuiService,
|
||||
private auth: AuthService,
|
||||
private sidebarService: SidebarService,
|
||||
private config: ConfigService
|
||||
private config: ConfigService,
|
||||
private settings: SettingsService,
|
||||
private userSettings: UserSettingsService
|
||||
) {
|
||||
this.guiService.isMobile$
|
||||
.pipe(takeUntil(this.unsubscribe$))
|
||||
@ -47,13 +50,18 @@ export class HeaderComponent implements OnInit, OnDestroy {
|
||||
this.auth.user$.pipe(takeUntil(this.unsubscribe$)).subscribe(async user => {
|
||||
this.user = user;
|
||||
await this.initMenuLists();
|
||||
if (user) {
|
||||
await this.loadTheme();
|
||||
await this.loadLang();
|
||||
}
|
||||
});
|
||||
|
||||
this.themeList = this.config.settings.themes.map(theme => {
|
||||
return {
|
||||
label: theme.label,
|
||||
command: () => {
|
||||
command: async () => {
|
||||
this.guiService.theme$.next(theme.name);
|
||||
await this.userSettings.set('theme', theme.name);
|
||||
},
|
||||
};
|
||||
});
|
||||
@ -61,7 +69,6 @@ export class HeaderComponent implements OnInit, OnDestroy {
|
||||
|
||||
async ngOnInit() {
|
||||
await this.initMenuLists();
|
||||
await this.loadLang();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
@ -74,24 +81,49 @@ export class HeaderComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
async initMenuLists() {
|
||||
await this.initMenuList();
|
||||
await this.initLangMenuList();
|
||||
await this.initUserMenuList();
|
||||
}
|
||||
|
||||
async initMenuList() {
|
||||
this.menu = [
|
||||
{
|
||||
label: 'common.news',
|
||||
routerLink: ['/'],
|
||||
icon: 'pi pi-home',
|
||||
},
|
||||
{
|
||||
label: 'header.menu.about',
|
||||
routerLink: ['/about'],
|
||||
icon: 'pi pi-info',
|
||||
},
|
||||
];
|
||||
|
||||
if (this.auth.user$.value) {
|
||||
this.menu.push({
|
||||
label: 'header.menu.admin',
|
||||
routerLink: ['/admin'],
|
||||
icon: 'pi pi-cog',
|
||||
visible: await this.auth.isAdmin(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async initLangMenuList() {
|
||||
this.langList = [
|
||||
{
|
||||
label: 'English',
|
||||
command: () => {
|
||||
command: async () => {
|
||||
this.translate('en');
|
||||
this.setLang('en');
|
||||
await this.setLang('en');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Deutsch',
|
||||
command: () => {
|
||||
command: async () => {
|
||||
this.translate('de');
|
||||
this.setLang('de');
|
||||
await this.setLang('de');
|
||||
},
|
||||
},
|
||||
];
|
||||
@ -109,10 +141,8 @@ export class HeaderComponent implements OnInit, OnDestroy {
|
||||
},
|
||||
{
|
||||
label: this.translateService.instant('header.logout'),
|
||||
command: () => {
|
||||
this.auth.logout().then(() => {
|
||||
console.log('logout');
|
||||
});
|
||||
command: async () => {
|
||||
await this.auth.logout();
|
||||
},
|
||||
icon: 'pi pi-sign-out',
|
||||
},
|
||||
@ -126,15 +156,33 @@ export class HeaderComponent implements OnInit, OnDestroy {
|
||||
.subscribe(res => this.ngConfig.setTranslation(res));
|
||||
}
|
||||
|
||||
async loadLang() {
|
||||
const lang = 'en';
|
||||
this.setLang(lang);
|
||||
this.translate(lang);
|
||||
async loadTheme() {
|
||||
const defaultTheme = (await this.settings.get('default_theme')) ?? 'maxlan';
|
||||
const userTheme = await this.userSettings.get('theme');
|
||||
const theme = userTheme ?? defaultTheme;
|
||||
|
||||
this.guiService.theme$.next(theme);
|
||||
|
||||
if (!userTheme) {
|
||||
await this.userSettings.set('theme', theme);
|
||||
}
|
||||
}
|
||||
|
||||
setLang(lang: string) {
|
||||
// this.settings.setSetting(`lang`, lang);
|
||||
console.log('setLang', lang);
|
||||
async loadLang() {
|
||||
const defaultLang = (await this.settings.get('default_language')) ?? 'en';
|
||||
const userLang = await this.userSettings.get('language');
|
||||
const lang = userLang ?? defaultLang;
|
||||
|
||||
this.translate(lang);
|
||||
|
||||
if (userLang) {
|
||||
return;
|
||||
}
|
||||
await this.userSettings.set('language', lang);
|
||||
}
|
||||
|
||||
async setLang(lang: string) {
|
||||
await this.userSettings.set('language', lang);
|
||||
}
|
||||
|
||||
toggleSidebar() {
|
||||
|
@ -103,6 +103,14 @@ export class AuthService {
|
||||
return this.keycloakService.logout();
|
||||
}
|
||||
|
||||
isLoggedIn(): boolean {
|
||||
return (
|
||||
this.keycloakService.isLoggedIn() &&
|
||||
!this.keycloakService.isTokenExpired() &&
|
||||
!!this.user$.value
|
||||
);
|
||||
}
|
||||
|
||||
async isAdmin(): Promise<boolean> {
|
||||
return await this.hasAnyPermissionLazy(this.anyPermissionForAdminPage);
|
||||
}
|
||||
|
111
web/src/app/service/user_settings.service.ts
Normal file
111
web/src/app/service/user_settings.service.ts
Normal file
@ -0,0 +1,111 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { throwError } from 'rxjs';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
import { Setting } from 'src/app/model/entities/setting';
|
||||
import { Apollo, gql } from 'apollo-angular';
|
||||
import { Logger } from 'src/app/service/logger.service';
|
||||
import { AuthService } from 'src/app/service/auth.service';
|
||||
|
||||
const log = new Logger('UserSettings');
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class UserSettingsService {
|
||||
constructor(
|
||||
private apollo: Apollo,
|
||||
private auth: AuthService
|
||||
) {}
|
||||
|
||||
get(key: string): Promise<string | undefined> {
|
||||
if (!this.auth.isLoggedIn()) {
|
||||
log.debug('get', key, 'not logged in');
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
log.debug('get', key);
|
||||
return new Promise((resolve, reject) => {
|
||||
this.apollo
|
||||
.query<{ userSettings: Setting[] }>({
|
||||
query: gql`
|
||||
query getUserSetting($key: String!) {
|
||||
userSettings(key: $key) {
|
||||
key
|
||||
value
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
key,
|
||||
},
|
||||
})
|
||||
.pipe(
|
||||
catchError(err => {
|
||||
throw err;
|
||||
})
|
||||
)
|
||||
.pipe(
|
||||
map(result =>
|
||||
result.data.userSettings?.length > 0
|
||||
? result.data.userSettings[0]
|
||||
: undefined
|
||||
)
|
||||
)
|
||||
.pipe(
|
||||
catchError(err => {
|
||||
reject(err);
|
||||
return throwError(() => err);
|
||||
})
|
||||
)
|
||||
.subscribe(setting => {
|
||||
log.debug('Got', key, setting);
|
||||
resolve(setting?.value);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
set(key: string, value: string): Promise<void> {
|
||||
if (!this.auth.isLoggedIn()) {
|
||||
log.debug('set', key, value, 'not logged in');
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
log.debug('set', key, value);
|
||||
return new Promise((resolve, reject) => {
|
||||
this.apollo
|
||||
.mutate<{ userSetting: { change: Setting } }>({
|
||||
mutation: gql`
|
||||
mutation changeUserSetting($input: UserSettingInput!) {
|
||||
userSetting {
|
||||
change(input: $input) {
|
||||
key
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
input: {
|
||||
key: key,
|
||||
value: value,
|
||||
},
|
||||
},
|
||||
})
|
||||
.pipe(
|
||||
catchError(err => {
|
||||
throw err;
|
||||
})
|
||||
)
|
||||
.pipe(map(result => result.data?.userSetting.change))
|
||||
.pipe(
|
||||
catchError(err => {
|
||||
reject(err);
|
||||
return throwError(() => err);
|
||||
})
|
||||
)
|
||||
.subscribe(() => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
@ -16,7 +16,6 @@
|
||||
"all": "Alle",
|
||||
"api_error": "API Fehler",
|
||||
"api_key": "API Key",
|
||||
"by": "von",
|
||||
"cancel": "Abbrechen",
|
||||
"choose": "Auswählen",
|
||||
"close": "Schließen",
|
||||
@ -28,7 +27,6 @@
|
||||
"domain": "Domain",
|
||||
"domains": "Domains",
|
||||
"download": "Herunterladen",
|
||||
"edited_at": "Bearbeitet am",
|
||||
"editor": "Bearbeiter",
|
||||
"error": "Fehler",
|
||||
"group": "Gruppe",
|
||||
@ -37,7 +35,6 @@
|
||||
"identifier": "Identifier",
|
||||
"key": "Schlüssel",
|
||||
"name": "Name",
|
||||
"news": "News",
|
||||
"role": "Rolle",
|
||||
"save": "Speichern",
|
||||
"short_url": "Url",
|
||||
@ -48,9 +45,7 @@
|
||||
},
|
||||
"dialog": {
|
||||
"abort": "Abbrechen",
|
||||
"back": "Zurück",
|
||||
"confirm": "Bestätigen",
|
||||
"continue": "Fortsetzen",
|
||||
"delete": {
|
||||
"header": "Löschen bestätigen",
|
||||
"message": "Sind Sie sicher, dass Sie {{entity}} löschen möchten?"
|
||||
@ -58,22 +53,18 @@
|
||||
"restore": {
|
||||
"header": "Wiederherstellung bestätigen",
|
||||
"message": "Sind Sie sicher, dass Sie {{entity}} wiederherstellen möchten?"
|
||||
},
|
||||
"save": "Speichern"
|
||||
}
|
||||
},
|
||||
"domain": {
|
||||
"count_header": "Domain(s)"
|
||||
},
|
||||
"error": {
|
||||
"404": "404 - Nicht gefunden",
|
||||
"create_failed": "Erstellung fehlgeschlagen",
|
||||
"delete_failed": "Löschen fehlgeschlagen",
|
||||
"missing_permissions": "Fehlende Berechtigungen: {{permissions}}",
|
||||
"network_error": "Netzwerkfehler",
|
||||
"permission_denied": "Fehlende Berechtigung",
|
||||
"restore_failed": "Wiederherstellung fehlgeschlagen",
|
||||
"unauthorized": "Nicht autorisiert",
|
||||
"update_failed": "Bearbeitung fehlgeschlagen"
|
||||
"retry": "Erneut versuchen",
|
||||
"server_unavailable": "Server nicht erreichbar",
|
||||
"unauthorized": "Nicht autorisiert"
|
||||
},
|
||||
"footer": {
|
||||
"imprint": "Impressum",
|
||||
@ -84,11 +75,12 @@
|
||||
"count_header": "Gruppe(n)"
|
||||
},
|
||||
"header": {
|
||||
"logout": "Ausloggen",
|
||||
"menu": {
|
||||
"about": "Über uns",
|
||||
"admin": "Admin"
|
||||
}
|
||||
"logout": "Ausloggen"
|
||||
},
|
||||
"permission_descriptions": {
|
||||
"short_urls": "Alle URLs sehen",
|
||||
"short_urls.by_assignment": "Alle Kurz-URLs anzeigen, die einer Gruppe nach Rolle zugewiesen sind",
|
||||
"users.update": "Benutzer inkl. der Rollen ändern"
|
||||
},
|
||||
"permissions": {
|
||||
"api_keys": "API Keys",
|
||||
@ -107,10 +99,6 @@
|
||||
"ip_list.create": "Erstellen",
|
||||
"ip_list.delete": "Löschen",
|
||||
"ip_list.update": "Bearbeiten",
|
||||
"news": "News",
|
||||
"news.create": "Erstellen",
|
||||
"news.delete": "Löschen",
|
||||
"news.update": "Bearbeiten",
|
||||
"roles": "Rollen",
|
||||
"roles.create": "Erstellen",
|
||||
"roles.delete": "Löschen",
|
||||
@ -125,19 +113,10 @@
|
||||
"users.delete": "Löschen",
|
||||
"users.update": "Bearbeiten"
|
||||
},
|
||||
"qr": {
|
||||
"width": "Breite"
|
||||
},
|
||||
"permission_descriptions": {
|
||||
"users.update": "Benutzer inkl. der Rollen ändern",
|
||||
"short_urls": "Alle URLs sehen",
|
||||
"short_urls.by_assignment": "Alle Kurz-URLs anzeigen, die einer Gruppe nach Rolle zugewiesen sind"
|
||||
},
|
||||
"role": {
|
||||
"count_header": "Rolle(n)"
|
||||
},
|
||||
"short_url": {
|
||||
"count_header": "Url(s)",
|
||||
"loading_screen": "Ladebildschirm",
|
||||
"short_url": "URL",
|
||||
"target_url": "Ziel",
|
||||
@ -146,12 +125,13 @@
|
||||
"sidebar": {
|
||||
"administration": "Administration",
|
||||
"api_keys": "API Keys",
|
||||
"feature_flags": "Funktionen",
|
||||
"header": {
|
||||
"create": "erstellen",
|
||||
"update": "bearbeiten"
|
||||
},
|
||||
"public": "Öffentlich",
|
||||
"roles": "Rollen",
|
||||
"settings": "Einstellungen",
|
||||
"users": "Benutzer"
|
||||
},
|
||||
"table": {
|
||||
@ -163,6 +143,7 @@
|
||||
"reset_filters": "Filter zurücksetzen",
|
||||
"reset_sort": "Sortierung zurücksetzen",
|
||||
"restore": "Wiederherstellen",
|
||||
"select_columns": "Spalten auswählen",
|
||||
"show_deleted": "Gelöschte anzeigen",
|
||||
"to": "bis",
|
||||
"update": "Bearbeiten"
|
||||
|
@ -16,7 +16,6 @@
|
||||
"all": "All",
|
||||
"api_error": "API error",
|
||||
"api_key": "API Key",
|
||||
"by": "by",
|
||||
"cancel": "Cancel",
|
||||
"choose": "Choose",
|
||||
"close": "Close",
|
||||
@ -28,7 +27,6 @@
|
||||
"domain": "Domain",
|
||||
"domains": "Domains",
|
||||
"download": "Download",
|
||||
"edited_at": "Edited at",
|
||||
"editor": "Editor",
|
||||
"error": "Fehler",
|
||||
"group": "Group",
|
||||
@ -37,7 +35,6 @@
|
||||
"identifier": "Identifier",
|
||||
"key": "Key",
|
||||
"name": "Name",
|
||||
"news": "News",
|
||||
"role": "Role",
|
||||
"save": "Save",
|
||||
"short_url": "Url",
|
||||
@ -48,9 +45,7 @@
|
||||
},
|
||||
"dialog": {
|
||||
"abort": "Abort",
|
||||
"back": "Back",
|
||||
"confirm": "Confirm",
|
||||
"continue": "Continue",
|
||||
"delete": {
|
||||
"header": "Confirm delete",
|
||||
"message": "Are you sure you want to delete {{entity}}?"
|
||||
@ -58,22 +53,18 @@
|
||||
"restore": {
|
||||
"header": "Confirm restore",
|
||||
"message": "Are you sure you want to restore {{entity}}?"
|
||||
},
|
||||
"save": "Save"
|
||||
}
|
||||
},
|
||||
"domain": {
|
||||
"count_header": "Domain(s)"
|
||||
},
|
||||
"error": {
|
||||
"404": "404 - Not found",
|
||||
"create_failed": "Create failed",
|
||||
"delete_failed": "Delete failed",
|
||||
"missing_permissions": "Missing permissions: {{permissions}}",
|
||||
"network_error": "Network Error",
|
||||
"permission_denied": "Permission Denied",
|
||||
"restore_failed": "Restore failed",
|
||||
"unauthorized": "Unauthorized",
|
||||
"update_failed": "Update failed"
|
||||
"retry": "Retry",
|
||||
"server_unavailable": "Server unavailable",
|
||||
"unauthorized": "Unauthorized"
|
||||
},
|
||||
"footer": {
|
||||
"imprint": "Imprint",
|
||||
@ -84,11 +75,12 @@
|
||||
"count_header": "Group(s)"
|
||||
},
|
||||
"header": {
|
||||
"logout": "Logout",
|
||||
"menu": {
|
||||
"about": "About",
|
||||
"admin": "Admin"
|
||||
}
|
||||
"logout": "Logout"
|
||||
},
|
||||
"permission_descriptions": {
|
||||
"short_urls": "See all URLs",
|
||||
"short_urls.by_assignment": "See all short urls assigned to a group by role",
|
||||
"users.update": "Change users including their roles"
|
||||
},
|
||||
"permissions": {
|
||||
"api_keys": "API Keys",
|
||||
@ -107,10 +99,6 @@
|
||||
"ip_list.create": "Create",
|
||||
"ip_list.delete": "Delete",
|
||||
"ip_list.update": "Update",
|
||||
"news": "News",
|
||||
"news.create": "Create",
|
||||
"news.delete": "Delete",
|
||||
"news.update": "Update",
|
||||
"roles": "Roles",
|
||||
"roles.create": "Create",
|
||||
"roles.delete": "Delete",
|
||||
@ -125,19 +113,10 @@
|
||||
"users.delete": "Delete",
|
||||
"users.update": "Update"
|
||||
},
|
||||
"permission_descriptions": {
|
||||
"users.update": "Change users including their roles",
|
||||
"short_urls": "See all URLs",
|
||||
"short_urls.by_assignment": "See all short urls assigned to a group by role"
|
||||
},
|
||||
"qr": {
|
||||
"width": "Width"
|
||||
},
|
||||
"role": {
|
||||
"count_header": "Role(s)"
|
||||
},
|
||||
"short_url": {
|
||||
"count_header": "Url(s)",
|
||||
"loading_screen": "Loading screen",
|
||||
"short_url": "URL",
|
||||
"target_url": "Target",
|
||||
@ -146,12 +125,13 @@
|
||||
"sidebar": {
|
||||
"administration": "Administration",
|
||||
"api_keys": "API Keys",
|
||||
"feature_flags": "Features",
|
||||
"header": {
|
||||
"create": "create",
|
||||
"update": "update"
|
||||
},
|
||||
"public": "Public",
|
||||
"roles": "Roles",
|
||||
"settings": "Settings",
|
||||
"users": "Users"
|
||||
},
|
||||
"table": {
|
||||
@ -163,6 +143,7 @@
|
||||
"reset_filters": "Reset filters",
|
||||
"reset_sort": "Reset sort",
|
||||
"restore": "Restore",
|
||||
"select_columns": "Select columns",
|
||||
"show_deleted": "Show deleted",
|
||||
"to": "to",
|
||||
"update": "Update"
|
||||
|
Loading…
Reference in New Issue
Block a user