mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) updates from grist-core
This commit is contained in:
commit
65a1863015
@ -6,8 +6,8 @@
|
|||||||
* IdP is the "Identity Provider", somewhere users log into, e.g. Okta or Google Apps.
|
* IdP is the "Identity Provider", somewhere users log into, e.g. Okta or Google Apps.
|
||||||
*
|
*
|
||||||
* We also use optional attributes for the user's name, for which we accept any of:
|
* We also use optional attributes for the user's name, for which we accept any of:
|
||||||
* given_name
|
* given_name + family_name
|
||||||
* family_name
|
* name
|
||||||
*
|
*
|
||||||
* Expected environment variables:
|
* Expected environment variables:
|
||||||
* env GRIST_OIDC_SP_HOST=https://<your-domain>
|
* env GRIST_OIDC_SP_HOST=https://<your-domain>
|
||||||
@ -21,6 +21,17 @@
|
|||||||
* The client secret for the application, as registered with the IdP.
|
* The client secret for the application, as registered with the IdP.
|
||||||
* env GRIST_OIDC_IDP_SCOPES
|
* env GRIST_OIDC_IDP_SCOPES
|
||||||
* The scopes to request from the IdP, as a space-separated list. Defaults to "openid email profile".
|
* The scopes to request from the IdP, as a space-separated list. Defaults to "openid email profile".
|
||||||
|
* env GRIST_OIDC_SP_PROFILE_NAME_ATTR
|
||||||
|
* The key of the attribute to use for the user's name.
|
||||||
|
* If omitted, the name will either be the concatenation of "given_name" + "family_name" or the "name" attribute.
|
||||||
|
* env GRIST_OIDC_SP_PROFILE_EMAIL_ATTR
|
||||||
|
* The key of the attribute to use for the user's email. Defaults to "email".
|
||||||
|
* env GRIST_OIDC_IDP_SKIP_END_SESSION_ENDPOINT
|
||||||
|
* If set to "true", on logout, there won't be any attempt to call the IdP's end_session_endpoint
|
||||||
|
* (the user will remain logged in in the IdP).
|
||||||
|
* env GRIST_OIDC_SP_IGNORE_EMAIL_VERIFIED
|
||||||
|
* If set to "true", the user will be allowed to login even if the email is not verified by the IDP.
|
||||||
|
* Defaults to false.
|
||||||
*
|
*
|
||||||
* This version of OIDCConfig has been tested with Keycloak OIDC IdP following the instructions
|
* This version of OIDCConfig has been tested with Keycloak OIDC IdP following the instructions
|
||||||
* at:
|
* at:
|
||||||
@ -43,12 +54,17 @@ import { Sessions } from './Sessions';
|
|||||||
import log from 'app/server/lib/log';
|
import log from 'app/server/lib/log';
|
||||||
import { appSettings } from './AppSettings';
|
import { appSettings } from './AppSettings';
|
||||||
import { RequestWithLogin } from './Authorizer';
|
import { RequestWithLogin } from './Authorizer';
|
||||||
|
import { UserProfile } from 'app/common/LoginSessionAPI';
|
||||||
|
|
||||||
const CALLBACK_URL = '/oauth2/callback';
|
const CALLBACK_URL = '/oauth2/callback';
|
||||||
|
|
||||||
export class OIDCConfig {
|
export class OIDCConfig {
|
||||||
private _client: Client;
|
private _client: Client;
|
||||||
private _redirectUrl: string;
|
private _redirectUrl: string;
|
||||||
|
private _namePropertyKey?: string;
|
||||||
|
private _emailPropertyKey: string;
|
||||||
|
private _skipEndSessionEndpoint: boolean;
|
||||||
|
private _ignoreEmailVerified: boolean;
|
||||||
|
|
||||||
public constructor() {
|
public constructor() {
|
||||||
}
|
}
|
||||||
@ -69,6 +85,24 @@ export class OIDCConfig {
|
|||||||
envVar: 'GRIST_OIDC_IDP_CLIENT_SECRET',
|
envVar: 'GRIST_OIDC_IDP_CLIENT_SECRET',
|
||||||
censor: true,
|
censor: true,
|
||||||
});
|
});
|
||||||
|
this._namePropertyKey = section.flag('namePropertyKey').readString({
|
||||||
|
envVar: 'GRIST_OIDC_SP_PROFILE_NAME_ATTR',
|
||||||
|
});
|
||||||
|
|
||||||
|
this._emailPropertyKey = section.flag('emailPropertyKey').requireString({
|
||||||
|
envVar: 'GRIST_OIDC_SP_PROFILE_EMAIL_ATTR',
|
||||||
|
defaultValue: 'email',
|
||||||
|
});
|
||||||
|
|
||||||
|
this._skipEndSessionEndpoint = section.flag('endSessionEndpoint').readBool({
|
||||||
|
envVar: 'GRIST_OIDC_IDP_SKIP_END_SESSION_ENDPOINT',
|
||||||
|
defaultValue: false,
|
||||||
|
})!;
|
||||||
|
|
||||||
|
this._ignoreEmailVerified = section.flag('ignoreEmailVerified').readBool({
|
||||||
|
envVar: 'GRIST_OIDC_SP_IGNORE_EMAIL_VERIFIED',
|
||||||
|
defaultValue: false,
|
||||||
|
})!;
|
||||||
|
|
||||||
const issuer = await Issuer.discover(issuerUrl);
|
const issuer = await Issuer.discover(issuerUrl);
|
||||||
this._redirectUrl = new URL(CALLBACK_URL, spHost).href;
|
this._redirectUrl = new URL(CALLBACK_URL, spHost).href;
|
||||||
@ -78,6 +112,10 @@ export class OIDCConfig {
|
|||||||
redirect_uris: [ this._redirectUrl ],
|
redirect_uris: [ this._redirectUrl ],
|
||||||
response_types: [ 'code' ],
|
response_types: [ 'code' ],
|
||||||
});
|
});
|
||||||
|
if (this._client.issuer.metadata.end_session_endpoint === undefined && !this._skipEndSessionEndpoint) {
|
||||||
|
throw new Error('The Identity provider does not propose end_session_endpoint. ' +
|
||||||
|
'If that is expected, please set GRIST_OIDC_IDP_SKIP_END_SESSION_ENDPOINT=true');
|
||||||
|
}
|
||||||
log.info(`OIDCConfig: initialized with issuer ${issuerUrl}`);
|
log.info(`OIDCConfig: initialized with issuer ${issuerUrl}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,6 +143,11 @@ export class OIDCConfig {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const userInfo = await this._client.userinfo(tokenSet);
|
const userInfo = await this._client.userinfo(tokenSet);
|
||||||
|
|
||||||
|
if (!this._ignoreEmailVerified && userInfo.email_verified !== true) {
|
||||||
|
throw new Error(`OIDCConfig: email not verified for ${userInfo.email}`);
|
||||||
|
}
|
||||||
|
|
||||||
const profile = this._makeUserProfileFromUserInfo(userInfo);
|
const profile = this._makeUserProfileFromUserInfo(userInfo);
|
||||||
log.info(`OIDCConfig: got OIDC response for ${profile.email} (${profile.name}) redirecting to ${targetUrl}`);
|
log.info(`OIDCConfig: got OIDC response for ${profile.email} (${profile.name}) redirecting to ${targetUrl}`);
|
||||||
|
|
||||||
@ -140,6 +183,10 @@ export class OIDCConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async getLogoutRedirectUrl(req: express.Request, redirectUrl: URL): Promise<string> {
|
public async getLogoutRedirectUrl(req: express.Request, redirectUrl: URL): Promise<string> {
|
||||||
|
// For IdPs that don't have end_session_endpoint, we just redirect to the logout page.
|
||||||
|
if (this._skipEndSessionEndpoint) {
|
||||||
|
return redirectUrl.href;
|
||||||
|
}
|
||||||
return this._client.endSessionUrl({
|
return this._client.endSessionUrl({
|
||||||
post_logout_redirect_uri: redirectUrl.href
|
post_logout_redirect_uri: redirectUrl.href
|
||||||
});
|
});
|
||||||
@ -167,14 +214,21 @@ export class OIDCConfig {
|
|||||||
return codeVerifier;
|
return codeVerifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _makeUserProfileFromUserInfo(userInfo: UserinfoResponse) {
|
private _makeUserProfileFromUserInfo(userInfo: UserinfoResponse): Partial<UserProfile> {
|
||||||
const email = userInfo.email;
|
return {
|
||||||
const fname = userInfo.given_name ?? '';
|
email: String(userInfo[ this._emailPropertyKey ]),
|
||||||
const lname = userInfo.family_name ?? '';
|
name: this._extractName(userInfo)
|
||||||
return {
|
};
|
||||||
email,
|
}
|
||||||
name: `${fname} ${lname}`.trim(),
|
|
||||||
};
|
private _extractName(userInfo: UserinfoResponse): string|undefined {
|
||||||
|
if (this._namePropertyKey) {
|
||||||
|
return (userInfo[ this._namePropertyKey ] as any)?.toString();
|
||||||
|
}
|
||||||
|
const fname = userInfo.given_name ?? '';
|
||||||
|
const lname = userInfo.family_name ?? '';
|
||||||
|
|
||||||
|
return `${fname} ${lname}`.trim() || userInfo.name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +217,13 @@
|
|||||||
"Duplicate Table": "Tabelle duplizieren",
|
"Duplicate Table": "Tabelle duplizieren",
|
||||||
"Raw Data Tables": "Rohdaten-Tabellen",
|
"Raw Data Tables": "Rohdaten-Tabellen",
|
||||||
"Table ID copied to clipboard": "Tabellen-ID in die Zwischenablage kopiert",
|
"Table ID copied to clipboard": "Tabellen-ID in die Zwischenablage kopiert",
|
||||||
"You do not have edit access to this document": "Sie haben keinen Bearbeitungszugriff auf dieses Dokument"
|
"You do not have edit access to this document": "Sie haben keinen Bearbeitungszugriff auf dieses Dokument",
|
||||||
|
"Edit Record Card": "Karteikarte bearbeiten",
|
||||||
|
"Rename Table": "Tabelle umbenennen",
|
||||||
|
"{{action}} Record Card": "{{action}} Karteikarte",
|
||||||
|
"Record Card": "Karteikarte",
|
||||||
|
"Remove Table": "Tabelle entfernen",
|
||||||
|
"Record Card Disabled": "Karteikarte Deaktiviert"
|
||||||
},
|
},
|
||||||
"DocHistory": {
|
"DocHistory": {
|
||||||
"Activity": "Aktivität",
|
"Activity": "Aktivität",
|
||||||
@ -663,7 +669,8 @@
|
|||||||
"Insert row above": "Zeile oben einfügen",
|
"Insert row above": "Zeile oben einfügen",
|
||||||
"Insert row below": "Zeile unten einfügen",
|
"Insert row below": "Zeile unten einfügen",
|
||||||
"Duplicate rows_one": "Zeile duplizieren",
|
"Duplicate rows_one": "Zeile duplizieren",
|
||||||
"Duplicate rows_other": "Zeilen duplizieren"
|
"Duplicate rows_other": "Zeilen duplizieren",
|
||||||
|
"View as card": "Ansicht als Karte"
|
||||||
},
|
},
|
||||||
"SelectionSummary": {
|
"SelectionSummary": {
|
||||||
"Copied to clipboard": "In die Zwischenablage kopiert"
|
"Copied to clipboard": "In die Zwischenablage kopiert"
|
||||||
@ -1295,5 +1302,13 @@
|
|||||||
},
|
},
|
||||||
"searchDropdown": {
|
"searchDropdown": {
|
||||||
"Search": "Suchen"
|
"Search": "Suchen"
|
||||||
|
},
|
||||||
|
"CardContextMenu": {
|
||||||
|
"Insert card above": "Karte oben einfügen",
|
||||||
|
"Duplicate card": "Karte duplizieren",
|
||||||
|
"Insert card below": "Karte unten einfügen",
|
||||||
|
"Delete card": "Karte löschen",
|
||||||
|
"Copy anchor link": "Ankerlink kopieren",
|
||||||
|
"Insert card": "Karte einfügen"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -543,7 +543,8 @@
|
|||||||
"Insert row above": "Insertar fila arriba",
|
"Insert row above": "Insertar fila arriba",
|
||||||
"Insert row below": "Insertar fila debajo",
|
"Insert row below": "Insertar fila debajo",
|
||||||
"Duplicate rows_one": "Duplicar fila",
|
"Duplicate rows_one": "Duplicar fila",
|
||||||
"Duplicate rows_other": "Duplicar filas"
|
"Duplicate rows_other": "Duplicar filas",
|
||||||
|
"View as card": "Ver como tarjeta"
|
||||||
},
|
},
|
||||||
"ShareMenu": {
|
"ShareMenu": {
|
||||||
"Access Details": "Detalles de Acceso",
|
"Access Details": "Detalles de Acceso",
|
||||||
@ -718,7 +719,13 @@
|
|||||||
"Duplicate Table": "Duplicar tabla",
|
"Duplicate Table": "Duplicar tabla",
|
||||||
"Raw Data Tables": "Tablas de datos brutos",
|
"Raw Data Tables": "Tablas de datos brutos",
|
||||||
"Table ID copied to clipboard": "ID de tabla copiado al portapapeles",
|
"Table ID copied to clipboard": "ID de tabla copiado al portapapeles",
|
||||||
"Click to copy": "Haga clic para copiar"
|
"Click to copy": "Haga clic para copiar",
|
||||||
|
"Edit Record Card": "Editar la ficha del registro",
|
||||||
|
"Rename Table": "Cambiar el nombre de la tabla",
|
||||||
|
"{{action}} Record Card": "{{action}} Ficha",
|
||||||
|
"Record Card": "Ficha de registro",
|
||||||
|
"Remove Table": "Quitar la tabla",
|
||||||
|
"Record Card Disabled": "Tarjeta de registro desactivada"
|
||||||
},
|
},
|
||||||
"DocPageModel": {
|
"DocPageModel": {
|
||||||
"Add Empty Table": "Agregar tabla vacía",
|
"Add Empty Table": "Agregar tabla vacía",
|
||||||
@ -1285,5 +1292,13 @@
|
|||||||
"FloatingPopup": {
|
"FloatingPopup": {
|
||||||
"Maximize": "Maximizar",
|
"Maximize": "Maximizar",
|
||||||
"Minimize": "Minimizar"
|
"Minimize": "Minimizar"
|
||||||
|
},
|
||||||
|
"CardContextMenu": {
|
||||||
|
"Insert card above": "Inserte la tarjeta arriba",
|
||||||
|
"Duplicate card": "Tarjeta duplicada",
|
||||||
|
"Insert card below": "Inserte la tarjeta a continuación",
|
||||||
|
"Delete card": "Borrar la tarjeta",
|
||||||
|
"Copy anchor link": "Copiar enlace fijado",
|
||||||
|
"Insert card": "Insertar la tarjeta"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,7 +217,13 @@
|
|||||||
"Duplicate Table": "Duplicar a Tabela",
|
"Duplicate Table": "Duplicar a Tabela",
|
||||||
"Raw Data Tables": "Tabelas de Dados Primários",
|
"Raw Data Tables": "Tabelas de Dados Primários",
|
||||||
"Table ID copied to clipboard": "ID da Tabela copiada para a área de transferência",
|
"Table ID copied to clipboard": "ID da Tabela copiada para a área de transferência",
|
||||||
"You do not have edit access to this document": "Você não tem permissão de edição desse documento"
|
"You do not have edit access to this document": "Você não tem permissão de edição desse documento",
|
||||||
|
"Edit Record Card": "Editar cartão de registro",
|
||||||
|
"Rename Table": "Renomear tabela",
|
||||||
|
"{{action}} Record Card": "{{action}} Cartão de registro",
|
||||||
|
"Record Card": "Cartão de registro",
|
||||||
|
"Remove Table": "Remover tabela",
|
||||||
|
"Record Card Disabled": "Cartão de registro desabilitado"
|
||||||
},
|
},
|
||||||
"DocHistory": {
|
"DocHistory": {
|
||||||
"Activity": "Atividade",
|
"Activity": "Atividade",
|
||||||
@ -663,7 +669,8 @@
|
|||||||
"Insert row above": "Inserir linha acima",
|
"Insert row above": "Inserir linha acima",
|
||||||
"Insert row below": "Inserir linha abaixo",
|
"Insert row below": "Inserir linha abaixo",
|
||||||
"Duplicate rows_one": "Duplicar linha",
|
"Duplicate rows_one": "Duplicar linha",
|
||||||
"Duplicate rows_other": "Duplicar linhas"
|
"Duplicate rows_other": "Duplicar linhas",
|
||||||
|
"View as card": "Ver como cartão"
|
||||||
},
|
},
|
||||||
"SelectionSummary": {
|
"SelectionSummary": {
|
||||||
"Copied to clipboard": "Copiado para a área de transferência"
|
"Copied to clipboard": "Copiado para a área de transferência"
|
||||||
@ -1295,5 +1302,13 @@
|
|||||||
"FloatingPopup": {
|
"FloatingPopup": {
|
||||||
"Maximize": "Maximizar",
|
"Maximize": "Maximizar",
|
||||||
"Minimize": "Minimizar"
|
"Minimize": "Minimizar"
|
||||||
|
},
|
||||||
|
"CardContextMenu": {
|
||||||
|
"Insert card above": "Inserir cartão acima",
|
||||||
|
"Duplicate card": "Duplicar o cartão",
|
||||||
|
"Insert card below": "Inserir cartão abaixo",
|
||||||
|
"Delete card": "Excluir cartão",
|
||||||
|
"Copy anchor link": "Copiar link de ancoragem",
|
||||||
|
"Insert card": "Inserir cartão"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -334,7 +334,13 @@
|
|||||||
"Duplicate Table": "Дублировать таблицу",
|
"Duplicate Table": "Дублировать таблицу",
|
||||||
"Table ID copied to clipboard": "Идентификатор таблицы скопирован в буфер обмена",
|
"Table ID copied to clipboard": "Идентификатор таблицы скопирован в буфер обмена",
|
||||||
"You do not have edit access to this document": "У вас нет доступа к редактированию этого документа",
|
"You do not have edit access to this document": "У вас нет доступа к редактированию этого документа",
|
||||||
"Delete {{formattedTableName}} data, and remove it from all pages?": "Удалить {{formattedTableName}} данные, и удалить их со всех страниц?"
|
"Delete {{formattedTableName}} data, and remove it from all pages?": "Удалить {{formattedTableName}} данные, и удалить их со всех страниц?",
|
||||||
|
"Edit Record Card": "Редактировать карточку записи",
|
||||||
|
"Rename Table": "Переименовать Таблицу",
|
||||||
|
"{{action}} Record Card": "{{action}} Карточка записи",
|
||||||
|
"Record Card": "Карточка записи",
|
||||||
|
"Remove Table": "Удалить Таблицу",
|
||||||
|
"Record Card Disabled": "Карточка записи отключена"
|
||||||
},
|
},
|
||||||
"DocHistory": {
|
"DocHistory": {
|
||||||
"Snapshots": "Снимки",
|
"Snapshots": "Снимки",
|
||||||
@ -603,7 +609,8 @@
|
|||||||
"Insert row below": "Вставить строку ниже",
|
"Insert row below": "Вставить строку ниже",
|
||||||
"Insert row": "Вставить строку",
|
"Insert row": "Вставить строку",
|
||||||
"Insert row above": "Вставить строку выше",
|
"Insert row above": "Вставить строку выше",
|
||||||
"Delete": "Удалить"
|
"Delete": "Удалить",
|
||||||
|
"View as card": "Посмотреть как карточку"
|
||||||
},
|
},
|
||||||
"RecordLayout": {
|
"RecordLayout": {
|
||||||
"Updating record layout.": "Обновление макета записи."
|
"Updating record layout.": "Обновление макета записи."
|
||||||
@ -1231,5 +1238,13 @@
|
|||||||
"FloatingPopup": {
|
"FloatingPopup": {
|
||||||
"Maximize": "Максимизировать",
|
"Maximize": "Максимизировать",
|
||||||
"Minimize": "Минимизировать"
|
"Minimize": "Минимизировать"
|
||||||
|
},
|
||||||
|
"CardContextMenu": {
|
||||||
|
"Insert card above": "Вставить карточку выше",
|
||||||
|
"Duplicate card": "Дублировать карточку",
|
||||||
|
"Insert card below": "Вставить карточку ниже",
|
||||||
|
"Delete card": "Удалить карточку",
|
||||||
|
"Copy anchor link": "Скопировать якорную ссылку",
|
||||||
|
"Insert card": "Вставить карточку"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@
|
|||||||
"Deleted {{at}}": "Izbrisano {{at}}",
|
"Deleted {{at}}": "Izbrisano {{at}}",
|
||||||
"Delete {{name}}": "Izbriši {{name}}",
|
"Delete {{name}}": "Izbriši {{name}}",
|
||||||
"Document will be permanently deleted.": "Dokument bo trajno izbrisan.",
|
"Document will be permanently deleted.": "Dokument bo trajno izbrisan.",
|
||||||
"Permanently Delete \"{{name}}\"?": "Trajno izbrisati \"{{name}}\"?",
|
"Permanently Delete \"{{name}}\"?": "Trajno izbrišem \"{{name}}\"?",
|
||||||
"(The organization needs a paid plan)": "(Organizacija potrebuje plačljiv načrt)",
|
"(The organization needs a paid plan)": "(Organizacija potrebuje plačljiv načrt)",
|
||||||
"Access Details": "Podrobnosti o dostopu",
|
"Access Details": "Podrobnosti o dostopu",
|
||||||
"All Documents": "Vsi dokumenti",
|
"All Documents": "Vsi dokumenti",
|
||||||
@ -168,7 +168,7 @@
|
|||||||
"Requires edit permissions": "Zahteva dovoljenja za urejanje",
|
"Requires edit permissions": "Zahteva dovoljenja za urejanje",
|
||||||
"Other Sites": "Druga spletna mesta",
|
"Other Sites": "Druga spletna mesta",
|
||||||
"Pinned Documents": "Pripeti dokumenti",
|
"Pinned Documents": "Pripeti dokumenti",
|
||||||
"To restore this document, restore the workspace first.": "Če želite obnoviti ta dokument, najprej obnovite delovni prostor.",
|
"To restore this document, restore the workspace first.": "Če želiš obnoviti ta dokument, najprej obnovi delovni prostor.",
|
||||||
"You are on your personal site. You also have access to the following sites:": "Nahajate se na svojem osebnem spletnem mestu. Prav tako imate dostop do naslednjih spletnih mest:",
|
"You are on your personal site. You also have access to the following sites:": "Nahajate se na svojem osebnem spletnem mestu. Prav tako imate dostop do naslednjih spletnih mest:",
|
||||||
"Restore": "Obnovi",
|
"Restore": "Obnovi",
|
||||||
"Move {{name}} to workspace": "Premakni {{name}} v delovni prostor",
|
"Move {{name}} to workspace": "Premakni {{name}} v delovni prostor",
|
||||||
@ -260,7 +260,8 @@
|
|||||||
"Copy anchor link": "Kopiraj sidrno povezavo",
|
"Copy anchor link": "Kopiraj sidrno povezavo",
|
||||||
"Duplicate rows_one": "Podvoji vrstico",
|
"Duplicate rows_one": "Podvoji vrstico",
|
||||||
"Duplicate rows_other": "Podvoji vrstice",
|
"Duplicate rows_other": "Podvoji vrstice",
|
||||||
"Insert row above": "Vstavi vrstico zgoraj"
|
"Insert row above": "Vstavi vrstico zgoraj",
|
||||||
|
"View as card": "Kartični pogled"
|
||||||
},
|
},
|
||||||
"Tools": {
|
"Tools": {
|
||||||
"Delete": "Izbriši",
|
"Delete": "Izbriši",
|
||||||
@ -298,7 +299,13 @@
|
|||||||
"Duplicate Table": "Podvojena tabela",
|
"Duplicate Table": "Podvojena tabela",
|
||||||
"Table ID copied to clipboard": "ID tabele kopiran v odložišče",
|
"Table ID copied to clipboard": "ID tabele kopiran v odložišče",
|
||||||
"You do not have edit access to this document": "Nimate dostopa za urejanje tega dokumenta",
|
"You do not have edit access to this document": "Nimate dostopa za urejanje tega dokumenta",
|
||||||
"Raw Data Tables": "Neobdelana tabela"
|
"Raw Data Tables": "Neobdelana tabela",
|
||||||
|
"Edit Record Card": "Uredi evidenčno kartico",
|
||||||
|
"Rename Table": "Preimenuj Tabelo",
|
||||||
|
"{{action}} Record Card": "{{action}} Evidenčno Kartico",
|
||||||
|
"Record Card": "Evidenčna kartica",
|
||||||
|
"Remove Table": "Odstrani Tabelo",
|
||||||
|
"Record Card Disabled": "Evidenčna kartica onemogočena"
|
||||||
},
|
},
|
||||||
"ViewLayoutMenu": {
|
"ViewLayoutMenu": {
|
||||||
"Delete record": "Brisanje zapisa",
|
"Delete record": "Brisanje zapisa",
|
||||||
@ -590,7 +597,7 @@
|
|||||||
"Organization": "Organizacija",
|
"Organization": "Organizacija",
|
||||||
"Replacing the original requires editing rights on the original document.": "Za zamenjavo izvirnika so potrebne pravice za urejanje izvirnega dokumenta.",
|
"Replacing the original requires editing rights on the original document.": "Za zamenjavo izvirnika so potrebne pravice za urejanje izvirnega dokumenta.",
|
||||||
"Remove document history (can significantly reduce file size)": "Odstranitev zgodovine dokumenta (lahko znatno zmanjša velikost datoteke)",
|
"Remove document history (can significantly reduce file size)": "Odstranitev zgodovine dokumenta (lahko znatno zmanjša velikost datoteke)",
|
||||||
"To save your changes, please sign up, then reload this page.": "Če želite shraniti spremembe, se prijavite in nato ponovno naložite to stran.",
|
"To save your changes, please sign up, then reload this page.": "Če želiš shraniti spremembe, se prijavi in nato ponovno naloži to stran.",
|
||||||
"The original version of this document will be updated.": "Prvotna različica tega dokumenta bo posodobljena.",
|
"The original version of this document will be updated.": "Prvotna različica tega dokumenta bo posodobljena.",
|
||||||
"However, it appears to be already identical.": "Vendar se zdi, da je že identična.",
|
"However, it appears to be already identical.": "Vendar se zdi, da je že identična.",
|
||||||
"Update Original": "Posodobitev izvirnika",
|
"Update Original": "Posodobitev izvirnika",
|
||||||
@ -642,7 +649,7 @@
|
|||||||
"Access rules give you the power to create nuanced rules to determine who can see or edit which parts of your document.": "Pravila dostopa vam omogočajo, da ustvarite podrobna pravila, s katerimi določite, kdo lahko vidi ali ureja posamezne dele dokumenta.",
|
"Access rules give you the power to create nuanced rules to determine who can see or edit which parts of your document.": "Pravila dostopa vam omogočajo, da ustvarite podrobna pravila, s katerimi določite, kdo lahko vidi ali ureja posamezne dele dokumenta.",
|
||||||
"Rearrange the fields in your card by dragging and resizing cells.": "Z vlečenjem in spreminjanjem velikosti polj na kartici spremenite njihovo razporeditev.",
|
"Rearrange the fields in your card by dragging and resizing cells.": "Z vlečenjem in spreminjanjem velikosti polj na kartici spremenite njihovo razporeditev.",
|
||||||
"Useful for storing the timestamp or author of a new record, data cleaning, and more.": "Uporabno za shranjevanje časovnega žiga ali avtorja novega zapisa, čiščenje podatkov in drugo.",
|
"Useful for storing the timestamp or author of a new record, data cleaning, and more.": "Uporabno za shranjevanje časovnega žiga ali avtorja novega zapisa, čiščenje podatkov in drugo.",
|
||||||
"Click the Add New button to create new documents or workspaces, or import data.": "Če želite ustvariti nove dokumente ali delovne prostore ali uvoziti podatke, kliknite gumb Dodaj.",
|
"Click the Add New button to create new documents or workspaces, or import data.": "Klikni gumb dodaj novega, če želiš ustvariti nove dokumente, delovne prostore ali uvoziti podatke,",
|
||||||
"Nested Filtering": "Vgnezdeno filtriranje",
|
"Nested Filtering": "Vgnezdeno filtriranje",
|
||||||
"Only those rows will appear which match all of the filters.": "Prikazane bodo samo tiste vrstice, ki ustrezajo vsem filtrom.",
|
"Only those rows will appear which match all of the filters.": "Prikazane bodo samo tiste vrstice, ki ustrezajo vsem filtrom.",
|
||||||
"Editing Card Layout": "Urejanje postavitve kartice",
|
"Editing Card Layout": "Urejanje postavitve kartice",
|
||||||
@ -655,11 +662,11 @@
|
|||||||
"They allow for one record to point (or refer) to another.": "Omogočajo, da en zapis kaže (ali se sklicuje) na drugega.",
|
"They allow for one record to point (or refer) to another.": "Omogočajo, da en zapis kaže (ali se sklicuje) na drugega.",
|
||||||
"Reference Columns": "Referenčni stolpci",
|
"Reference Columns": "Referenčni stolpci",
|
||||||
"To configure your calendar, select columns for start": {
|
"To configure your calendar, select columns for start": {
|
||||||
"end dates and event titles. Note each column's type.": "Če želite konfigurirati svoj koledar, izberite stolpce za začetne/končne datume in naslove dogodkov. Upoštevajte vrsto vsakega stolpca."
|
"end dates and event titles. Note each column's type.": "Če želiš konfigurirati svoj koledar, izberi stolpce za začetne/končne datume in naslove dogodkov. Upoštevaj vrsto vsakega stolpca."
|
||||||
},
|
},
|
||||||
"Calendar": "Koledar",
|
"Calendar": "Koledar",
|
||||||
"Apply conditional formatting to cells in this column when formula conditions are met.": "Uporabi pogojno oblikovanje za celice v tem stolpcu, ko so izpolnjeni pogoji formule.",
|
"Apply conditional formatting to cells in this column when formula conditions are met.": "Uporabi pogojno oblikovanje za celice v tem stolpcu, ko so izpolnjeni pogoji formule.",
|
||||||
"To make an anchor link that takes the user to a specific cell, click on a row and press {{shortcut}}.": "Če želite narediti sidrno povezavo, ki uporabnika pripelje do določene celice, kliknite vrstico in pritisnite {{shortcut}}.",
|
"To make an anchor link that takes the user to a specific cell, click on a row and press {{shortcut}}.": "Če želiš narediti sidrno povezavo, ki uporabnika pripelje do določene celice, klikni vrstico in pritisni {{shortcut}}.",
|
||||||
"Unpin to hide the the button while keeping the filter.": "Odpnite, da skrijete gumb in obdržite filter.",
|
"Unpin to hide the the button while keeping the filter.": "Odpnite, da skrijete gumb in obdržite filter.",
|
||||||
"Apply conditional formatting to rows based on formulas.": "Uporabi pogojno oblikovanje za vrstice na podlagi formul.",
|
"Apply conditional formatting to rows based on formulas.": "Uporabi pogojno oblikovanje za vrstice na podlagi formul.",
|
||||||
"Click on “Open row styles” to apply conditional formatting to rows.": "Klikni »Odpri sloge vrstic«, da za vrstice uporabiš pogojno oblikovanje.",
|
"Click on “Open row styles” to apply conditional formatting to rows.": "Klikni »Odpri sloge vrstic«, da za vrstice uporabiš pogojno oblikovanje.",
|
||||||
@ -707,14 +714,14 @@
|
|||||||
"Close": "Zapri",
|
"Close": "Zapri",
|
||||||
"Allow anyone with the link to open.": "Omogočite odprtje vsakomur, ki ima povezavo.",
|
"Allow anyone with the link to open.": "Omogočite odprtje vsakomur, ki ima povezavo.",
|
||||||
"Invite people to {{resourceType}}": "Povabite ljudi k {{resourceType}}",
|
"Invite people to {{resourceType}}": "Povabite ljudi k {{resourceType}}",
|
||||||
"Public access inherited from {{parent}}. To remove, set 'Inherit access' option to 'None'.": "Uporabnik podeduje dovoljenja od {{parent}}. Če jih želite odstraniti, nastavite možnost \"Podeduje dostop\" na \"Ne\".",
|
"Public access inherited from {{parent}}. To remove, set 'Inherit access' option to 'None'.": "Uporabnik podeduje dovoljenja od {{parent}}. Če jih želiš odstraniti, nastavi možnost \"Podeduje dostop\" na \"Ne\".",
|
||||||
"Remove my access": "Odstranitev mojega dostopa",
|
"Remove my access": "Odstranitev mojega dostopa",
|
||||||
"Public access": "Javni dostop",
|
"Public access": "Javni dostop",
|
||||||
"Public Access": "Javni dostop",
|
"Public Access": "Javni dostop",
|
||||||
"Cancel": "Prekliči",
|
"Cancel": "Prekliči",
|
||||||
"Grist support": "Grist podpora",
|
"Grist support": "Grist podpora",
|
||||||
"You are about to remove your own access to this {{resourceType}}": "Odstranili boste svoj dostop do tega {{resourceType}}",
|
"You are about to remove your own access to this {{resourceType}}": "Odstranili boste svoj dostop do tega {{resourceType}}",
|
||||||
"User inherits permissions from {{parent}}. To remove, set 'Inherit access' option to 'None'.": "Uporabnik podeduje dovoljenja od {{parent}}. Če jih želite odstraniti, nastavite možnost \"Podeduje dostop\" na \"Ni\".",
|
"User inherits permissions from {{parent}}. To remove, set 'Inherit access' option to 'None'.": "Uporabnik podeduje dovoljenja od {{parent}}. Če jih želiš odstraniti, nastavi možnost \"Podeduje dostop\" na \"Ni\".",
|
||||||
"Guest": "Gost",
|
"Guest": "Gost",
|
||||||
"Invite multiple": "Povabite več",
|
"Invite multiple": "Povabite več",
|
||||||
"Confirm": "Potrdite",
|
"Confirm": "Potrdite",
|
||||||
@ -813,7 +820,7 @@
|
|||||||
"Welcome to Grist!": "Dobrodošli v Gristu!",
|
"Welcome to Grist!": "Dobrodošli v Gristu!",
|
||||||
"Visit our {{link}} to learn more about Grist.": "Obiščite našo spletno stran {{link}} da izveste več o Grisstu.",
|
"Visit our {{link}} to learn more about Grist.": "Obiščite našo spletno stran {{link}} da izveste več o Grisstu.",
|
||||||
"Sign in": "Prijavi se",
|
"Sign in": "Prijavi se",
|
||||||
"To use Grist, please either sign up or sign in.": "Če želite uporabljati Grist, se prijavite ali prvič prijavite."
|
"To use Grist, please either sign up or sign in.": "Če želiš uporabljati Grist, se prijavi ali prvič prijavi."
|
||||||
},
|
},
|
||||||
"WelcomeSitePicker": {
|
"WelcomeSitePicker": {
|
||||||
"You have access to the following Grist sites.": "Imate dostop do naslednjih Grist spletnih mest .",
|
"You have access to the following Grist sites.": "Imate dostop do naslednjih Grist spletnih mest .",
|
||||||
@ -1231,5 +1238,13 @@
|
|||||||
},
|
},
|
||||||
"sendToDrive": {
|
"sendToDrive": {
|
||||||
"Sending file to Google Drive": "Pošiljanje datoteke v Google Drive"
|
"Sending file to Google Drive": "Pošiljanje datoteke v Google Drive"
|
||||||
|
},
|
||||||
|
"CardContextMenu": {
|
||||||
|
"Insert card above": "Vstavi kartico zgoraj",
|
||||||
|
"Duplicate card": "Podvoji kartico",
|
||||||
|
"Insert card below": "Vstavi kartico spodaj",
|
||||||
|
"Delete card": "Briši kartico",
|
||||||
|
"Copy anchor link": "Kopiraj sidrno povezavo",
|
||||||
|
"Insert card": "Vstavi kartico"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user