Organization writes were superadmin-only, so standing up a tenant needed an out-of-band superadmin. Creating one is now self-service, and an admin manages the org they belong to. - POST /api/orgs is open to any authenticated user. A creator who isn't a superadmin must have no organization yet (a single-valued membership relation means a second one would abandon the first), and is promoted to the new org's admin and first member in the same request. If that promotion fails the org is rolled back, so it is never left stranded with nobody able to administer it. Superadmins still create tenants without joining them. - PATCH/DELETE are manager-gated and scope an admin to their own org. An admin deletes theirs only as its sole member: they are detached and demoted to a plain user before the record goes, so the org is empty when it is removed. Other members still block deletion with a 409. - /api/me now carries organization + organizationName, which the clients need to tell "no org yet" from "org you administer". The panel, Web App (new OrgManager.vue in Settings) and Phone App (new _OrganizationSection) all mirror the server's gates rather than re-deciding them. The Phone App cached its role at login and gates the Users tab on it, so AuthService.adoptRole refreshes that from the profile instead of making a freshly promoted admin sign in again. Covered by orgs_test.go, which drives the real handler + middleware chain against a stand-in PocketBase: promotion, the already-a-member refusal, superadmin staying unattached, the rollback, own-org scoping, the detach-and-demote, and the blocking-member 409. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
169 lines
5.5 KiB
JSON
169 lines
5.5 KiB
JSON
{
|
|
"app": {
|
|
"apiServer": "API-server",
|
|
"switchToLight": "Skift til lyst tema",
|
|
"switchToDark": "Skift til mørkt tema",
|
|
"theme": "Tema",
|
|
"signOut": "Log ud",
|
|
"loading": "Indlæser…",
|
|
"standardUserNote": "Logget ind som almindelig bruger — administrationssektioner kræver en administratorrolle",
|
|
"footer": "DriverVault — bilservice- og vedligeholdelsesregister."
|
|
},
|
|
|
|
"sections": {
|
|
"overview": "Oversigt",
|
|
"users": "Brugere",
|
|
"orgs": "Organisationer",
|
|
"pocketbase": "PocketBase",
|
|
"webapp": "Webapp",
|
|
"plugins": "Plugins",
|
|
"api": "API"
|
|
},
|
|
|
|
"login": {
|
|
"title": "Log ind",
|
|
"subtitle": "Superadmin-konsol til DriverVault API-serveren.",
|
|
"email": "E-mail",
|
|
"password": "Adgangskode",
|
|
"submit": "Log ind",
|
|
"submitting": "Logger ind…",
|
|
"invalid": "Ugyldig e-mail eller adgangskode.",
|
|
"failed": "Kunne ikke logge ind.",
|
|
"authNote": "Godkender mod PocketBase gennem denne server"
|
|
},
|
|
|
|
"status": {
|
|
"title": "Status",
|
|
"unreachable": "utilgængelig",
|
|
"checking": "Tjekker…",
|
|
"apiServer": "API-server",
|
|
"pocketBase": "PocketBase",
|
|
"webApp": "Webapp",
|
|
"thisProcess": "denne proces"
|
|
},
|
|
|
|
"common": {
|
|
"create": "Opret",
|
|
"save": "Gem",
|
|
"cancel": "Annuller",
|
|
"edit": "Rediger",
|
|
"delete": "Slet",
|
|
"rename": "Omdøb",
|
|
"empty": "—",
|
|
"name": "Navn",
|
|
"email": "E-mail",
|
|
"role": "Rolle",
|
|
"organization": "Organisation"
|
|
},
|
|
|
|
"users": {
|
|
"title": "Brugere",
|
|
"allOrgs": "Alle organisationer",
|
|
"yourOrg": "Din organisation",
|
|
"newUser": "Ny bruger",
|
|
"password": "Adgangskode",
|
|
"passwordUnchanged": "Adgangskode (tom = uændret)",
|
|
"passwordPlaceholder": "mindst 8 tegn",
|
|
"orgNone": "— ingen —",
|
|
"you": "dig",
|
|
"empty": "Ingen brugere.",
|
|
"confirmDelete": "Slet {email}? Dette kan ikke fortrydes."
|
|
},
|
|
|
|
"orgs": {
|
|
"title": "Organisationer",
|
|
"subtitle": "Enheder, som brugere tilhører",
|
|
"subtitleOwn": "Din organisation",
|
|
"subtitleNone": "Opret en for at administrere dit eget team",
|
|
"newOrg": "Ny organisation",
|
|
"namePlaceholder": "Acme Fleet",
|
|
"empty": "Ingen organisationer endnu.",
|
|
"createHint": "Du har endnu ingen organisation. Opret en for at blive dens administrator.",
|
|
"colId": "ID",
|
|
"confirmDelete": "Slet organisationen \"{name}\"?",
|
|
"confirmDeleteOwn": "Slet din organisation „{name}“? Du fjernes fra den og bliver en almindelig bruger."
|
|
},
|
|
|
|
"pocketbase": {
|
|
"title": "PocketBase",
|
|
"subtitle": "Databaseforbindelse brugt af hvert endpoint",
|
|
"connected": "forbundet",
|
|
"noSuperuser": "ingen superbruger",
|
|
"unreachable": "utilgængelig",
|
|
"baseUrl": "Basis-URL",
|
|
"superuserEmail": "Superbrugerens e-mail",
|
|
"superuserPassword": "Superbrugerens adgangskode",
|
|
"passwordUnchanged": "uændret",
|
|
"passwordNotSet": "ikke angivet",
|
|
"saveApply": "Gem og anvend",
|
|
"testConnection": "Test forbindelse",
|
|
"persistedEnv": "gemt i .env",
|
|
"testOk": "Forbindelse OK — superbruger godkendt.",
|
|
"testReachableNoAuth": "PocketBase er tilgængelig, men servicekontoen blev ikke godkendt.",
|
|
"testUnreachable": "PocketBase er ikke tilgængelig på den adresse.",
|
|
"savedNotice": "Gemt. Serveren bruger nu denne PocketBase."
|
|
},
|
|
|
|
"webapp": {
|
|
"title": "Webapp",
|
|
"subtitle": "Adressen, der tjekkes ved statuskontrol, og hvem der må kalde dette API fra en browser",
|
|
"reachable": "tilgængelig",
|
|
"unreachable": "utilgængelig",
|
|
"baseUrl": "Basis-URL",
|
|
"allowedOrigins": "Tilladte oprindelser",
|
|
"originsHint": "Kommasepareret, eller {star} for enhver. Native mobilapps er ikke underlagt CORS.",
|
|
"saveApply": "Gem og anvend",
|
|
"testConnection": "Test forbindelse",
|
|
"persistedEnv": "gemt i .env",
|
|
"testOk": "Webappen er tilgængelig.",
|
|
"testFailed": "Webappen svarede ikke på sit helbredstjek på den adresse.",
|
|
"savedNotice": "Gemt. Nye oprindelser gælder fra næste anmodning."
|
|
},
|
|
|
|
"plugins": {
|
|
"title": "Plugins",
|
|
"subtitle": "Integrationer med tredjepartstjenester",
|
|
"registerExternal": "Registrér ekstern",
|
|
"cancelRegister": "Annuller",
|
|
"name": "Navn",
|
|
"baseUrl": "Basis-URL",
|
|
"provider": "Udbyder",
|
|
"register": "Registrér",
|
|
"empty": "Ingen plugins endnu. Registrér et eksternt ovenfor, eller kompilér et indbygget stik.",
|
|
"builtin": "indbygget",
|
|
"enabled": "aktiveret",
|
|
"disabled": "deaktiveret",
|
|
"health": "Helbred",
|
|
"configure": "Konfigurer",
|
|
"close": "Luk",
|
|
"noConfig": "Dette plugin kræver ingen konfiguration.",
|
|
"notSet": "Ikke angivet — lad organisationer og brugere vælge",
|
|
"capabilities": "Funktioner",
|
|
"saved": "Gemt.",
|
|
"checking": "Tjekker…",
|
|
"save": "Gem",
|
|
"saveEnable": "Gem og aktivér",
|
|
"disable": "Deaktiver",
|
|
"remove": "Fjern",
|
|
"builtinNote": "Indbyggede plugins kan deaktiveres, men ikke fjernes",
|
|
"confirmRemove": "Fjern det eksterne plugin \"{name}\"? Dets gemte konfiguration slettes."
|
|
},
|
|
|
|
"api": {
|
|
"colEndpoint": "Endpoint",
|
|
"colDescription": "Beskrivelse",
|
|
"authNone": "Ingen godkendelse",
|
|
"authBearer": "Bearer-token",
|
|
"authManager": "Admin / superadmin",
|
|
"authSuperadmin": "Superadmin",
|
|
"groupPublic": "Offentlig",
|
|
"groupIdentity": "Identitet",
|
|
"groupCars": "Biler",
|
|
"groupService": "Serviceposter",
|
|
"groupParts": "Reservedele",
|
|
"groupAccount": "Konto",
|
|
"groupManagement": "Administration",
|
|
"groupSuperadmin": "Superadmin"
|
|
}
|
|
}
|