(core) updates from grist-core

pull/1157/head
Paul Fitzpatrick 1 month ago
commit 773588f795

@ -0,0 +1,52 @@
# Inspired by PeerTube templates:
# https://github.com/Chocobozzz/PeerTube/blob/3d4d49a23eae71f3ce62cbbd7d93f07336a106b7/.github/ISSUE_TEMPLATE/00-bug-issue.yml
name: 🐛 Bug Report
description: Use this template for reporting a bug
body:
- type: markdown
attributes:
value: |
Thanks for taking time to fill out this bug report!
Please search among past open/closed issues for a similar one beforehand:
- https://github.com/gristlabs/grist-core/issues?q=
- https://community.getgrist.com/
- type: textarea
attributes:
label: Describe the current behavior
- type: textarea
attributes:
label: Steps to reproduce
value: |
1.
2.
3.
- type: textarea
attributes:
label: Describe the expected behavior
- type: checkboxes
attributes:
label: Where have you encountered this bug?
options:
- label: On [docs.getgrist.com](https://docs.getgrist.com)
- label: On a self-hosted instance
validations:
required: true
- type: textarea
attributes:
label: Instance information (when self-hosting only)
description: In case you self-host, please share information above. You can discard any question you don't know the answer.
value: |
* Grist instance:
* Version:
* URL (if it's OK for you to share it):
* Installation mode: docker/kubernetes/...
* Architecture: single-worker/multi-workers
* Browser name, version and platforms on which you could reproduce the bug:
* Link to browser console log if relevant:
* Link to server log if relevant:

@ -0,0 +1,33 @@
# Inspired by PeerTube templates:
# https://github.com/Chocobozzz/PeerTube/blob/master/.github/ISSUE_TEMPLATE/10-installation-issue.yml
name: 🛠️ Installation/Upgrade Issue
description: Use this template for installation/upgrade issues
body:
- type: markdown
attributes:
value: |
Please check first the official documentation for self-hosting: https://support.getgrist.com/self-managed/
- type: markdown
attributes:
value: |
Please search among past open/closed issues for a similar one beforehand:
- https://github.com/gristlabs/grist-core/issues?q=
- https://community.getgrist.com/
- type: textarea
attributes:
label: Describe the problem
- type: textarea
attributes:
label: Additional information
value: |
* Grist version:
* Grist instance URL:
* SSO solution used and its version (if relevant):
* S3 storage solution and its version (if relevant):
* Docker version (if relevant):
* NodeJS version (if relevant):
* Redis version (if relevant):
* PostgreSQL version (if relevant):

@ -0,0 +1,23 @@
# Inspired by PeerTube templates:
# https://github.com/Chocobozzz/PeerTube/blob/master/.github/ISSUE_TEMPLATE/30-feature-request.yml
---
name: ✨ Feature Request
description: Use this template to ask for new features and suggest new ideas 💡
body:
- type: markdown
attributes:
value: |
Thanks for taking time to share your ideas!
Please search among past open/closed issues for a similar one beforehand:
- https://github.com/gristlabs/grist-core/issues?q=
- https://community.getgrist.com/
- type: textarea
attributes:
label: Describe the problem to be solved
description: Provide a clear and concise description of what the problem is
- type: textarea
attributes:
label: Describe the solution you would like
description: Provide a clear and concise description of what you want to happen

@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: 🤷💻🤦 Question/Forum
url: https://community.getgrist.com/
about: You can ask and answer other questions here
- name: 💬 Discord
url: https://discord.com/invite/MYKpYQ3fbP
about: Chat with us via Discord for quick Q/A here and sharing tips

@ -0,0 +1,27 @@
## Context
<!-- Please include a summary of the change, with motivation and context -->
<!-- Bonus: if you are comfortable writing one, please insert a user-story https://en.wikipedia.org/wiki/User_story#Common_templates -->
## Proposed solution
<!-- Describe here how you address the issue -->
## Related issues
<!-- If suggesting a new feature or change, please discuss it in an issue first -->
<!-- If fixing a bug, there should be an issue describing it with steps to reproduce -->
<!-- If this does not solve entirely the issue, make also a checklist of what is done or not: -->
## Has this been tested?
<!-- Put an `x` in the box that applies: -->
- [ ] 👍 yes, I added tests to the test suite
- [ ] 💭 no, because this PR is a draft and still needs work
- [ ] 🙅 no, because this is not relevant here
- [ ] 🙋 no, because I need help <!-- Detail how we can help you -->
## Screenshots / Screencasts
<!-- delete if not relevant -->

@ -4,13 +4,13 @@
## docker buildx build -t ... --build-context=ext=<path> .
## The code in <path> will then be built along with the rest of Grist.
################################################################################
FROM scratch as ext
FROM scratch AS ext
################################################################################
## Javascript build stage
################################################################################
FROM node:18-buster as builder
FROM node:18-buster AS builder
# Install all node dependencies.
WORKDIR /grist
@ -46,7 +46,7 @@ RUN \
################################################################################
# Fetch python3.11 and python2.7
FROM python:3.11-slim-buster as collector
FROM python:3.11-slim-buster AS collector
# Install all python dependencies.
ADD sandbox/requirements.txt requirements.txt
@ -66,7 +66,7 @@ RUN \
# Fetch gvisor-based sandbox. Note, to enable it to run within default
# unprivileged docker, layers of protection that require privilege have
# been stripped away, see https://github.com/google/gvisor/issues/4371
FROM docker.io/gristlabs/gvisor-unprivileged:buster as sandbox
FROM docker.io/gristlabs/gvisor-unprivileged:buster AS sandbox
################################################################################
## Run-time stage

@ -125,9 +125,9 @@ the standard Grist functionality, as well as extra source-available
code for enterprise customers taken from the
[grist-ee](https://github.com/gristlabs/grist-ee) repository. This
extra code is not under a free or open source license. By default,
however, the code from the `grist-ee` repository is completely inert and
inactive. This code becomes active only when an administrator enables
it by setting either `GRIST_ACTIVATION` or `GRIST_ACTIVATION_FILE`.
however, the code from the `grist-ee` repository is completely inert
and inactive. This code becomes active only when enabled from the
administrator panel.
If you would rather use an image that contains exclusively free and
open source code, the `gristlabs/grist-oss` Docker image is available

@ -0,0 +1,29 @@
import { sanitizeHTML } from 'app/client/ui/sanitizeHTML';
import { BindableValue, DomElementMethod, subscribeElem } from 'grainjs';
import { marked } from 'marked';
/**
* Helper function for using Markdown in grainjs elements. It accepts
* both plain Markdown strings, as well as methods that use an observable.
* Example usage:
*
* cssSection(markdown(t(`# New Markdown Function
*
* We can _write_ [the usual Markdown](https://markdownguide.org) *inside*
* a Grainjs element.`)));
*
* or
*
* cssSection(markdown(use => use(toggle) ? t('The toggle is **on**') : t('The toggle is **off**'));
*
* Markdown strings are easier for our translators to handle, as it's possible
* to include all of the context around a single markdown string without
* breaking it up into separate strings for grainjs elements.
*/
export function markdown(markdownObs: BindableValue<string>): DomElementMethod {
return elem => subscribeElem(elem, markdownObs, value => setMarkdownValue(elem, value));
}
function setMarkdownValue(elem: Element, markdownValue: string): void {
elem.innerHTML = sanitizeHTML(marked(markdownValue));
}

@ -0,0 +1,44 @@
import {getHomeUrl} from 'app/client/models/AppModel';
import {Disposable, Observable} from "grainjs";
import {ConfigAPI} from 'app/common/ConfigAPI';
import {delay} from 'app/common/delay';
export class ToggleEnterpriseModel extends Disposable {
public readonly edition: Observable<string | null> = Observable.create(this, null);
private readonly _configAPI: ConfigAPI = new ConfigAPI(getHomeUrl());
public async fetchEnterpriseToggle(): Promise<void> {
const edition = await this._configAPI.getValue('edition');
this.edition.set(edition);
}
public async updateEnterpriseToggle(edition: string): Promise<void> {
// We may be restarting the server, so these requests may well
// fail if done in quick succession.
await retryOnNetworkError(() => this._configAPI.setValue({edition}));
this.edition.set(edition);
await retryOnNetworkError(() => this._configAPI.restartServer());
}
}
// Copied from DocPageModel.ts
const reconnectIntervals = [1000, 1000, 2000, 5000, 10000];
async function retryOnNetworkError<R>(func: () => Promise<R>): Promise<R> {
for (let attempt = 0; ; attempt++) {
try {
return await func();
} catch (err) {
// fetch() promises that network errors are reported as TypeError. We'll accept NetworkError too.
if (err.name !== "TypeError" && err.name !== "NetworkError") {
throw err;
}
// We really can't reach the server. Make it known.
if (attempt >= reconnectIntervals.length) {
throw err;
}
const reconnectTimeout = reconnectIntervals[attempt];
console.warn(`Call to ${func.name} failed, will retry in ${reconnectTimeout} ms`, err);
await delay(reconnectTimeout);
}
}
}

@ -9,6 +9,7 @@ import {AppHeader} from 'app/client/ui/AppHeader';
import {leftPanelBasic} from 'app/client/ui/LeftPanelCommon';
import {pagePanels} from 'app/client/ui/PagePanels';
import {SupportGristPage} from 'app/client/ui/SupportGristPage';
import {ToggleEnterpriseWidget} from 'app/client/ui/ToggleEnterpriseWidget';
import {createTopBarHome} from 'app/client/ui/TopBar';
import {cssBreadcrumbs, separator} from 'app/client/ui2018/breadcrumbs';
import {basicButton} from 'app/client/ui2018/buttons';
@ -25,7 +26,6 @@ import {Computed, Disposable, dom, IDisposable,
IDisposableOwner, MultiHolder, Observable, styled} from 'grainjs';
import {AdminSection, AdminSectionItem, HidableToggle} from 'app/client/ui/AdminPanelCss';
const t = makeT('AdminPanel');
// Translated "Admin Panel" name, made available to other modules.
@ -35,6 +35,7 @@ export function getAdminPanelName() {
export class AdminPanel extends Disposable {
private _supportGrist = SupportGristPage.create(this, this._appModel);
private _toggleEnterprise = ToggleEnterpriseWidget.create(this);
private readonly _installAPI: InstallAPI = new InstallAPIImpl(getHomeUrl());
private _checks: AdminChecks;
@ -161,6 +162,13 @@ Please log in as an administrator.`)),
description: t('Current version of Grist'),
value: cssValueLabel(`Version ${version.version}`),
}),
dom.create(AdminSectionItem, {
id: 'enterprise',
name: t('Enterprise'),
description: t('Enable Grist Enterprise'),
value: dom.create(HidableToggle, this._toggleEnterprise.getEnterpriseToggleObservable()),
expandedContent: this._toggleEnterprise.buildEnterpriseSection(),
}),
this._buildUpdates(owner),
]),
dom.create(AdminSection, t('Self Checks'), [

@ -0,0 +1,45 @@
import {bigBasicButton, bigBasicButtonLink, bigPrimaryButton} from 'app/client/ui2018/buttons';
import {theme} from 'app/client/ui2018/cssVars';
import {styled} from 'grainjs';
export const cssSection = styled('div', ``);
export const cssParagraph = styled('div', `
color: ${theme.text};
font-size: 14px;
line-height: 20px;
margin-bottom: 12px;
`);
export const cssOptInOutMessage = styled(cssParagraph, `
line-height: 40px;
font-weight: 600;
margin-top: 24px;
margin-bottom: 0px;
`);
export const cssOptInButton = styled(bigPrimaryButton, `
margin-top: 24px;
`);
export const cssOptOutButton = styled(bigBasicButton, `
margin-top: 24px;
`);
export const cssSponsorButton = styled(bigBasicButtonLink, `
margin-top: 24px;
`);
export const cssButtonIconAndText = styled('div', `
display: flex;
align-items: center;
`);
export const cssButtonText = styled('span', `
margin-left: 8px;
`);
export const cssSpinnerBox = styled('div', `
margin-top: 24px;
text-align: center;
`);

@ -1,14 +1,24 @@
import {makeT} from 'app/client/lib/localization';
import {AppModel} from 'app/client/models/AppModel';
import {TelemetryModel, TelemetryModelImpl} from 'app/client/models/TelemetryModel';
import {basicButtonLink, bigBasicButton, bigBasicButtonLink, bigPrimaryButton} from 'app/client/ui2018/buttons';
import {theme} from 'app/client/ui2018/cssVars';
import {
cssButtonIconAndText,
cssButtonText,
cssOptInButton,
cssOptInOutMessage,
cssOptOutButton,
cssParagraph,
cssSection,
cssSpinnerBox,
cssSponsorButton,
} from 'app/client/ui/AdminTogglesCss';
import {basicButtonLink} from 'app/client/ui2018/buttons';
import {icon} from 'app/client/ui2018/icons';
import {cssLink} from 'app/client/ui2018/links';
import {loadingSpinner} from 'app/client/ui2018/loaders';
import {commonUrls} from 'app/common/gristUrls';
import {TelemetryPrefsWithSources} from 'app/common/InstallAPI';
import {Computed, Disposable, dom, makeTestId, styled} from 'grainjs';
import {Computed, Disposable, dom, makeTestId} from 'grainjs';
const testId = makeTestId('test-support-grist-page-');
@ -164,45 +174,3 @@ function gristCoreLink() {
{href: commonUrls.githubGristCore, target: '_blank'},
);
}
const cssSection = styled('div', ``);
const cssParagraph = styled('div', `
color: ${theme.text};
font-size: 14px;
line-height: 20px;
margin-bottom: 12px;
`);
const cssOptInOutMessage = styled(cssParagraph, `
line-height: 40px;
font-weight: 600;
margin-top: 24px;
margin-bottom: 0px;
`);
const cssOptInButton = styled(bigPrimaryButton, `
margin-top: 24px;
`);
const cssOptOutButton = styled(bigBasicButton, `
margin-top: 24px;
`);
const cssSponsorButton = styled(bigBasicButtonLink, `
margin-top: 24px;
`);
const cssButtonIconAndText = styled('div', `
display: flex;
align-items: center;
`);
const cssButtonText = styled('span', `
margin-left: 8px;
`);
const cssSpinnerBox = styled('div', `
margin-top: 24px;
text-align: center;
`);

@ -0,0 +1,78 @@
import {makeT} from 'app/client/lib/localization';
import {markdown} from 'app/client/lib/markdown';
import {Computed, Disposable, dom, makeTestId} from "grainjs";
import {commonUrls} from "app/common/gristUrls";
import {ToggleEnterpriseModel} from 'app/client/models/ToggleEnterpriseModel';
import {
cssOptInButton,
cssOptOutButton,
cssParagraph,
cssSection,
} from 'app/client/ui/AdminTogglesCss';
const t = makeT('ToggleEnterprsiePage');
const testId = makeTestId('test-toggle-enterprise-page-');
export class ToggleEnterpriseWidget extends Disposable {
private readonly _model: ToggleEnterpriseModel = new ToggleEnterpriseModel();
private readonly _isEnterprise = Computed.create(this, this._model.edition, (_use, edition) => {
return edition === 'enterprise';
}).onWrite(async (enabled) => {
await this._model.updateEnterpriseToggle(enabled ? 'enterprise' : 'core');
});
constructor() {
super();
this._model.fetchEnterpriseToggle().catch(reportError);
}
public getEnterpriseToggleObservable() {
return this._isEnterprise;
}
public buildEnterpriseSection() {
return cssSection(
dom.domComputed(this._isEnterprise, (enterpriseEnabled) => {
return [
enterpriseEnabled ?
cssParagraph(
markdown(t('Grist Enterprise is **enabled**.')),
testId('enterprise-opt-out-message'),
) : null,
cssParagraph(
markdown(t(`An activation key is used to run Grist Enterprise after a trial period
of 30 days has expired. Get an activation key by [signing up for Grist
Enterprise]({{signupLink}}). You do not need an activation key to run
Grist Core.
Learn more in our [Help Center]({{helpCenter}}).`, {
signupLink: commonUrls.plans,
helpCenter: commonUrls.helpEnterpriseOptIn
}))
),
this._buildEnterpriseSectionButtons(),
];
}),
testId('enterprise-opt-in-section'),
);
}
public _buildEnterpriseSectionButtons() {
return dom.domComputed(this._isEnterprise, (enterpriseEnabled) => {
if (enterpriseEnabled) {
return [
cssOptOutButton(t('Disable Grist Enterprise'),
dom.on('click', () => this._isEnterprise.set(false)),
),
];
} else {
return [
cssOptInButton(t('Enable Grist Enterprise'),
dom.on('click', () => this._isEnterprise.set(true)),
),
];
}
});
}
}

@ -6,8 +6,9 @@
* It can be instantiated by calling showUserManagerModal with the UserAPI and IUserManagerOptions.
*/
import { makeT } from 'app/client/lib/localization';
import {commonUrls} from 'app/common/gristUrls';
import {commonUrls, isOrgInPathOnly} from 'app/common/gristUrls';
import {capitalizeFirstWord, isLongerThan} from 'app/common/gutil';
import {getGristConfig} from 'app/common/urlUtils';
import {FullUser} from 'app/common/LoginSessionAPI';
import * as roles from 'app/common/roles';
import {Organization, PermissionData, UserAPI} from 'app/common/UserAPI';
@ -816,15 +817,25 @@ const cssMemberPublicAccess = styled(cssMemberSecondary, `
function renderTitle(resourceType: ResourceType, resource?: Resource, personal?: boolean) {
switch (resourceType) {
case 'organization': {
if (personal) { return t('Your role for this team site'); }
return [
t('Manage members of team site'),
!resource ? null : cssOrgName(
`${(resource as Organization).name} (`,
cssOrgDomain(`${(resource as Organization).domain}.getgrist.com`),
')',
)
];
if (personal) {
return t('Your role for this team site');
}
function getOrgDisplay() {
if (!resource) {
return null;
}
const org = resource as Organization;
const gristConfig = getGristConfig();
const gristHomeHost = gristConfig.homeUrl ? new URL(gristConfig.homeUrl).host : '';
const baseDomain = gristConfig.baseDomain || gristHomeHost;
const orgDisplay = isOrgInPathOnly() ? `${baseDomain}/o/${org.domain}` : `${org.domain}${baseDomain}`;
return cssOrgName(`${org.name} (`, cssOrgDomain(orgDisplay), ')');
}
return [t('Manage members of team site'), getOrgDisplay()];
}
default: {
return personal ?

@ -0,0 +1,31 @@
import {BaseAPI, IOptions} from "app/common/BaseAPI";
import {addCurrentOrgToPath} from 'app/common/urlUtils';
/**
* An API for accessing the internal Grist configuration, stored in
* config.json.
*/
export class ConfigAPI extends BaseAPI {
constructor(private _homeUrl: string, options: IOptions = {}) {
super(options);
}
public async getValue(key: string): Promise<any> {
return (await this.requestJson(`${this._url}/api/config/${key}`, {method: 'GET'})).value;
}
public async setValue(value: any, restart=false): Promise<void> {
await this.request(`${this._url}/api/config`, {
method: 'PATCH',
body: JSON.stringify({config: value, restart}),
});
}
public async restartServer(): Promise<void> {
await this.request(`${this._url}/api/admin/restart`, {method: 'POST'});
}
private get _url(): string {
return addCurrentOrgToPath(this._homeUrl);
}
}

@ -84,6 +84,7 @@ export const commonUrls = {
helpTryingOutChanges: "https://support.getgrist.com/copying-docs/#trying-out-changes",
helpCustomWidgets: "https://support.getgrist.com/widget-custom",
helpTelemetryLimited: "https://support.getgrist.com/telemetry-limited",
helpEnterpriseOptIn: "https://support.getgrist.com/self-managed/#how-do-i-activate-grist-enterprise",
helpCalendarWidget: "https://support.getgrist.com/widget-calendar",
helpLinkKeys: "https://support.getgrist.com/examples/2021-04-link-keys",
helpFilteringReferenceChoices: "https://support.getgrist.com/col-refs/#filtering-reference-choices-in-dropdown",

@ -22,6 +22,15 @@ export class Activation extends BaseEntity {
@Column({name: 'updated_at', default: () => "CURRENT_TIMESTAMP"})
public updatedAt: Date;
// When the enterprise activation was first enabled, so we know when
// to start counting the trial date.
//
// Activations are created at Grist installation to track other
// things such as prefs, but the user might not enable Enterprise
// until later.
@Column({name: 'enabled_at', type: nativeValues.dateTimeType, nullable: true})
public enabledAt: Date|null;
public checkProperties(props: any): props is Partial<InstallProperties> {
for (const key of Object.keys(props)) {
if (!installPropertyKeys.includes(key)) {

@ -0,0 +1,18 @@
import * as sqlUtils from "app/gen-server/sqlUtils";
import { MigrationInterface, QueryRunner, TableColumn } from "typeorm";
export class ActivationEnabled1722529827161 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
const dbType = queryRunner.connection.driver.options.type;
const datetime = sqlUtils.datetime(dbType);
await queryRunner.addColumn('activations', new TableColumn({
name: 'enabled_at',
type: datetime,
isNullable: true,
}));
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn('activations', 'enabled_at');
}
}

@ -0,0 +1,35 @@
import * as express from 'express';
import {expressWrap} from 'app/server/lib/expressWrap';
import {getGlobalConfig} from 'app/server/lib/globalConfig';
import log from "app/server/lib/log";
export class ConfigBackendAPI {
public addEndpoints(app: express.Express, requireInstallAdmin: express.RequestHandler) {
app.get('/api/config/:key', requireInstallAdmin, expressWrap((req, resp) => {
log.debug('config: requesting configuration', req.params);
// Only one key is valid for now
if (req.params.key === 'edition') {
resp.send({value: getGlobalConfig().edition.get()});
} else {
resp.status(404).send({ error: 'Configuration key not found.' });
}
}));
app.patch('/api/config', requireInstallAdmin, expressWrap(async (req, resp) => {
const config = req.body.config;
log.debug('config: received new configuration item', config);
// Only one key is valid for now
if(config.edition !== undefined) {
await getGlobalConfig().edition.set(config.edition);
resp.send({ msg: 'ok' });
} else {
resp.status(400).send({ error: 'Invalid configuration key' });
}
}));
}
}

@ -87,7 +87,8 @@ import {AddressInfo} from 'net';
import fetch from 'node-fetch';
import * as path from 'path';
import * as serveStatic from "serve-static";
import {IGristCoreConfig} from "./configCore";
import {ConfigBackendAPI} from "app/server/lib/ConfigBackendAPI";
import {IGristCoreConfig} from "app/server/lib/configCore";
// Health checks are a little noisy in the logs, so we don't show them all.
// We show the first N health checks:
@ -1876,20 +1877,24 @@ export class FlexServer implements GristServer {
const probes = new BootProbes(this.app, this, '/api', adminMiddleware);
probes.addEndpoints();
this.app.post('/api/admin/restart', requireInstallAdmin, expressWrap(async (req, resp) => {
const newConfig = req.body.newConfig;
this.app.post('/api/admin/restart', requireInstallAdmin, expressWrap(async (_, resp) => {
resp.on('finish', () => {
// If we have IPC with parent process (e.g. when running under
// Docker) tell the parent that we have a new environment so it
// can restart us.
if (process.send) {
process.send({ action: 'restart', newConfig });
process.send({ action: 'restart' });
}
});
// On the topic of http response codes, thus spake MDN:
// "409: This response is sent when a request conflicts with the current state of the server."
const status = process.send ? 200 : 409;
return resp.status(status).send();
if(!process.env.GRIST_RUNNING_UNDER_SUPERVISOR) {
// On the topic of http response codes, thus spake MDN:
// "409: This response is sent when a request conflicts with the current state of the server."
return resp.status(409).send({
error: "Cannot automatically restart the Grist server to enact changes. Please restart server manually."
});
}
return resp.status(200).send({ msg: 'ok' });
}));
// Restrict this endpoint to install admins
@ -1948,6 +1953,14 @@ export class FlexServer implements GristServer {
}));
}
public addConfigEndpoints() {
// Need to be an admin to change the Grist config
const requireInstallAdmin = this.getInstallAdmin().getMiddlewareRequireAdmin();
const configBackendAPI = new ConfigBackendAPI();
configBackendAPI.addEndpoints(this.app, requireInstallAdmin);
}
// Get the HTML template sent for document pages.
public async getDocTemplate(): Promise<DocTemplate> {
const page = await fse.readFile(path.join(getAppPathTo(this.appRoot, 'static'),

@ -98,7 +98,7 @@ export class FileConfig<FileContents> {
}
public async persistToDisk() {
await Deps.writeFile(this._filePath, JSON.stringify(this._rawConfig, null, 2));
await Deps.writeFile(this._filePath, JSON.stringify(this._rawConfig, null, 2) + "\n");
}
}

@ -4,7 +4,8 @@ import {
fileConfigAccessorFactory,
IWritableConfigValue
} from "./config";
import { convertToCoreFileContents, IGristCoreConfigFileLatest } from "./configCoreFileFormats";
import {convertToCoreFileContents, IGristCoreConfigFileLatest} from "./configCoreFileFormats";
import {isAffirmative} from 'app/common/gutil';
export type Edition = "core" | "enterprise";
@ -23,6 +24,9 @@ export function loadGristCoreConfigFile(configPath?: string): IGristCoreConfig {
export function loadGristCoreConfig(fileConfig?: FileConfig<IGristCoreConfigFileLatest>): IGristCoreConfig {
const fileConfigValue = fileConfigAccessorFactory(fileConfig);
return {
edition: createConfigValue<Edition>("core", fileConfigValue("edition"))
edition: createConfigValue<Edition>(
isAffirmative(process.env.TEST_ENABLE_ACTIVATION) ? "enterprise" : "core",
fileConfigValue("edition")
)
};
}

@ -165,6 +165,7 @@ export async function main(port: number, serverTypes: ServerType[],
server.addLogEndpoint();
server.addGoogleAuthEndpoint();
server.addInstallEndpoints();
server.addConfigEndpoints();
}
if (includeDocs) {

@ -3,14 +3,14 @@ import {spawn} from 'child_process';
let grist;
function startGrist(newConfig={}) {
saveNewConfig(newConfig);
// H/T https://stackoverflow.com/a/36995148/11352427
grist = spawn('./sandbox/run.sh', {
stdio: ['inherit', 'inherit', 'inherit', 'ipc']
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
env: {...process.env, GRIST_RUNNING_UNDER_SUPERVISOR: true}
});
grist.on('message', function(data) {
if (data.action === 'restart') {
console.log('Restarting Grist with new environment');
console.log('Restarting Grist with new configuration');
// Note that we only set this event handler here, after we have
// a new environment to reload with. Small chance of a race here
@ -26,10 +26,4 @@ function startGrist(newConfig={}) {
return grist;
}
// Stub function
function saveNewConfig(newConfig) {
// TODO: something here to actually persist the new config before
// restarting Grist.
}
startGrist();

@ -1305,7 +1305,8 @@
"Removed webhook.": "Der Webhook wurde entfernt.",
"Webhook Id": "Webhook Id",
"Filter for changes in these columns (semicolon-separated ids)": "Filter für Änderungen in diesen Spalten (durch Semikolon getrennte IDs)",
"Cleared webhook queue.": "Webhook-Warteschlange geleert."
"Cleared webhook queue.": "Webhook-Warteschlange geleert.",
"Header Authorization": "Kopfzeilen-Autorisierung"
},
"FormulaAssistant": {
"Ask the bot.": "Fragen Sie den Bot.",
@ -1617,7 +1618,9 @@
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future since session IDs have been updated to be inherently cryptographically secure.": "Grist signiert die Sitzungscookies der Benutzer mit einem geheimen Schlüssel. Bitte setzen Sie diesen Schlüssel über die Umgebungsvariable GRIST_SESSION_SECRET. Grist greift auf eine hart kodierte Voreinstellung zurück, wenn sie nicht gesetzt ist. Wir werden diesen Hinweis möglicherweise in Zukunft entfernen, da Sitzungs-IDs, die seit v1.1.16 erzeugt werden, von Natur aus kryptographisch sicher sind.",
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future as session IDs generated since v1.1.16 are inherently cryptographically secure.": "Grist signiert die Sitzungscookies der Benutzer mit einem geheimen Schlüssel. Bitte setzen Sie diesen Schlüssel über die Umgebungsvariable GRIST_SESSION_SECRET. Grist greift auf eine hart kodierte Voreinstellung zurück, wenn sie nicht gesetzt ist. Wir werden diesen Hinweis möglicherweise in Zukunft entfernen, da Sitzungs-IDs, die seit v1.1.16 erzeugt werden, von Natur aus kryptographisch sicher sind.",
"Key to sign sessions with": "Schlüssel zum Anmelden von Sitzungen mit",
"Session Secret": "Sitzungsgeheimnis"
"Session Secret": "Sitzungsgeheimnis",
"Enterprise": "Unternehmen",
"Enable Grist Enterprise": "Aktivieren Sie Grist Enterprise"
},
"Section": {
"Insert section above": "Abschnitt oben einfügen",
@ -1696,5 +1699,50 @@
"Average Time (s)": "Durchschnittliche Zeit(en)",
"Loading timing data. Don't close this tab.": "Zeitpunktsdaten laden. Schließen Sie diese Registerkarte nicht.",
"Column ID": "Spalte ID"
},
"DocTutorial": {
"Click to expand": "Klicken Sie zum Erweitern",
"Finish": "Fertig",
"Do you want to restart the tutorial? All progress will be lost.": "Möchten Sie das Tutorial neu starten? Alle Fortschritte gehen dann verloren.",
"End tutorial": "Tutorial beenden",
"Next": "Nächste",
"Restart": "Neustart",
"Previous": "Vorherige"
},
"OnboardingPage": {
"Back": "Zurück",
"Type here": "Hier tippen",
"Welcome": "Willkommen",
"What brings you to Grist (you can select multiple)?": "Was bringt Sie zu Grist (Sie können mehrere auswählen)?",
"Discover Grist in 3 minutes": "Entdecken Sie Grist in 3 Minuten",
"Go hands-on with the Grist Basics tutorial": "Praktische Übungen mit dem Grist Basics-Tutorial",
"Go to the tutorial!": "Gehen Sie zum Tutorial!",
"Next step": "Nächster Schritt",
"Tell us who you are": "Sagen Sie uns, wer Sie sind",
"What is your role?": "Was ist Ihre Aufgabe?",
"What organization are you with?": "In welches Unternehem sind Sie tätig?",
"Your organization": "Ihr Unternehmen",
"Your role": "Ihre Rolle",
"Skip step": "Schritt überspringen",
"Skip tutorial": "Tutorial überspringen"
},
"OnboardingCards": {
"Complete the tutorial": "Fertigen Sie das Tutorial",
"3 minute video tour": "3 Minuten Video-Tour",
"Learn the basic of reference columns, linked widgets, column types, & cards.": "Lernen Sie die Grundlagen von Referenzspalten, verknüpften Widgets, Spaltentypen und Karten kennen.",
"Complete our basics tutorial": "Vervollständigen Sie unser Grundlagen-Tutorial"
},
"ToggleEnterpriseWidget": {
"Disable Grist Enterprise": "Grist Enterprise deaktivieren",
"Enable Grist Enterprise": "Grist Enterprise aktivieren",
"An activation key is used to run Grist Enterprise after a trial period\nof 30 days has expired. Get an activation key by [signing up for Grist\nEnterprise]({{signupLink}}). You do not need an activation key to run\nGrist Core.\n\nLearn more in our [Help Center]({{helpCenter}}).": "Ein Aktivierungsschlüssel wird verwendet, um Grist Enterprise nach Ablauf einer Testphase\nvon 30 Tagen. Sie erhalten einen Aktivierungsschlüssel, indem Sie [sich für Grist\nEnterprise anmelden]({{signupLink}}). Sie brauchen keinen Aktivierungsschlüssel, um\nGrist Core zu benutzen.\n\nErfahren Sie mehr in unserem [Help Center]({{helpCenter}}).",
"Grist Enterprise is **enabled**.": "Grist Enterprise ist **aktiviert**."
},
"ViewLayout": {
"Delete": "Löschen",
"Table {{tableName}} will no longer be visible": "Die Tabelle {{tableName}} wird nicht mehr sichtbar sein.",
"raw data page": "Rohdaten-Seite",
"Delete data and this widget.": "Daten und dieses Widget löschen.",
"Keep data and delete widget. Table will remain available in {{rawDataLink}}": "Daten behalten und Widget löschen. Die Tabelle bleibt verfügbar in {{rawDataLink}}"
}
}

@ -1572,7 +1572,9 @@
"Grist allows different types of authentication to be configured, including SAML and OIDC. We recommend enabling one of these if Grist is accessible over the network or being made available to multiple people.": "Grist allows different types of authentication to be configured, including SAML and OIDC. We recommend enabling one of these if Grist is accessible over the network or being made available to multiple people.",
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future as session IDs generated since v1.1.16 are inherently cryptographically secure.": "Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future as session IDs generated since v1.1.16 are inherently cryptographically secure.",
"Key to sign sessions with": "Key to sign sessions with",
"Session Secret": "Session Secret"
"Session Secret": "Session Secret",
"Enable Grist Enterprise": "Enable Grist Enterprise",
"Enterprise": "Enterprise"
},
"Columns": {
"Remove Column": "Remove Column"
@ -1665,5 +1667,18 @@
"What organization are you with?": "What organization are you with?",
"Your organization": "Your organization",
"Your role": "Your role"
},
"ToggleEnterpriseWidget": {
"An activation key is used to run Grist Enterprise after a trial period\nof 30 days has expired. Get an activation key by [signing up for Grist\nEnterprise]({{signupLink}}). You do not need an activation key to run\nGrist Core.\n\nLearn more in our [Help Center]({{helpCenter}}).": "An activation key is used to run Grist Enterprise after a trial period\nof 30 days has expired. Get an activation key by [signing up for Grist\nEnterprise]({{signupLink}}). You do not need an activation key to run\nGrist Core.\n\nLearn more in our [Help Center]({{helpCenter}}).",
"Disable Grist Enterprise": "Disable Grist Enterprise",
"Enable Grist Enterprise": "Enable Grist Enterprise",
"Grist Enterprise is **enabled**.": "Grist Enterprise is **enabled**."
},
"ViewLayout": {
"Delete": "Delete",
"Delete data and this widget.": "Delete data and this widget.",
"Keep data and delete widget. Table will remain available in {{rawDataLink}}": "Keep data and delete widget. Table will remain available in {{rawDataLink}}",
"Table {{tableName}} will no longer be visible": "Table {{tableName}} will no longer be visible",
"raw data page": "raw data page"
}
}

@ -1612,7 +1612,9 @@
"Session Secret": "Secreto de sesión",
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future since session IDs have been updated to be inherently cryptographically secure.": "Grist firma las cookies de sesión de usuario con una clave secreta. Establezca esta clave mediante la variable de entorno GRIST_SESSION_SECRET. Si no se establece, Grist vuelve a un valor predeterminado. Es posible que quitemos este aviso en el futuro, ya que los identificadores de sesión generados desde la versión 1.1.16 son intrínsecamente seguros desde el punto de vista criptográfico.",
"Key to sign sessions with": "Clave para firmar sesiones con",
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future as session IDs generated since v1.1.16 are inherently cryptographically secure.": "Grist firma las cookies de sesión de usuario con una clave secreta. Establezca esta clave mediante la variable de entorno GRIST_SESSION_SECRET. Si no se establece, Grist vuelve a un valor predeterminado. Es posible que quitemos este aviso en el futuro, ya que los identificadores de sesión generados desde la versión 1.1.16 son intrínsecamente seguros desde el punto de vista criptográfico."
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future as session IDs generated since v1.1.16 are inherently cryptographically secure.": "Grist firma las cookies de sesión de usuario con una clave secreta. Establezca esta clave mediante la variable de entorno GRIST_SESSION_SECRET. Si no se establece, Grist vuelve a un valor predeterminado. Es posible que quitemos este aviso en el futuro, ya que los identificadores de sesión generados desde la versión 1.1.16 son intrínsecamente seguros desde el punto de vista criptográfico.",
"Enterprise": "Empresarial",
"Enable Grist Enterprise": "Activar Grist Enterprise"
},
"CreateTeamModal": {
"Cancel": "Cancelar",
@ -1687,5 +1689,50 @@
"Total Time (s)": "Tiempo total (s)",
"Column ID": "ID de la columna",
"Max Time (s)": "Tiempo máximo (s)"
},
"DocTutorial": {
"Click to expand": "Haz clic para ampliar",
"End tutorial": "Fin del tutorial",
"Next": "Siguiente",
"Restart": "Reanudar",
"Do you want to restart the tutorial? All progress will be lost.": "¿Quieres reiniciar el tutorial? Se perderá todo el progreso.",
"Finish": "Finalizar",
"Previous": "Anterior"
},
"OnboardingCards": {
"Complete our basics tutorial": "Completa nuestro tutorial básico",
"Complete the tutorial": "Completa el tutorial",
"3 minute video tour": "La duración del vídeo es de 3 minutos",
"Learn the basic of reference columns, linked widgets, column types, & cards.": "Aprende los conceptos básicos de las columnas de referencia, widgets vinculados, tipos de columnas y tarjetas."
},
"OnboardingPage": {
"Discover Grist in 3 minutes": "Descubre Grist en 3 minutos",
"Next step": "Paso siguiente",
"Skip step": "Omitir el paso",
"Skip tutorial": "Omitir el tutorial",
"Tell us who you are": "¿Quién eres?",
"Type here": "Escribe aquí",
"Welcome": "Bienvenid@",
"What brings you to Grist (you can select multiple)?": "¿Qué te trae a Grist (puedes seleccionar varias opciones)?",
"What is your role?": "¿Cual es tu papel?",
"Your role": "Tu función",
"Back": "Atrás",
"Your organization": "Tu organización",
"Go hands-on with the Grist Basics tutorial": "Práctica con el tutorial básico de Grist",
"Go to the tutorial!": "¡Ve al tutorial!",
"What organization are you with?": "¿A qué organización perteneces?"
},
"ViewLayout": {
"Delete": "Borrar",
"Delete data and this widget.": "Eliminar datos y este widget.",
"Keep data and delete widget. Table will remain available in {{rawDataLink}}": "Mantener datos y eliminar el widget. La tabla permanecerá disponible en {{rawDataLink}}",
"Table {{tableName}} will no longer be visible": "La tabla {{tableName}} ya no será visible",
"raw data page": "página de datos en bruto"
},
"ToggleEnterpriseWidget": {
"An activation key is used to run Grist Enterprise after a trial period\nof 30 days has expired. Get an activation key by [signing up for Grist\nEnterprise]({{signupLink}}). You do not need an activation key to run\nGrist Core.\n\nLearn more in our [Help Center]({{helpCenter}}).": "Una clave de activación se utiliza para ejecutar Grist Enterprise después de un período de prueba\nde 30 días. Obtén una clave de activación [registrándose en Grist\nEmpresarial]({{signupLink}}). No necesitas una clave de activación para ejecutar\nGrist Core.\n\nMás información en nuestro [Centro de Ayuda]({{helpCenter}}).",
"Disable Grist Enterprise": "Desactivar Grist Enterprise",
"Enable Grist Enterprise": "Activar Grist Enterprise",
"Grist Enterprise is **enabled**.": "Grist Enterprise está **activado**."
}
}

@ -37,7 +37,7 @@
"User Attributes": "Erabiltzailearen atributuak",
"Seed rules": "-",
"Add Table-wide Rule": "Gehitu taula osorako araua",
"This default should be changed if editors' access is to be limited. ": "Akats hori aldatu beharko litzateke editoreen sarbidea mugatu nahi bada. ",
"This default should be changed if editors' access is to be limited. ": "Editoreen sarbidea mugatu nahi bada, defektuzko araua aldatu beharko litzateke. ",
"Remove {{- tableId }} rules": "Kendu {{- tableId}} arauak",
"Remove {{- name }} user attribute": "Kendu {{- name}} erabiltzailearen atributua",
"Remove column {{- colId }} from {{- tableId }} rules": "Kendu {{- colId }} zutabea {{- tableId }} arauetatik",
@ -85,7 +85,7 @@
"ViewAsDropdown": {
"View As": "Ikusi honela",
"Users from table": "Taulako erabiltzaileak",
"Example Users": "Erabiltzaile-eredua"
"Example Users": "Probako erabiltzaileak"
},
"ActionLog": {
"All tables": "Taula guztiak",
@ -103,7 +103,7 @@
"Remove": "Kendu",
"Remove API Key": "Kendu API gakoa",
"This API key can be used to access this account anonymously via the API.": "API gako hau erabiliz kontu honetara modu anonimoan sartzea dago.",
"By generating an API key, you will be able to make API calls for your own account.": "API gako bat sortuz gero, zure kontua eskatu ahal izango du.",
"By generating an API key, you will be able to make API calls for your own account.": "API gako bat sortuz gero, zure kontuari eskaerak egin ahal izango dizkiozu.",
"This API key can be used to access your account via the API. Dont share your API key with anyone.": "API gako hau erabiliz zure kontuan sartzea dago. Ez partekatu zure API gakoa inorekin.",
"You're about to delete an API key. This will cause all future requests using this API key to be rejected. Do you still want to delete?": "API gako bat ezabatzear zaude. Horrek etorkizuneko eskaera guztiak baztertuko ditu. Ziur ezabatu nahi duzula?"
},
@ -120,7 +120,7 @@
"Manage Team": "Kudeatu Taldea",
"Home Page": "Hasierako orria",
"Billing Account": "Fakturazio-kontua",
"Legacy": "Legatua"
"Legacy": "Zaharkitua"
},
"AppModel": {
"This team site is suspended. Documents can be read, but not modified.": "Taldearen gunea bertan behera utzi da. Dokumentuak irakur daitezke, baina ez moldatu."
@ -151,7 +151,7 @@
"Filter by this value": "Iragazi balio honen arabera"
},
"ColorSelect": {
"Apply": "Ezarri",
"Apply": "Aplikatu",
"Cancel": "Utzi",
"Default cell style": "Gelaxken defektuzko estiloa"
},
@ -166,12 +166,12 @@
"Filter by Range": "Iragazi tartearen arabera",
"Max": "Max.",
"Start": "Hasi",
"End": "Amaitu",
"End": "Amaiera",
"Other Values": "Beste balio batzuk",
"All Except": "Denak, hauek izan ezik",
"Other Non-Matching": "Bat ez datozen beste batzuk",
"Other Matching": "Bat datozen beste bat",
"All Shown": "Guztiak erakusten ari dira",
"Other Non-Matching": "Bat ez datorren beste bat",
"Other Matching": "Bat datorren beste bat",
"All Shown": "Guztiak erakusten",
"Future Values": "Etorkizuneko balioak"
},
"CustomSectionConfig": {
@ -181,12 +181,12 @@
"Pick a column": "Hautatu zutabea",
"Read selected table": "Irakurri hautatutako taula",
"Widget does not require any permissions.": "Widgetak ez du baimenik behar.",
"Clear selection": "Garbitu hautatutakoa",
"Clear selection": "Garbitu hautaketa",
"Pick a {{columnType}} column": "Aukeratu {{columnType}} zutabe bat",
"Learn more about custom widgets": "Ikasi gehiago norbere widgeti buruz",
"Learn more about custom widgets": "Ikasi gehiago widget pertsonalizatuei buruz",
"No document access": "Sarbiderik ez dokumentura",
"Widget needs to {{read}} the current table.": "Widgetek {{read}} behar du uneko taula.",
"Select Custom Widget": "Aukeratu Widget pertsonalizatua",
"Widget needs to {{read}} the current table.": "Widgetak uneko taula {{read}} behar du.",
"Select Custom Widget": "Hautatu widget pertsonalizatua",
"Widget needs {{fullAccess}} to this document.": "Widgetak {{fullAccess}} sarbidea behar du dokumentu honetara.",
"{{wrongTypeCount}} non-{{columnType}} columns are not shown_one": "{{wrongTypeCount}} ez da {{columnType}} zutabea erakusten",
"No {{columnType}} columns in table.": "Ez dago {{columnType}} zutaberik taulan.",
@ -214,7 +214,7 @@
"Compare to Current": "Alderatu unekoarekin",
"Compare to Previous": "Alderatu aurrekoarekin",
"Snapshots are unavailable.": "Argazkiak ez daude erabilgarri.",
"Only owners have access to snapshots for documents with access rules.": "Jabeek bakarrik eskura ditzakete sarbide-arauak dituzten dokumentuak.",
"Only owners have access to snapshots for documents with access rules.": "Jabeek bakarrik eskura ditzakete sarbide-arauak dituzten dokumentuen argazkiak.",
"Snapshots": "Argazkiak",
"Open Snapshot": "Ireki argazkia"
},
@ -269,7 +269,7 @@
"Enter recovery mode": "Sartu berreskuratze moduan",
"Sorry, access to this document has been denied. [{{error}}]": "Barkatu, dokumentu honetarako sarbidea ukatu da. [{{error}}]",
"Error accessing document": "Errorea dokumentura sartzean",
"You can try reloading the document, or using recovery mode. Recovery mode opens the document to be fully accessible to owners, and inaccessible to others. It also disables formulas. [{{error}}]": "Dokumentua birkargatzen saia zaitezke, edo berreskuratze-modua erabiltzen. Berreskuratzeko moduak dokumentua irekitzen du jabeentzat guztiz irisgarria izateko, eta beste batzuentzat eskuraezina. Formulak ere desgaitzen ditu. [{{error}}]"
"You can try reloading the document, or using recovery mode. Recovery mode opens the document to be fully accessible to owners, and inaccessible to others. It also disables formulas. [{{error}}]": "Dokumentua birkargatzen saia zaitezke, edo berreskuratze-modua erabiltzen. Berreskuratze-moduak dokumentua jabeentzat guztiz irisgarria izateko irekitzen du, baina gainerakoentzat eskuraezin egongo da. Formulak ere ezgaitzen ditu. [{{error}}]"
},
"DocumentSettings": {
"Currency:": "Moneta:",
@ -293,7 +293,7 @@
"Time Zone": "Ordu-eremua",
"Cancel": "Utzi",
"Locale:": "Eskualdeko ezarpenak:",
"Engine (experimental {{span}} change at own risk):": "Motorra (esperimentala {{span}} aldatu zure kontu):",
"Engine (experimental {{span}} change at own risk):": "Motorra ({{span}} esperimentala, aldatu zure kontu):",
"Manage Webhooks": "Kudeatu webhookak",
"Webhooks": "Webhookak",
"API Console": "API kontsola",
@ -304,8 +304,8 @@
"Data Engine": "Datu-motorra",
"ID for API use": "APIaren erabilerarako Ida",
"Locale": "Eskualdeko ezarpenak",
"Hard reset of data engine": "Datu-motorraren berrezarpena",
"Try API calls from the browser": "Saiatu APIren deiak nabigatzailetik",
"Hard reset of data engine": "Datu-motorraren berrasiera",
"Try API calls from the browser": "Probatu APIaren eskaerak nabigatzailetik",
"Reload data engine": "Birkargatu datu-motorra",
"Formula timer": "Formula-kronometroa",
"Reload data engine?": "Datu-motorra birkargatu?",
@ -325,7 +325,7 @@
"Notify other services on doc changes": "Jakinarazi beste zerbitzu batzuei dokumentuak aldatzerakoan",
"python2 (legacy)": "python2 (legatua)",
"python3 (recommended)": "python3 (gomendatua)",
"Time reload": "Kargatu denbora"
"Time reload": "Kronometratu birkarga"
},
"DocumentUsage": {
"Attachments Size": "Eranskinen tamaina",
@ -347,15 +347,15 @@
"Lightweight CRM": "CRM arina",
"Afterschool Program": "Eskolaz kanpoko programa",
"Investment Research": "Inbertsioen ikerketa",
"Check out our related tutorial for how to link data, and create high-productivity layouts.": "Kontsultatu gure tutoriala datuak lotzeko eta produktibitate handiko antolaketak sortzeko.",
"Check out our related tutorial for how to link data, and create high-productivity layouts.": "Begiratu gure tutoriala datuak lotzeko eta produktibitate handiko antolaketak sortzeko.",
"Tutorial: Analyze & Visualize": "Tutoriala: aztertu eta bistaratu",
"Tutorial: Create a CRM": "Tutoriala: CRM bat sortu",
"Tutorial: Manage Business Data": "Tutoriala: Negozio-datuak kudeatu",
"Welcome to the Afterschool Program template": "Ongi etorri Eskolaz kanpoko programa txantiloira",
"Welcome to the Investment Research template": "Ongi etorri Inbertsioen ikerketa txantiloira",
"Welcome to the Lightweight CRM template": "Ongi etorri CRM arinaren txantiloira",
"Check out our related tutorial for how to model business data, use formulas, and manage complexity.": "Kontsultatu gure tutoriala negozio-datuak modelatzeko, formulak erabiltzeko eta konplexutasuna kudeatzeko.",
"Check out our related tutorial to learn how to create summary tables and charts, and to link charts dynamically.": "Kontsultatu gure tutoriala laburpen-taulak eta grafikoak sortzen ikasteko eta grafikoak dinamikoki lotzeko."
"Check out our related tutorial for how to model business data, use formulas, and manage complexity.": "Begiratu gure tutoriala negozio-datuak modelatzeko, formulak erabiltzeko eta konplexutasuna kudeatzeko.",
"Check out our related tutorial to learn how to create summary tables and charts, and to link charts dynamically.": "Begiratu gure tutoriala laburpen-taulak eta grafikoak sortzen ikasteko eta grafikoak dinamikoki lotzeko."
},
"FieldConfig": {
"Clear and reset": "Garbitu eta berrezarri",
@ -365,7 +365,7 @@
"Set formula": "Ezarri formula",
"DESCRIPTION": "DESKRIBAPENA",
"Convert column to data": "Bilakatu zutabea datu",
"Column options are limited in summary tables.": "Zutabeen aukerak laburpen-tauletan mugatuta daude.",
"Column options are limited in summary tables.": "Zutabeen aukerak laburpen-tauletara mugatuta daude.",
"Data Columns_other": "Datu-zutabeak",
"Formula Columns_one": "Formula-zutabea",
"Formula Columns_other": "Formula-zutabeak",
@ -443,15 +443,15 @@
"Last Updated At": "Azken eguneraketa",
"Last Updated By": "Azken eguneratzailea",
"UUID": "UUIDa",
"Timestamp": "Denbora-zigilua",
"Timestamp": "Data-zigilua",
"Add formula column": "Gehitu formula-zutabea",
"Created at": "Sortze-data",
"Created by": "Sortzailea",
"Last updated at": "Azken eguneraketa",
"DateTime": "DateTime",
"DateTime": "Data eta ordua",
"Reference": "Erreferentzia",
"Attachment": "Eranskina",
"Integer": "Zbk osoa",
"Integer": "Zenbaki osoa",
"Created At": "Sortze-data",
"Created By": "Sortzailea",
"Lookups": "Bilaketak",
@ -462,7 +462,7 @@
"No reference columns.": "Ez dago erreferentzia-zutaberik.",
"Search columns": "Bilaketa-zutabeak",
"Detect duplicates in...": "Antzeman bikoizketak…",
"Add column with type": "Gehitu zutabea tipoarekin",
"Add column with type": "Gehitu mota honetako zutabea",
"Last updated by": "Azken eguneratzailea",
"Numeric": "Zenbakizkoa",
"Reference List": "Erreferentzia-zerrenda"
@ -481,7 +481,7 @@
"Sign in": "Hasi saioa",
"To use Grist, please either sign up or sign in.": "Grist erabiltzeko eman izena edo hasi saioa.",
"Visit our {{link}} to learn more about Grist.": "Bisitatu {{link}} Grist-i buruz gehiago ikasteko.",
"Help Center": "Laguntza gunea",
"Help Center": "Laguntza Gunea",
"Import Document": "Inportatu dokumentua",
"Welcome to {{orgName}}": "Ongi etorri {{orgName}}(e)ra",
"Sign up": "Eman izena",
@ -513,7 +513,7 @@
"Tutorial": "Tutoriala"
},
"LeftPanelCommon": {
"Help Center": "Laguntza gunea"
"Help Center": "Laguntza Gunea"
},
"MakeCopyMenu": {
"As Template": "Txantiloi gisa",
@ -530,20 +530,20 @@
"Sign up": "Eman izena",
"No destination workspace": "Ez dago helmugako lan-eremurik",
"Original Looks Unrelated": "Badirudi jatorrizkoak ez duela zerikusirik",
"Overwrite": "Gainean idatzi",
"Overwrite": "Gainidatzi",
"Workspace": "Lan-eremua",
"You do not have write access to this site": "Ez duzu gune honetarako idazketa-sarbiderik",
"You do not have write access to the selected workspace": "Ez duzu hautatutako lan-eremurako idazketa-sarbiderik",
"Download full document and history": "Jaitsi dokumentu osoa eta historia",
"However, it appears to be already identical.": "Hala ere, badirudi jadanik berdina dela.",
"However, it appears to be already identical.": "Hala ere, badirudi lehendik berdina dela.",
"Include the structure without any of the data.": "Sartu egitura, daturik gabe.",
"It will be overwritten, losing any content not in this document.": "Gainean idatziko da, dokumentu honetan ez dagoen edukia galduz.",
"It will be overwritten, losing any content not in this document.": "Gainidatziko da, dokumentu honetan ez dagoen edukia galduz.",
"The original version of this document will be updated.": "Dokumentu honen jatorrizko bertsioa eguneratuko da.",
"To save your changes, please sign up, then reload this page.": "Aldaketak gordetzeko, eman izena eta ondoren birkargatu orri hau.",
"Replacing the original requires editing rights on the original document.": "Jatorrizkoa ordezkatzeko, jatorrizko dokumentua editatzeko-eskubidea behar da.",
"Remove all data but keep the structure to use as a template": "Kendu datu guztiak baina gorde egitura txantiloi gisa erabiltzeko",
"Remove document history (can significantly reduce file size)": "Kendu dokumentuaren historia (fitxategiaren tamaina nabarmen murriztu daiteke)",
"Be careful, the original has changes not in this document. Those changes will be overwritten.": "Kontuz, jatorrizkoan egindako aldaketa ez daude dokumentu honetan. Aldaketa horien gainean idatziko da."
"Be careful, the original has changes not in this document. Those changes will be overwritten.": "Kontuz, jatorrizkoan egindako aldaketa ez daude dokumentu honetan. Aldaketa horiek gainidatziko dira."
},
"NotifyUI": {
"Ask for help": "Eskatu laguntza",
@ -593,7 +593,7 @@
"Fields_one": "Eremua",
"Fields_other": "Eremuak",
"Row Style": "Errenkadaren estiloa",
"Sort & Filter": "Sailkatu eta iragazi",
"Sort & Filter": "Sailkatu eta Iragazi",
"Theme": "Gaia",
"You do not have edit access to this document": "Ez duzu dokumentu hau editatzeko sarbiderik",
"Reset form": "Berrezarri formularioa",
@ -625,14 +625,14 @@
"Select Widget": "Hautatu widgeta",
"TRANSFORM": "ERALDATU",
"SELECTOR FOR": "HAUTATZAILEA",
"Series_one": "Serieak",
"Series_other": "Serieak",
"Series_one": "Segida",
"Series_other": "Segidak",
"Redirect automatically after submission": "Birbideratu automatikoki bidali ondoren",
"Submission": "Bidalketa",
"Table column name": "Taularen zutabearen izena",
"Select a field in the form widget to configure.": "Aukeratu widgetaren formularioko eremu bat konfiguratzeko.",
"Select a field in the form widget to configure.": "Hautatu widgetaren formularioko eremu bat konfiguratzeko.",
"Submit button label": "Bidaltzeko botoiaren testua",
"Success text": "Arrakastatsua denean erakusteko testua",
"Success text": "Bidali denean erakusteko testua",
"WIDGET TITLE": "WIDGETAREN IZENA",
"Widget": "Widgeta",
"Add referenced columns": "Gehitu erreferentziazko zutabeak",
@ -691,13 +691,13 @@
"Empty values last": "Balio hutsak amaieran",
"Natural sort": "Sailkapen naturala",
"Search Columns": "Bilaketa-zutabeak",
"Use choice position": "Erabili posizio hautatua"
"Use choice position": "Erabili hautatutako kokapena"
},
"SortFilterConfig": {
"Filter": "IRAGAZI",
"Save": "Gorde",
"Sort": "SAILKATU",
"Update Sort & Filter settings": "Eguneratu sailkatze- eta iragazketa-ezarpenak",
"Update Sort & Filter settings": "Eguneratu Sailkatu eta Iragazi ezarpenak",
"Revert": "Itzuli"
},
"ThemeConfig": {
@ -740,7 +740,7 @@
"View Only": "Ikusi soilik",
"Viewer": "Ikuslea",
"No Default Access": "Ez dago defektuzko sarbiderik",
"In Full": "Bete-betean (osorik)"
"In Full": "Osorik"
},
"ViewConfigTab": {
"Form": "Formularioa",
@ -748,14 +748,14 @@
"Advanced settings": "Ezarpen aurreratuak",
"Big tables may be marked as \"on-demand\" to avoid loading them into the data engine.": "Taula handiak \"nahieran\" gisa marka litezke datu-motorrean kargatzea saihesteko.",
"Compact": "Trinkotu",
"Edit Card Layout": "Editatu Karten antolaketa",
"Edit Card Layout": "Editatu txartelen antolaketa",
"Make On-Demand": "Egin nahieran",
"Plugin: ": "Plugina: ",
"Unmark On-Demand": "Utzi nahieran egiteari",
"Blocks": "Blokeak"
},
"ViewLayoutMenu": {
"Advanced Sort & Filter": "Sailkapen eta iragazki aurreratua",
"Advanced Sort & Filter": "Sailkatu eta Iragazi aurreratua",
"Download as CSV": "Jaitsi CSV gisa",
"Download as XLSX": "Jaitsi XLSX gisa",
"Open configuration": "Ireki konfigurazioa",
@ -769,7 +769,7 @@
"Data selection": "Datuen hautaketa",
"Delete record": "Ezabatu erregistroa",
"Delete widget": "Ezabatu widgeta",
"Edit Card Layout": "Editatu Karten antolaketa"
"Edit Card Layout": "Editatu txartelen antolaketa"
},
"ViewSectionMenu": {
"(empty)": "(hutsik)",
@ -780,7 +780,7 @@
"(customized)": "(pertsonalizatua)",
"Custom options": "Aukera pertsonalizatuak",
"Revert": "Itzuli",
"Update Sort&Filter settings": "Eguneratu Sailkatu eta Irakazi ezarpenak"
"Update Sort&Filter settings": "Eguneratu Sailkatu eta Iragazi ezarpenak"
},
"VisibleFieldsConfig": {
"Clear": "Garbitu",
@ -790,7 +790,7 @@
"Show {{label}}": "Erakutsi {{label}}",
"Hidden {{label}}": "{{label}} ezkutatuta",
"Visible {{label}}": "{{label}} ikusgai",
"Cannot drop items into Hidden Fields": "Ezin dira ezkutatutako eremuetako elementuak deuseztatu"
"Cannot drop items into Hidden Fields": "Ezin dira elementuak ezkutatutako eremuetan jarri"
},
"WelcomeQuestions": {
"Education": "Hezkuntza",
@ -834,11 +834,11 @@
"Your account has been deleted.": "Zure kontua ezabatu da.",
"An unknown error occurred.": "Errore ezezagun bat gertatu da.",
"Form not found": "Ez da formularioa aurkitu",
"Access denied{{suffix}}": "Sarbidea ukatua da{{suffix}}",
"Access denied{{suffix}}": "Sarbidea ukatu da{{suffix}}",
"Error{{suffix}}": "Errorea{{suffix}}",
"Page not found{{suffix}}": "Ez da orria aurkitu {{suffix}}",
"Signed out{{suffix}}": "Saioa amaituta{{suffix}}",
"Contact support": "Jarri harremanetan",
"Contact support": "Eskatu laguntza",
"The requested page could not be found.{{separator}}Please check the URL and try again.": "Ezin izan da eskatutako orria aurkitu.{{separator}}Egiaztatu URLa eta saiatu berriro.",
"You are now signed out.": "Saioa amaitu duzu.",
"You are signed in as {{email}}. You can sign in with a different account, or ask an administrator for access.": "{{email}} gisa hasi duzu saioa. Beste kontu batekin hasi dezakezu saioa, edo administratzaile bati sarbidea eskatu.",
@ -855,7 +855,7 @@
"Choice": "Aukera",
"Choice List": "Aukeren zerrenda",
"Attachment": "Eranskina",
"* Workspaces are available on team plans. ": "* Lan-eremuak TEAM planetan daude eskuragarri. ",
"* Workspaces are available on team plans. ": "* Lan-eremuak TEAM planean daude eskuragarri. ",
"Upgrade now": "Eguneratu orain",
"Numeric": "Zenbakizkoa",
"Integer": "Osoa",
@ -910,7 +910,7 @@
"Users from table": "Taulako erabiltzaileak"
},
"TypeTransform": {
"Apply": "Ezarri",
"Apply": "Aplikatu",
"Cancel": "Utzi",
"Preview": "Aurrebista",
"Revise": "Berrikusi",
@ -954,7 +954,7 @@
"Save": "Gorde",
"Reply to a comment": "Erantzun iruzkin bati",
"Show resolved comments": "Erakutsi konpondutako iruzkinak",
"Only my threads": "Nire hariak bakarrik",
"Only my threads": "Soilik nire hariak",
"Started discussion": "Eztabaida hasi du"
},
"FieldBuilder": {
@ -963,11 +963,11 @@
"CELL FORMAT": "GELAXKEN FORMATUA",
"DATA FROM TABLE": "TAULAKO DATUAK",
"Mixed format": "Formatu mistoa",
"Mixed types": "Mota mistoak",
"Mixed types": "Askotariko motak",
"Changing multiple column types": "Hainbat zutabe mota aldatzen",
"Save field settings for {{colId}} as common": "{{colId}} eremuaren konfigurazioa defektuzko gisa gorde da",
"Use separate field settings for {{colId}}": "Erabili eremu-ezarpen bereiziak {{colId}}(e)rako",
"Revert field settings for {{colId}} to common": "{{colId}} eremuaren konfigurazioa defektuzkora itzuli da"
"Save field settings for {{colId}} as common": "Gorde {{colId}} eremu-ezarpenak arrunt gisa",
"Use separate field settings for {{colId}}": "Erabili {{colId}} eremu-ezarpen bereiziak",
"Revert field settings for {{colId}} to common": "Itzuli {{colId}} eremu-ezarpenak defektuzkora"
},
"FormulaEditor": {
"Column or field is required": "Beharrezkoa da zutabea edo eremua",
@ -977,7 +977,7 @@
"Error in the cell": "Errorea gelaxkan",
"Expand Editor": "Hedatu editorea",
"Errors in all {{numErrors}} cells": "Erroreak {{numErrors}} gelaxka guztietan",
"editingFormula is required": "editatuFormula beharrezkoa da",
"editingFormula is required": "editingFormula beharrezkoa da",
"Errors in {{numErrors}} of {{numCells}} cells": "Erroreak {{numCells}}eko {{numErrors}} gelaxketan-"
},
"NumericTextBox": {
@ -987,7 +987,7 @@
"Decimals": "Dezimalak",
"Currency": "Moneta",
"Field Format": "Eremuaren formatua",
"Spinner": "Spinner",
"Spinner": "Spinnerra",
"max": "max",
"min": "min"
},
@ -1002,7 +1002,7 @@
"Configuring your document": "Dokumentua konfiguratzen",
"Editing Data": "Datuak editatzen",
"Enter": "Sartu",
"Help Center": "Laguntza gunea",
"Help Center": "Laguntza Gunea",
"Use the Share button ({{share}}) to share the document or export data.": "Erabili Partekatu botoia ({{share}}) dokumentua partekatu edo datuak esportatzeko.",
"Welcome to Grist!": "Ongi etorri Grist-era!",
"template library": "txantiloi liburutegia",
@ -1011,16 +1011,16 @@
"Browse our {{templateLibrary}} to discover what's possible and get inspired.": "Arakatu gure {{templateLibrary}} aukerak ikusi eta inspiratzeko.",
"Customizing columns": "Zutabeak pertsonalizatzen",
"Double-click or hit {{enter}} on a cell to edit it. ": "Egin klik birritan edo sakatu {{enter}} gelaxka batean editatzeko. ",
"Flying higher": "Gorago hegan",
"Flying higher": "Urrunago joateko",
"Reference": "Erreferentzia",
"Make it relational! Use the {{ref}} type to link tables. ": "Harremanak izan daitezela! Erabili {{ref}} mota taulak lotzeko. ",
"Make it relational! Use the {{ref}} type to link tables. ": "Egizu erlazional! Erabili {{ref}} mota taulak lotzeko. ",
"Use {{helpCenter}} for documentation or questions.": "Erabili {{helpCenter}} dokumentaziorako edo galderetarako.",
"Use {{addNew}} to add widgets, pages, or import more data. ": "Erabili {{addNew}} widgetak, orriak edo datu gehiago inportatzeko. ",
"Use {{addNew}} to add widgets, pages, or import more data. ": "Erabili {{addNew}} widgetak edo orriak gehitzeko, edo datu gehiago inportatzeko. ",
"creator panel": "sortzailearen mahaigaina",
"Start with {{equal}} to enter a formula.": "Hasi {{equal}}ekin formula bat sartzeko.",
"Set formatting options, formulas, or column types, such as dates, choices, or attachments. ": "Ezarri formatu-aukerak, formulak edo zutabe-motak, hala nola datak, aukerak edo eranskinak. ",
"Toggle the {{creatorPanel}} to format columns, ": "Erabili {{creatorPanel}} zutabeak formatatzeko, ",
"convert to card view, select data, and more.": "txartel bista, datuak aukeratu, eta gehiago."
"Set formatting options, formulas, or column types, such as dates, choices, or attachments. ": "Ezarri formatu-aukerak, formulak, edo zutabe-motak; datak, aukerak edo eranskinak adibidez. ",
"Toggle the {{creatorPanel}} to format columns, ": "Erabili {{creatorPanel}} zutabeei formatua emateko, ",
"convert to card view, select data, and more.": "txartel-bista bihurtzeko, datuak hautatzeko, eta gehiagorako."
},
"LanguageMenu": {
"Language": "Hizkuntza"
@ -1034,7 +1034,7 @@
"Calendar": "Egutegia",
"Example: {{example}}": "Adibidea: {{example}}",
"Learn more": "Ikasi gehiago",
"Editing Card Layout": "Editatu karten antolaketa",
"Editing Card Layout": "Txartelen antolaketa editatzen",
"Formulas that trigger in certain cases, and store the calculated value as data.": "Kasu jakin batzuetan abiarazten diren formulak, eta kalkulatutako balioak datu gisa gordetzen dute.",
"Link your new widget to an existing widget on this page.": "Lotu zure widget berria orrialde honetan lehendik dagoen widget batekin.",
"Raw Data page": "Datu gordinen orria",
@ -1054,7 +1054,7 @@
"Apply conditional formatting to rows based on formulas.": "Aplikatu baldintza-formatua formuletan oinarritzen diren errenkadei.",
"Click the Add New button to create new documents or workspaces, or import data.": "Egin klik \"Gehitu berria\" botoian dokumentu edo lan-eremu berriak sortzeko, edo datuak inportatzeko.",
"Click on “Open row styles” to apply conditional formatting to rows.": "Egin klik \"Ireki errenkada-estiloak\"-en errenkadei formatu-baldintzak aplikatzeko.",
"Nested Filtering": "Iragazki habiratuak",
"Nested Filtering": "iragazki habiratuak",
"Pinned filters are displayed as buttons above the widget.": "Finkatutako iragazkiak botoi gisa ageri dira widgetaren gainean.",
"Select the table containing the data to show.": "Hautatu erakutsi beharreko datuak dituen taula.",
"Only those rows will appear which match all of the filters.": "Iragazki guztiekin bat datozen errenkadak baino ez dira agertuko.",
@ -1065,23 +1065,23 @@
"Access rules give you the power to create nuanced rules to determine who can see or edit which parts of your document.": "Sarbide-arauek arau zehatzak sortzeko aukera ematen dizute, zure dokumentuaren zein zati nork ikusi edo editatu dezakeen zehazteko.",
"Anchor Links": "Aingura-estekak",
"Custom Widgets": "Widget pertsonalizatuak",
"entire": "osorik",
"Useful for storing the timestamp or author of a new record, data cleaning, and more.": "Baliagarria da data-zigilu edo erregistro berri baten egilea gordetzeko, datuak garbitzeko, eta gehiago.",
"entire": "osoa",
"Useful for storing the timestamp or author of a new record, data cleaning, and more.": "Baliagarria da data-zigilu edo erregistro berri baten egilea gordetzeko, datuak garbitzeko, eta gehiagorako.",
"To make an anchor link that takes the user to a specific cell, click on a row and press {{shortcut}}.": "Erabiltzailea gelaxka zehatz batera eramaten duen aingura-esteka bat sortzeko, egin klik errenkada batean eta sakatu {{shortcut}}.",
"You can choose one of our pre-made widgets or embed your own by providing its full URL.": "Aldez aurretik egindako widget bat aukeratu dezakezu edo zurea txertatu URL osoa emanez.",
"To configure your calendar, select columns for start": {
"end dates and event titles. Note each column's type.": "Zure egutegia konfiguratzeko, aukeratu zutabeak hasierako/amaierako datetarako eta gertaeren izenburuetarako. Zehaztu zutabe bakoitzaren mota."
"end dates and event titles. Note each column's type.": "Zure egutegia konfiguratzeko, hautatu zutabeak hasierako/amaierako datetarako eta gertaeren izenburuetarako. Zehaztu zutabe bakoitzaren mota."
},
"A UUID is a randomly-generated string that is useful for unique identifiers and link keys.": "UUID bat ausaz sortutako kate bat da, identifikatzaile eta lotura-tekla berezietarako baliagarria dena.",
"Lookups return data from related tables.": "Bilaketek erlazionatutako tauletatik datuak itzultzen dituzte.",
"Use reference columns to relate data in different tables.": "Erabili erreferentzia-zutabeak taula ezberdinetako datuak erlazionatzeko.",
"You can choose from widgets available to you in the dropdown, or embed your own by providing its full URL.": "Goitibeheran dauden widgeten artean aukeratu dezakezu, edo zurea txertatu URL osoa emanez.",
"Use the \\u{1D6BA} icon to create summary (or pivot) tables, for totals or subtotals.": "Erabili \\u{1D6BA} ikonoa laburpen- (edo pibote-) taulak sortzeko, totaletarako edo azpi-totaletarako.",
"Cells in a reference column always identify an {{entire}} record in that table, but you may select which column from that record to show.": "Erreferentzia-zutabe bateko gelaxkek beti identifikatzen dute erregistro {{entire}} bat taula horretan, baina erregistro horretako zein zutabe erakutsi hautatu dezakezu.",
"Linking Widgets": "Widgetak lotzen (erlazionatzen)",
"Use the \\u{1D6BA} icon to create summary (or pivot) tables, for totals or subtotals.": "Erabili \\u{1D6BA} ikonoa laburpen-taulak edo taula dinamikoak sortzeko, guztizkoetarako edo guztizko partzialetarako.",
"Cells in a reference column always identify an {{entire}} record in that table, but you may select which column from that record to show.": "Erreferentzia-zutabe bateko gelaxkek beti identifikatzen dute erregistro {{entire}} taula horretan, baina erregistro horretako zein zutabe erakutsi hautatu dezakezu.",
"Linking Widgets": "Widgetak lotzen",
"Unpin to hide the the button while keeping the filter.": "Utzi finkatzeari botoia ezkutatzeko iragazkia mantendu bitartean.",
"Select the table to link to.": "Hautatu lotu beharreko taula.",
"Use the 𝚺 icon to create summary (or pivot) tables, for totals or subtotals.": "Erabili 𝚺 ikonoa laburpen- (edo pibote-) taulak sortzeko, totaletarako edo azpi-totaletarako.",
"Use the 𝚺 icon to create summary (or pivot) tables, for totals or subtotals.": "Erabili 𝚺 ikonoa laburpen-taulak edo taula dinamikoak sortzeko, guztizkoetarako edo guztizko partzialetarako.",
"Can't find the right columns? Click 'Change Widget' to select the table with events data.": "Ez dituzu zutabe egokiak aurkitzen? Egin klik \"Aldatu widgeta\"-n gertaeren datuak dituen taula hautatzeko.",
"Clicking {{EyeHideIcon}} in each cell hides the field from this view without deleting it.": "Gelaxka bakoitzeko {{EyeHideIcon}}-en klik eginez gero, eremua ikuspegi honetatik ezkutatuko da ezabatu gabe."
},
@ -1094,7 +1094,7 @@
"Cancel": "Utzi",
"Save": "Gorde",
"Column label": "Zutabearen etiketa",
"Provide a column label": "Eman zutabeari etiketa bat"
"Provide a column label": "Ezarri zutabearen etiketa"
},
"Clipboard": {
"Got it": "Ulertuta",
@ -1123,7 +1123,7 @@
"Memo": "Memorandum",
"Removed webhook.": "Webhooka kendu da.",
"Webhook Id": "Webhook IDa",
"Ready Column": "Prest zutabea",
"Ready Column": "Zutabea prest",
"Filter for changes in these columns (semicolon-separated ids)": "Iragazki aldaketetarako zutabe hauetan (\";\" bidez bareizi IDak)",
"Header Authorization": "Goiburuko baimena"
},
@ -1136,7 +1136,7 @@
"Need help? Our AI assistant can help.": "Laguntza behar duzu? Gure AA laguntzaileak lagun zaitzake.",
"Tips": "Aholkuak",
"AI Assistant": "AA laguntzailea",
"Apply": "Ezarri",
"Apply": "Aplikatu",
"Cancel": "Utzi",
"Learn more": "Ikasi gehiago",
"Clear Conversation": "Garbitu elkarrizketa",
@ -1147,7 +1147,7 @@
"Formula Help. ": "Formulen laguntza ",
"Function List": "Funtzioen zerrenda",
"Grist's AI Formula Assistance. ": "Gristen AAeko formula-laguntzailea ",
"Formula Cheat Sheet": "Formularen eskuliburua",
"Formula Cheat Sheet": "Formulen eskuliburua",
"Hi, I'm the Grist Formula AI Assistant.": "Kaixo, Gristen AAeko formula-laguntzailea naiz.",
"Code View": "Kode-ikustailea",
"See our {{helpFunction}} and {{formulaCheat}}, or visit our {{community}} for more help.": "Ikusi gure {{helpFunction}} eta {{formulaCheat}}, edo bisitatu gure {{community}} laguntza gehiagorako.",
@ -1167,11 +1167,11 @@
},
"ChartView": {
"Pick a column": "Hautatu zutabea",
"Create separate series for each value of the selected column.": "Sortu serie bereiziak hautatutako zutabearen balio bakoitzerako.",
"Each Y series is followed by a series for the length of error bars.": "Y serie bakoitzaren ondoren serie bat dago errore-barren luzerarako.",
"Create separate series for each value of the selected column.": "Sortu segida bereiziak hautatutako zutabearen balio bakoitzerako.",
"Each Y series is followed by a series for the length of error bars.": "Y segida bakoitzaren ondoren errore-barren luzerarako segida bat dator.",
"Toggle chart aggregation": "Grafikoaren agregazioa bai/ez",
"selected new group data columns": "hautatutako taldekako datu-zutabe berriak",
"Each Y series is followed by two series, for top and bottom error bars.": "Y serie bakoitzaren ondoren bi serie daude, goiko eta beheko errore-barretarako."
"Each Y series is followed by two series, for top and bottom error bars.": "Y segida bakoitzaren ondoren goiko eta beheko errore-barrentzako segida bana dator."
},
"FilterBar": {
"SearchColumns": "Bilatu zutabeak",
@ -1185,8 +1185,8 @@
"Select fields to match on": "Hautatu bat egiteko eremuak",
"Update existing records": "Eguneratu lehendik dauden erregistroak",
"{{count}} unmatched field_other": "Bat ez datozen {{count}} eremu",
"Column Mapping": "Zutabeen mapa",
"Column mapping": "Zutabeen mapa",
"Column Mapping": "Zutabeen mapaketa",
"Column mapping": "Zutabeen esleipena",
"{{count}} unmatched field in import_one": "Bat ez datorren eremu {{count}} inportazioan",
"{{count}} unmatched field in import_other": "Bat ez datozen {{count}} eremu inportazioan",
"{{count}} unmatched field_one": "Bat ez datorren eremu {{count}}",
@ -1208,7 +1208,7 @@
"UnknownUser": "Erabiltzaile ezezaguna"
},
"TypeTransformation": {
"Apply": "Ezarri",
"Apply": "Aplikatu",
"Cancel": "Utzi",
"Preview": "Aurrebista",
"Revise": "Berrikusi",
@ -1226,18 +1226,18 @@
"Code View is available only when you have full document access.": "Kode-ikustailea dokumentu guztiak eskura dituzunean bakarrik dago eskuragarri."
},
"DocTour": {
"No valid document tour": "Ez du balio dokumentu-ibilbideak",
"Cannot construct a document tour from the data in this document. Ensure there is a table named GristDocTour with columns Title, Body, Placement, and Location.": "Ezin da dokumentu-ibilbide bat egin dokumentu honetako datuetatik abiatuta. GristDocTour izeneko mahai bat dago zutabeekin. Izenburua, gorputza, kokapena eta kokapena."
"No valid document tour": "Ez dago baliozko dokumentu-bisitaldirik",
"Cannot construct a document tour from the data in this document. Ensure there is a table named GristDocTour with columns Title, Body, Placement, and Location.": "Ezin da dokumentu-bisitaldi bat sortu dokumentu honetako datuetatik abiatuta. Egiaztatu GristDocTour izeneko taula bat dagoela Izenburua, Gorputza, eta Kokapena zutabeekin."
},
"Drafts": {
"Restore last edit": "Leheneratu azken edizioa",
"Undo discard": "Desegin baztertzailea"
"Undo discard": "Desegin bazterketa"
},
"GristDoc": {
"Import from file": "Inportatu fitxategitik",
"Added new linked section to view {{viewName}}": "{{viewName}} ikusteko lotutako atal berria gehitu da",
"go to webhook settings": "Joan webhooken ezarpenetara",
"Saved linked section {{title}} in view {{name}}": "{{title}} atala gorde da hemen: {{name}}"
"Saved linked section {{title}} in view {{name}}": "{{title}} lotutako atala {{name}} bistan gorde da"
},
"OpenVideoTour": {
"Grist Video Tour": "Gristen bideo-bisitaldia",
@ -1272,7 +1272,7 @@
"Convert column to formula": "Bihurtu zutabea formula"
},
"FieldEditor": {
"It should be impossible to save a plain data value into a formula column": "Ezinezkoa litzateke datu-balio soil bat gordetzea formula-zutabe batean",
"It should be impossible to save a plain data value into a formula column": "Ezinezkoa litzateke datu-balio soil bat formula-zutabe batean gordetzea",
"Unable to finish saving edited cell": "Ezin izan da gelaxka gordetzen amaitu"
},
"HyperLinkEditor": {
@ -1292,16 +1292,16 @@
"Invite people to {{resourceType}}": "Gonbidatu jendea {{resourceType}}(e)ra",
"Link copied to clipboard": "Esteka arbelera kopiatu da",
"On": "Piztuta",
"Once you have removed your own access, you will not be able to get it back without assistance from someone else with sufficient access to the {{name}}.": "Zure sarbidea kendu ondoren, ezingo duzu berreskuratu {{name}}(e)rako sarbide nahikoa duen norbaiten laguntzarik gabe.",
"Once you have removed your own access, you will not be able to get it back without assistance from someone else with sufficient access to the {{name}}.": "Zure sarbidea kendu ondoren, ezingo duzu berreskuratu {{name}}(e)rako sarbide nahikoa duen beste norbaiten laguntzarik gabe.",
"Public access": "Sarbide publikoa",
"Public access inherited from {{parent}}. To remove, set 'Inherit access' option to 'None'.": "Sarbide publikoak {{parent}}(r)en baimenak hartzen ditu. Kentzeko, ezarri \"Jaso sarbidea\" \"Bat ere ez\" aukerara.",
"Public access inherited from {{parent}}. To remove, set 'Inherit access' option to 'None'.": "Sarbide publikoak {{parent}}(r)en baimenak jasotzen ditu. Kentzeko, ezarri \"Jarauntsitako sarbidea\" \"Bat ere ez\" aukerara.",
"Public access: ": "Sarbide publikoa: ",
"Remove my access": "Kendu nire sarbidea",
"member": "kidea",
"team site": "Taldearen gunea",
"{{limitAt}} of {{limitTop}} {{collaborator}}s": "{{limitAt}} of {{limitTop}} {{collaborator}}s",
"{{limitAt}} of {{limitTop}} {{collaborator}}s": "{{limitTop}}(e)tik {{limitAt}} {{collaborator}}",
"{{collaborator}} limit exceeded": "{{collaborator}}-muga gainditu da",
"User inherits permissions from {{parent}}. To remove, set 'Inherit access' option to 'None'.": "Erabiltzaileak {{parent}}(r)en baimenak hartzen ditu. Kentzeko, ezarri \"Jaso sarbidea\" \"Bat ere ez\" aukerara.",
"User inherits permissions from {{parent}}. To remove, set 'Inherit access' option to 'None'.": "Erabiltzaileak {{parent}}(r)en baimenak jasotzen ditu. Kentzeko, ezarri \"Jarauntsitako sarbidea\" \"Bat ere ez\" aukerara.",
"Anyone with link ": "Esteka duen edonor ",
"Cancel": "Utzi bertan behera",
"Close": "Itxi",
@ -1321,17 +1321,17 @@
"guest": "gonbidatua",
"No default access allows access to be granted to individual documents or workspaces, rather than the full team site.": "Ez dago dokumentu indibidualetarako edo lan-guneetarako defektuzko-sarbiderik, lantaldearen gune osora baizik.",
"You are about to remove your own access to this {{resourceType}}": "{{resourceType}} honetarako zure sarbidea ezabatzear zaude",
"User inherits permissions from {{parent})}. To remove, set 'Inherit access' option to 'None'.": "Erabiltzaileak {{parent})} -ren baimenak heredatzen ditu. Kentzeko, ezarri \"Heredatu sarbidea\" aukera \"Bat ere ez\" aukerara.",
"free collaborator": "Kolaboratzaile askea",
"Once you have removed your own access, you will not be able to get it back without assistance from someone else with sufficient access to the {{resourceType}}.": "Zure sarbidea kendu eta gero, ezingo duzu berreskuratu {{resourceType}}(e)rako sarbidea nahikoa duen norbaiten laguntzarik gabe.",
"User has view access to {{resource}} resulting from manually-set access to resources inside. If removed here, this user will lose access to resources inside.": "Erabiltzaileak {{resource}}-rako bistarako sarbidea du, barneko baliabideetarako sarbidea eskuz ezartzearen ondorioz. Hemendik kenduz gero, barruan dauden baliabideak galduko ditu."
"User inherits permissions from {{parent})}. To remove, set 'Inherit access' option to 'None'.": "Erabiltzaileak {{parent}}(r)en baimenak jasotzen ditu. Kentzeko, ezarri \"Jarauntsitako sarbidea\" aukera \"Bat ere ez\" aukerara.",
"free collaborator": "kolaboratzaile askea",
"Once you have removed your own access, you will not be able to get it back without assistance from someone else with sufficient access to the {{resourceType}}.": "Zure sarbidea kendu ondoren, ezingo duzu berreskuratu {{resourceType}}(e)rako sarbide nahikoa duen beste norbaiten laguntzarik gabe.",
"User has view access to {{resource}} resulting from manually-set access to resources inside. If removed here, this user will lose access to resources inside.": "Erabiltzaileak {{resource}}-rako bistarako sarbidea du, barneko baliabideetarako sarbidea eskuz ezartzearen ondorioz. Hemendik kenduz gero, barruan dauden baliabideetarako sarbidea galduko du."
},
"SupportGristNudge": {
"Help Center": "Laguntza-gunea",
"Help Center": "Laguntza Gunea",
"Opt in to Telemetry": "Bidali telemetria",
"Support Grist": "Eman babesa Grist-i",
"Support Grist page": "Eman babesa Grist-en orriari",
"Opted In": "Onartua",
"Opted In": "Izena emanda",
"Close": "Itxi",
"Contribute": "Hartu parte",
"Thank you! Your trust and support is greatly appreciated. Opt out any time from the {{link}} in the user menu.": "Mila esker! Zure konfiantza eta babesa oso estimatua da. Edozein unetan bidaltzeari utzi diezaiokezu erabiltzailearen menuko {{link}}tik.",
@ -1339,7 +1339,7 @@
},
"SupportGristPage": {
"GitHub Sponsors page": "GitHub Sponsors orria",
"Help Center": "Laguntza-gunea",
"Help Center": "Laguntza Gunea",
"Home": "Hasiera",
"Support Grist": "Eman babesa Grist-i",
"Telemetry": "Telemetria",
@ -1351,7 +1351,7 @@
"Sponsor Grist Labs on GitHub": "Eman babesa Grist Labs-i GitHuben",
"This instance is opted in to telemetry. Only the site administrator has permission to change this.": "Instantzia honek telemetria bidaltzea aukeratu du. Administratzaileak bakarrik du aukera hau aldatzeko baimena.",
"This instance is opted out of telemetry. Only the site administrator has permission to change this.": "Instantzia honek telemetria ez bidaltzea aukeratu du. Administratzaileak bakarrik du aukera hau aldatzeko baimena.",
"You can opt out of telemetry at any time from this page.": "Orri honeta telemetria ez bidaltzea aukera dezakezu edozein unetan.",
"You can opt out of telemetry at any time from this page.": "Orri honetan telemetria ez bidaltzea aukera dezakezu edozein unetan.",
"You have opted in to telemetry. Thank you!": "Telemetria bidaltzea aukeratu duzu. Mila esker!",
"You have opted out of telemetry.": "Telemetria ez bidaltzea aukeratu duzu.",
"Manage Sponsorship": "Kudeatu babesletza"
@ -1401,7 +1401,7 @@
"Reset form": "Berrezarri formularioa",
"Share": "Partekatu",
"Save your document to publish this form.": "Gorde dokumentua formularioa argitaratzeko.",
"Preview": "Aurreikusi"
"Preview": "Aurrebista"
},
"Editor": {
"Delete": "Ezabatu"
@ -1416,25 +1416,25 @@
"Paragraph": "Paragrafoa",
"Paste": "Itsatsi",
"Separator": "Bereizgailua",
"Unmapped fields": "Mapeatu gabeko eremuak",
"Unmapped fields": "Esleitu gabeko eremuak",
"Header": "Goiburua"
},
"UnmappedFieldsConfig": {
"Clear": "Garbitu",
"Select All": "Hautatu guztiaa",
"Map fields": "Mapeatu eremuak",
"Mapped": "Mapeatuta",
"Unmap fields": "Desmapeatu eremuak",
"Unmapped": "Desmapeatuta"
"Select All": "Hautatu guztia",
"Map fields": "Mapaketatu eremuak",
"Mapped": "Mapaketatuta",
"Unmap fields": "Utzi eremuak esleitzeari",
"Unmapped": "Esleitu gabe"
},
"FormConfig": {
"Default": "Defektuzkoa",
"Field Format": "Eremu-formatua",
"Ascending": "Goranzkoa",
"Ascending": "Gorantz",
"Descending": "Beherantz",
"Select": "Hautatu",
"Vertical": "Bertikala",
"Radio": "Radioa",
"Radio": "Aukera-botoia",
"Field rules": "Eremu-arauak",
"Required field": "Nahitaezko eremua",
"Field Rules": "Eremu-arauak",
@ -1446,7 +1446,7 @@
"Oops! The form you're looking for doesn't exist.": "Hara! Bilatzen ari zaren formularioa ez da existitzen.",
"There was a problem loading the form.": "Arazo bat egon da formularioa kargatzean.",
"You don't have access to this form.": "Ez duzu formulario honetarako sarbiderik.",
"Oops! This form is no longer published.": "Hara! Formulario hau ez dago argitaratuta egoteari utzi dio."
"Oops! This form is no longer published.": "Hara! Formularioak argitaratuta egoteari utzi dio."
},
"FormPage": {
"There was an error submitting your form. Please try again.": "Errore bat egon da zure formularioa bidaltzean. Saiatu berriro."
@ -1468,11 +1468,11 @@
},
"MappedFieldsConfig": {
"Clear": "Garbitu",
"Map fields": "Mapeatu eremuak",
"Mapped": "Mapeatuta",
"Map fields": "Mapaketatu eremuak",
"Mapped": "Mapaketatuta",
"Select All": "Hautatu guztia",
"Unmapped": "Desmapeatuta",
"Unmap fields": "Desmapeatu eremuak"
"Unmapped": "Esleitu gabe",
"Unmap fields": "Utzi eremuak esleitzeari"
},
"CreateTeamModal": {
"Cancel": "Utzi",
@ -1481,7 +1481,7 @@
"Team name": "Taldearen izena",
"Team name is required": "Taldearen izena beharrezkoa da",
"Work as a Team": "Egin lan taldean",
"Billing is not supported in grist-core": "Fakturazioa ez da bateragarria grist-core-rekin",
"Billing is not supported in grist-core": "grist-corek ez du fakturazioa onartzen",
"Choose a name and url for your team site": "Aukeratu zure talderako izen eta URL bat",
"Create site": "Sortu gunea",
"Domain name is invalid": "Domeinuaren izenak ez du balio",
@ -1490,8 +1490,8 @@
},
"AdminPanel": {
"Current version of Grist": "Grist-en uneko bertsioa",
"Admin Panel": "Administratzaile Panela",
"Current": "Uneko",
"Admin Panel": "Administratzailearen mahaigaina",
"Current": "Unekoa",
"Help us make Grist better": "Lagun gaitzazu Grist hobetzen",
"Home": "Hasiera",
"Sponsor": "Babeslea",
@ -1502,7 +1502,7 @@
"Error": "Errorea",
"Error checking for updates": "Errorea eguneraketak bilatzean",
"Grist is up to date": "Grist egunean dago",
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future since session IDs have been updated to be inherently cryptographically secure.": "Grist-ek erabiltzailearen saioen cookieak giltza sekretu batekin sinatzen ditu. Ezarri giltza hau GRIST_SESSION_SECRET aldagaiaren bidez. Grist kodifikazio gogorreko akats batera erortzen da ezarrita ez dagoenean. Abisu hau etorkizunean ezaba dezakegu... v1.1.16tik sortutako saio-identifikazioak kriptografikoki seguruak direlako.",
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future since session IDs have been updated to be inherently cryptographically secure.": "Grist-ek erabiltzaileen saioen cookieak gako sekretu batekin sinatzen ditu. Ezarri gako hau GRIST_SESSION_SECRET aldagaiaren bidez. Ezarrita ez dagoenean, defektuzkora joko du. Abisu hau etorkizunean ezaba dezakegu v1.1.16tik aurrera kriptografikoki seguruak diren saio-identifikazioak sortzen direlako.",
"Learn more.": "Ikasi gehiago.",
"Newer version available": "Eskuragarri dago bertsio berriago bat",
"OK": "Ados",
@ -1516,9 +1516,9 @@
"Grist allows different types of authentication to be configured, including SAML and OIDC. We recommend enabling one of these if Grist is accessible over the network or being made available to multiple people.": "Gristek autentifikazio mota ezberdinak konfiguratzen uzten du, SAML eta OIDC barne. Horietako bat baimentzea gomendatzen dugu Grist lokaletik kanpo badago edo pertsona askoren eskura jartzen bada.",
"Results": "Emaitzak",
"Self Checks": "Norbere egiaztatzeak",
"Or, as a fallback, you can set: {{bootKey}} in the environment and visit: {{url}}": "Edo, falback gisa, ingurunean {{bootKey}} jar dezakezu eta {{url}} bisitatu",
"Or, as a fallback, you can set: {{bootKey}} in the environment and visit: {{url}}": "Edo, bigarren aukera gisa, aldagaian {{bootKey}} jar dezakezu eta {{url}} bisitatu",
"Grist allows different types of authentication to be configured, including SAML and OIDC. We recommend enabling one of these if Grist is accessible over the network or being made available to multiple people.": "Gristek autentifikazio mota ezberdinak konfiguratzen uzten du, SAML eta OIDC barne. Horietako bat baimentzea gomendatzen dugu Grist lokaletik kanpo badago edo pertsona askoren eskura jartzen bada.",
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future as session IDs generated since v1.1.16 are inherently cryptographically secure.": "Grist-ek erabiltzailearen saioen cookieak giltza sekretu batekin sinatzen ditu. Ezarri giltza hau GRIST_SESSION_SECRET aldagaiaren bidez. Grist kodifikazio gogorreko akats batera erortzen da ezarrita ez dagoenean. Abisu hau etorkizunean ezaba dezakegu... v1.1.16tik sortutako saio-identifikazioak kriptografikoki seguruak direlako.",
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future as session IDs generated since v1.1.16 are inherently cryptographically secure.": "Grist-ek erabiltzaileen saioen cookieak gako sekretu batekin sinatzen ditu. Ezarri gako hau GRIST_SESSION_SECRET aldagaiaren bidez. Ezarrita ez dagoenean, defektuzkora joko du. Abisu hau etorkizunean ezaba dezakegu v1.1.16tik aurrera kriptografikoki seguruak diren saio-identifikazioak sortzen direlako.",
"Support Grist Labs on GitHub": "Eman babesa Grist Labs-i GitHuben",
"Telemetry": "Telemetria",
"Version": "Bertsioa",
@ -1532,10 +1532,12 @@
"Current authentication method": "Uneko autentifikazio-metodoa",
"No fault detected.": "Ez da akatsik antzeman.",
"Notes": "Oharrak",
"You do not have access to the administrator panel.\nPlease log in as an administrator.": "Ez duzu administratzaile-mahaigainera sarbiderik. Hasi saioa administratzaile gisa.",
"You do not have access to the administrator panel.\nPlease log in as an administrator.": "Ez duzu administratzailearen mahaigainera sarbiderik.\nHasi saioa administratzaile gisa.",
"Key to sign sessions with": "Saioak sinatzeko gakoa",
"Grist allows for very powerful formulas, using Python. We recommend setting the environment variable GRIST_SANDBOX_FLAVOR to gvisor if your hardware supports it (most will), to run formulas in each document within a sandbox isolated from other documents and isolated from the network.": "Gristek formula oso boteretsuak onartzen ditu, Piton erabiliz. GRIST_SANDBOX_FLAVOR ingurumen aldagaia gvisorrari jartzea gomendatzen dugu, zure hardwareak eusten badio (gehienak borondatezkoak), dokumentu bakoitzean formulak exekutatzeko beste dokumentu batzuetatik isolatutako eta saretik isolatutako sandbox baten barruan.",
"Session Secret": "Saioaren gakoa"
"Grist allows for very powerful formulas, using Python. We recommend setting the environment variable GRIST_SANDBOX_FLAVOR to gvisor if your hardware supports it (most will), to run formulas in each document within a sandbox isolated from other documents and isolated from the network.": "Gristek formula oso boteretsuak onartzen ditu, Python erabiliz. Dokumentu bakoitzean beste dokumentu batzuetatik eta saretik isolatutako sandbox baten barruan formulak exekutatzeko, GRIST_SANDBOX_FLAVOR aldagaia gvisor-era aldatzea gomendatzen dugu, zure hardwarea bateragarria bada (gehienak badira).",
"Session Secret": "Saioaren gakoa",
"Enable Grist Enterprise": "Gaitu Grist Enterprise",
"Enterprise": "Enterprise"
},
"Columns": {
"Remove Column": "Kendu zutabea"
@ -1545,7 +1547,7 @@
"No values in show column of referenced table": "Ez dago baliorik erakusten den zutabean edo erreferentzia-taulan"
},
"Toggle": {
"Checkbox": "Aukera-kutxa",
"Checkbox": "Kontrol-laukia",
"Field Format": "Eremuaren formatua",
"Switch": "Aldatu"
},
@ -1577,22 +1579,22 @@
"Table": "Taula",
"Calendar": "Egutegia",
"Card": "Txartela",
"Card List": "Txartelen zerrenda"
"Card List": "Txartel-zerrenda"
},
"TimingPage": {
"Formula timer": "Formula-kronometroa-",
"Loading timing data. Don't close this tab.": "Denboren datuak kargatzen. Ez itxi fitxa hau.",
"Loading timing data. Don't close this tab.": "Kronometroaren datuak kargatzen. Ez itxi fitxa hau.",
"Max Time (s)": "Denbora maximoa (s)",
"Average Time (s)": "Batez besteko denbora(k) (s)",
"Column ID": "Zutabearen IDa",
"Table ID": "Taularen IDa",
"Total Time (s)": "Denbora guztira (s)",
"Number of Calls": "Eskaera-kopurua"
"Number of Calls": "Eskaera kopurua"
},
"WelcomeSitePicker": {
"Welcome back": "Ongi etorri",
"You have access to the following Grist sites.": "Grist gune hauetarako sarbidea duzu.",
"You can always switch sites using the account menu.": "Beti alda ditzakezu guneak kontuaren menua erabiliz."
"You can always switch sites using the account menu.": "Kontuaren menua erabiliz beti alda ditzakezu guneak."
},
"SearchModel": {
"Search all pages": "Bilatu orri guztiak",
@ -1609,8 +1611,8 @@
"Hidden fields": "Ezkutatutako eremuak"
},
"CustomView": {
"Some required columns aren't mapped": "Nahitaezko zutabe batzuk ez daude mapeatuta",
"To use this widget, please map all non-optional columns from the creator panel on the right.": "Widget hau erabiltzeko, mapeatu aukerakoak ez diren zutabeak eskuineko sortzaileen mahaigainetik."
"Some required columns aren't mapped": "Nahitaezko zutabe batzuk ez daude esleituta",
"To use this widget, please map all non-optional columns from the creator panel on the right.": "Widget hau erabiltzeko, esleitu aukerakoak ez diren zutabeak sortzaileen mahaigainetik, eskuinean."
},
"FormContainer": {
"Build your own form": "Sortu zure formularioa",
@ -1633,5 +1635,50 @@
},
"DropdownConditionEditor": {
"Enter condition.": "Sartu baldintza."
},
"DocTutorial": {
"Click to expand": "Egin klik hedatzeko",
"Do you want to restart the tutorial? All progress will be lost.": "Berriz hasi nahi duzu tutoriala? Orain arte egindakoa galduko da.",
"Next": "Hurrengoa",
"Previous": "Aurrekoa",
"Restart": "Hasi berriz",
"End tutorial": "Tutorialaren amaiera",
"Finish": "Amaitu"
},
"OnboardingCards": {
"3 minute video tour": "3 minutuko bideo-bisitaldia",
"Complete our basics tutorial": "Burutu oinarrizko tutoriala",
"Complete the tutorial": "Burutu tutoriala",
"Learn the basic of reference columns, linked widgets, column types, & cards.": "Ikasi erreferentzia-zutabeen, lotutako widgeten, zutabe-moten eta txartelen oinarriak."
},
"OnboardingPage": {
"Go hands-on with the Grist Basics tutorial": "Murgildu Gristen oinarrizko tutorialean",
"Next step": "Hurrengo urratsa",
"Skip step": "Utzi egin gabe",
"Skip tutorial": "Utzi tutoriala egin gabe",
"Welcome": "Ongi etorri",
"What brings you to Grist (you can select multiple)?": "Zerk zakartza Gristera? (bat baino gehiago hautatu dezakezu)?",
"Back": "Atzera",
"Tell us who you are": "Esaguzu nor zaren",
"Discover Grist in 3 minutes": "Ezagutu Grist 3 minututan",
"Go to the tutorial!": "Joan tutorialera!",
"Type here": "Idatzi hemen",
"What is your role?": "Zein da zure rola?",
"What organization are you with?": "Zein erakunderekin jarduten duzu?",
"Your role": "Zure rola",
"Your organization": "Zure erakundea"
},
"ToggleEnterpriseWidget": {
"Grist Enterprise is **enabled**.": "Grist Enterprise **gaituta** dago.",
"Disable Grist Enterprise": "Ezgaitu Grist Enterprise",
"Enable Grist Enterprise": "Gaitu Grist Enterprise",
"An activation key is used to run Grist Enterprise after a trial period\nof 30 days has expired. Get an activation key by [signing up for Grist\nEnterprise]({{signupLink}}). You do not need an activation key to run\nGrist Core.\n\nLearn more in our [Help Center]({{helpCenter}}).": "Aktibazio-gako bat erabili da 30 eguneko epea iraungi eta probaldiaren\nondoren Grist Enterprise exekutatzeko. Eskuratu aktibazio-gako bat [Grist\nEnterprise-n izena eman]({{signupLink}})ez. Ez duzu aktibazio-gakorik behar\nGrist Core exekutatzeko.\n\nLortu informazio gehiago gure [Laguntza Gunea]({{helpCenter}})n."
},
"ViewLayout": {
"Delete data and this widget.": "Ezabatu datuak eta widgeta.",
"Keep data and delete widget. Table will remain available in {{rawDataLink}}": "Mantendu datuak eta ezabatu widgeta. Taulak erabilgarri egoten jarraituko du {{rawDataLink}}(e)n",
"Table {{tableName}} will no longer be visible": "{{tableName}} taula ez da ikusgai egongo aurrerantzean",
"raw data page": "datu gordinen orria",
"Delete": "Ezabatu"
}
}

@ -1234,7 +1234,7 @@
"Event Types": "Types d'événements",
"Memo": "Mémo",
"Ready Column": "Colonne de déclenchement",
"Removed webhook.": "Suppression du webhook.",
"Removed webhook.": "Point d'ancrage supprimé.",
"Filter for changes in these columns (semicolon-separated ids)": "Filtrer les changements dans ces colonnes (identifiants séparés par des points-virgules)",
"Status": "Statut",
"URL": "URL",
@ -1633,5 +1633,37 @@
"Number of Calls": "Nombre d'appels",
"Table ID": "ID de la table",
"Total Time (s)": "Temps total"
},
"DocTutorial": {
"Next": "Suivant",
"Restart": "Redémarrer",
"Click to expand": "Cliquez pour agrandir",
"End tutorial": "Fin du tutoriel",
"Do you want to restart the tutorial? All progress will be lost.": "Voulez-vous recommencer le tutoriel? Tous les progrès seront perdus.",
"Previous": "Précédent",
"Finish": "Finir"
},
"OnboardingCards": {
"Complete our basics tutorial": "Complétez notre tutoriel des bases",
"Learn the basic of reference columns, linked widgets, column types, & cards.": "Apprenez les bases des colonnes de référence, des vues liées, des types de colonnes et des fiches.",
"3 minute video tour": "Visite guidée vidéo de 3 minutes",
"Complete the tutorial": "Compléter le tutoriel"
},
"OnboardingPage": {
"Back": "Retour",
"Discover Grist in 3 minutes": "Découvrez Grist en 3 minutes",
"Go hands-on with the Grist Basics tutorial": "Mettez la main à la pâte avec le tutoriel des bases Grist",
"Type here": "Tapez ici",
"Welcome": "Bienvenue",
"What organization are you with?": "Quelle est l'organisation à laquelle vous appartenez?",
"Your organization": "Votre organisation",
"Your role": "Votre rôle",
"Next step": "Prochaine étape",
"Skip step": "Sauter cette étape",
"Skip tutorial": "Sauter le tutoriel",
"Go to the tutorial!": "Allez au tutoriel!",
"Tell us who you are": "Dites-nous qui vous êtes",
"What brings you to Grist (you can select multiple)?": "Qu'est-ce qui vous amène à Grist (vous pouvez en sélectionner plusieurs)?",
"What is your role?": "Quel est votre rôle?"
}
}

@ -1297,7 +1297,8 @@
"Removed webhook.": "Webhook removido.",
"Webhook Id": "Id do webhook",
"Table": "Tabela",
"Filter for changes in these columns (semicolon-separated ids)": "Filtrar as alterações nessas Colunas (ids separados por ponto e vírgula)"
"Filter for changes in these columns (semicolon-separated ids)": "Filtrar as alterações nessas Colunas (ids separados por ponto e vírgula)",
"Header Authorization": "Autorização de cabeçalho"
},
"FieldContextMenu": {
"Copy anchor link": "Copiar link de âncora",
@ -1621,7 +1622,9 @@
"Key to sign sessions with": "Chave para assinar sessões com",
"Session Secret": "Segredo da sessão",
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future since session IDs have been updated to be inherently cryptographically secure.": "O Grist assina os cookies de sessão do usuário com uma chave secreta. Defina essa chave por meio da variável de ambiente GRIST_SESSION_SECRET. O Grist retorna a um padrão codificado quando ele não está definido. Poderemos remover esse aviso no futuro, pois os IDs de sessão gerados desde a versão 1.1.16 são inerentemente seguros em termos de criptografia.",
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future as session IDs generated since v1.1.16 are inherently cryptographically secure.": "O Grist assina os cookies de sessão do usuário com uma chave secreta. Defina essa chave por meio da variável de ambiente GRIST_SESSION_SECRET. O Grist retorna a um padrão codificado quando ele não está definido. Poderemos remover esse aviso no futuro, pois os IDs de sessão gerados desde a versão 1.1.16 são inerentemente seguros em termos de criptografia."
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future as session IDs generated since v1.1.16 are inherently cryptographically secure.": "O Grist assina os cookies de sessão do usuário com uma chave secreta. Defina essa chave por meio da variável de ambiente GRIST_SESSION_SECRET. O Grist retorna a um padrão codificado quando ele não está definido. Poderemos remover esse aviso no futuro, pois os IDs de sessão gerados desde a versão 1.1.16 são inerentemente seguros em termos de criptografia.",
"Enterprise": "Empresarial",
"Enable Grist Enterprise": "Habilitar a Grist Empresarial"
},
"Field": {
"No choices configured": "Nenhuma opção configurada",
@ -1696,5 +1699,50 @@
"Loading timing data. Don't close this tab.": "Carregando dados de tempo. Não feche essa guia.",
"Number of Calls": "Número de chamadas",
"Table ID": "ID da tabela"
},
"DocTutorial": {
"Do you want to restart the tutorial? All progress will be lost.": "Você quer reiniciar o tutorial? Todo o progresso será perdido.",
"Finish": "Terminar",
"Restart": "Reiniciar",
"Click to expand": "Clique para expandir",
"Previous": "Anterior",
"End tutorial": "Finalizar tutorial",
"Next": "Próximo"
},
"OnboardingCards": {
"3 minute video tour": "Vídeo tour de 3 minutos",
"Complete our basics tutorial": "Conclua nosso tutorial básico",
"Complete the tutorial": "Concluir o tutorial",
"Learn the basic of reference columns, linked widgets, column types, & cards.": "Aprenda o básico sobre Colunas de referência, widgets vinculados, tipos de colunas e cartões."
},
"OnboardingPage": {
"Discover Grist in 3 minutes": "Descubra Grist em 3 minutos",
"Go hands-on with the Grist Basics tutorial": "Pratique com o tutorial Conceitos Básicos do Grist",
"Go to the tutorial!": "Vá para o tutorial!",
"Next step": "Próximo passo",
"Skip tutorial": "Pular o tutorial",
"Tell us who you are": "Diga-nos quem você é",
"Type here": "Digite aqui",
"What brings you to Grist (you can select multiple)?": "O que o traz ao Grist (você pode selecionar várias opções)?",
"What is your role?": "Qual é a sua função?",
"What organization are you with?": "Em que organização você está?",
"Your organization": "Sua organização",
"Your role": "Sua função",
"Skip step": "Pular passo",
"Back": "Voltar",
"Welcome": "Bem-vindo"
},
"ToggleEnterpriseWidget": {
"Disable Grist Enterprise": "Desativar o Grist Empresarial",
"Enable Grist Enterprise": "Habilitar a Grist Empresarial",
"Grist Enterprise is **enabled**.": "O Grist Empresarial está **habilitado**.",
"An activation key is used to run Grist Enterprise after a trial period\nof 30 days has expired. Get an activation key by [signing up for Grist\nEnterprise]({{signupLink}}). You do not need an activation key to run\nGrist Core.\n\nLearn more in our [Help Center]({{helpCenter}}).": "Uma chave de ativação é usada para executar o Grist Enterprise após um período de avaliação\nde 30 dias tenha expirado. Obtenha uma chave de ativação [inscrevendo-se no Grist\nEmpresarial]({{signupLink}}). Você não precisa de uma chave de ativação para executar o\nGrist Core.\n\nSaiba mais em nossa [Central de Ajuda]({{helpCenter}})."
},
"ViewLayout": {
"Delete": "Excluir",
"Delete data and this widget.": "Excluir dados e este widget.",
"Keep data and delete widget. Table will remain available in {{rawDataLink}}": "Mantenha os dados e exclua o widget. A tabela permanecerá disponível em {{rawDataLink}}",
"Table {{tableName}} will no longer be visible": "A tabela {{tableName}} não estará mais visível",
"raw data page": "página de dados brutos"
}
}

@ -517,7 +517,8 @@
"Visit our {{link}} to learn more about Grist.": "Navštíviť náš {{link}} a dozvedieť sa viac o Grist.",
"Learn more in our {{helpCenterLink}}, or find an expert via our {{sproutsProgram}}.": "Viac informácií nájdete v našom {{helpCenterLink}} alebo nájdite odborníka prostredníctvom nášho {{sproutsProgram}}.",
"Interested in using Grist outside of your team? Visit your free ": "Máte záujem používať Grist mimo váš tím? Navštívte svoje bezplatné ",
"Sign up": "Prihlásiť sa"
"Sign up": "Prihlásiť sa",
"Learn more in our {{helpCenterLink}}.": "Zistiť viac v našom {{helpCenterLink}}."
},
"Importer": {
"Merge rows that match these fields:": "Zlúčiť riadky, ktoré zodpovedajú týmto poliam:",
@ -1117,7 +1118,8 @@
"URL": "URL",
"Webhook Id": "Webhook ID",
"Table": "Tabuľka",
"Filter for changes in these columns (semicolon-separated ids)": "Filtrovať zmeny v týchto stĺpcoch (identifikátory oddelené bodkočiarkou)"
"Filter for changes in these columns (semicolon-separated ids)": "Filtrovať zmeny v týchto stĺpcoch (identifikátory oddelené bodkočiarkou)",
"Header Authorization": "Autorizácia Hlavičky"
},
"FormulaAssistant": {
"Capabilities": "Schopnosti",
@ -1632,5 +1634,37 @@
},
"Columns": {
"Remove Column": "Odobrať stĺpec"
},
"DocTutorial": {
"End tutorial": "Ukončiť tutorial",
"Finish": "Dokončiť",
"Next": "Ďaľší",
"Previous": "Predošlý",
"Restart": "Reštart",
"Do you want to restart the tutorial? All progress will be lost.": "Chcete reštartovať výukový program? Všetok pokrok sa stratí.",
"Click to expand": "Kliknutím rozbaliť"
},
"OnboardingCards": {
"Complete our basics tutorial": "Náš kompletný základný návod",
"Complete the tutorial": "Dokončiť tutoriál",
"Learn the basic of reference columns, linked widgets, column types, & cards.": "Naučiť sa základ referenčných stĺpcov, prepojených miniaplikácií, typov stĺpcov a kariet.",
"3 minute video tour": "3 minútová videoprehliadka"
},
"OnboardingPage": {
"Back": "Späť",
"Discover Grist in 3 minutes": "Preskúmať Grist za 3 minúty",
"Go hands-on with the Grist Basics tutorial": "Praktický tutoriál Základy Gristu",
"Go to the tutorial!": "Prejsť na tutoriál!",
"Next step": "Ďalší krok",
"Skip step": "Prekočiť krok",
"Skip tutorial": "Preskočiť tutoriál",
"Tell us who you are": "Povedz nám, kto si",
"Welcome": "Vitajte",
"What brings you to Grist (you can select multiple)?": "Čo vás privádza do Gristu (môžete vybrať viacero)?",
"What is your role?": "Aká je vaša úloha?",
"What organization are you with?": "Aká je Vaša organizácia?",
"Type here": "Zadať sem",
"Your organization": "Vaša organizácia",
"Your role": "Vaša úloha"
}
}

@ -1558,7 +1558,9 @@
"Key to sign sessions with": "Ključ za podpisovanje sej",
"Session Secret": "Skrivnost seje",
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future since session IDs have been updated to be inherently cryptographically secure.": "Grist podpisuje piškotke uporabniške seje s skrivnim ključem. Ta ključ nastavite prek spremenljivke okolja GRIST_SESSION_SECRET. Grist se vrne na trdo kodirano privzeto vrednost, če ni nastavljena. To obvestilo bomo morda odstranili v prihodnosti, saj so ID-ji sej, ustvarjeni od različice 1.1.16, sami po sebi kriptografsko varni.",
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future as session IDs generated since v1.1.16 are inherently cryptographically secure.": "Grist podpisuje piškotke uporabniške seje s skrivnim ključem. Ta ključ nastavite prek spremenljivke okolja GRIST_SESSION_SECRET. Grist se vrne na trdo kodirano privzeto vrednost, če ni nastavljena. To obvestilo bomo morda odstranili v prihodnosti, saj so ID-ji sej, ustvarjeni od različice 1.1.16, sami po sebi kriptografsko varni."
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future as session IDs generated since v1.1.16 are inherently cryptographically secure.": "Grist podpisuje piškotke uporabniške seje s skrivnim ključem. Ta ključ nastavite prek spremenljivke okolja GRIST_SESSION_SECRET. Grist se vrne na trdo kodirano privzeto vrednost, če ni nastavljena. To obvestilo bomo morda odstranili v prihodnosti, saj so ID-ji sej, ustvarjeni od različice 1.1.16, sami po sebi kriptografsko varni.",
"Enable Grist Enterprise": "Omogoči Grist Enterprise",
"Enterprise": "Podjetje"
},
"ChoiceEditor": {
"Error in dropdown condition": "Napaka v spustnem meniju",
@ -1633,5 +1635,50 @@
"Average Time (s)": "Povprečni čas (i)",
"Column ID": "ID stolpca",
"Formula timer": "Časovnik formule"
},
"DocTutorial": {
"Click to expand": "Kliknite za razširitev",
"Do you want to restart the tutorial? All progress will be lost.": "Ali želite znova zagnati učbenik? Ves napredek bo izgubljen.",
"End tutorial": "Končaj vadnico",
"Finish": "Končaj",
"Next": "Naslednji",
"Previous": "Prejšnji",
"Restart": "Ponovni zagon"
},
"OnboardingCards": {
"3 minute video tour": "3 minutni video ogled",
"Complete our basics tutorial": "Dokončaj našo vadnico o osnovah",
"Complete the tutorial": "Dokončaj vadnico",
"Learn the basic of reference columns, linked widgets, column types, & cards.": "Nauči se osnov referenčnih stolpcev, povezanih pripomočkov, vrst stolpcev in kartic."
},
"OnboardingPage": {
"Back": "Nazaj",
"Next step": "Naslednji korak",
"Skip step": "Preskoči korak",
"Skip tutorial": "Preskoči vadnico",
"Tell us who you are": "Povej nam, kdo si",
"Type here": "Piši tukaj",
"Welcome": "Dobrodošel",
"What brings you to Grist (you can select multiple)?": "Kaj te je pripeljalo do Grista (lahko izbereš več)?",
"What is your role?": "Kakšna je tvoja vloga?",
"What organization are you with?": "V kateri organizaciji si?",
"Your organization": "Tvoja organizacija",
"Your role": "Tvoja vloga",
"Go hands-on with the Grist Basics tutorial": "Preizkusi vadnico Osnove Grista",
"Discover Grist in 3 minutes": "Odkrij Grist v 3 minutah",
"Go to the tutorial!": "Pojdi na vadnico!"
},
"ToggleEnterpriseWidget": {
"Disable Grist Enterprise": "Onemogoči Grist Enterprise",
"Enable Grist Enterprise": "Omogoči Grist Enterprise",
"Grist Enterprise is **enabled**.": "Grist Enterprise je **omogočen**.",
"An activation key is used to run Grist Enterprise after a trial period\nof 30 days has expired. Get an activation key by [signing up for Grist\nEnterprise]({{signupLink}}). You do not need an activation key to run\nGrist Core.\n\nLearn more in our [Help Center]({{helpCenter}}).": "Za zagon Grist Enterprise po poskusnem obdobju 30 dni potrebujete aktivacijski ključ. Pridobite aktivacijski ključ tako, da se [prijavite za Grist\nEnterprise]({{signupLink}}). Za delovanje Grist Core ne potrebujete aktivacijskega ključa\n.\n\nIzvedite več v našem [centru za pomoč]({{helpCenter}})."
},
"ViewLayout": {
"Delete": "Briši",
"Delete data and this widget.": "Izbriši podatke in ta pripomoček.",
"Keep data and delete widget. Table will remain available in {{rawDataLink}}": "Ohranite podatke in izbrišite pripomoček. Tabela bo ostala na voljo v {{rawDataLink}}",
"Table {{tableName}} will no longer be visible": "Tabela {{tableName}} ne bo več vidna",
"raw data page": "stran z neobdelanimi podatki"
}
}

@ -44,6 +44,8 @@ import {Shares1701557445716 as Shares} from 'app/gen-server/migration/1701557445
import {Billing1711557445716 as BillingFeatures} from 'app/gen-server/migration/1711557445716-Billing';
import {UserLastConnection1713186031023
as UserLastConnection} from 'app/gen-server/migration/1713186031023-UserLastConnection';
import {ActivationEnabled1722529827161
as ActivationEnabled} from 'app/gen-server/migration/1722529827161-Activation-Enabled';
const home: HomeDBManager = new HomeDBManager();
@ -53,7 +55,7 @@ const migrations = [Initial, Login, PinDocs, UserPicture, DisplayEmail, DisplayE
ExternalBilling, DocOptions, Secret, UserOptions, GracePeriodStart,
DocumentUsage, Activations, UserConnectId, UserUUID, UserUniqueRefUUID,
Forks, ForkIndexes, ActivationPrefs, AssistantLimit, Shares, BillingFeatures,
UserLastConnection];
UserLastConnection, ActivationEnabled];
// Assert that the "members" acl rule and group exist (or not).
function assertMembersGroup(org: Organization, exists: boolean) {

@ -33,6 +33,16 @@ setOptionsModifyFunc(({chromeOpts, firefoxOpts}) => {
// Set "kiosk" printing that saves to PDF without offering any dialogs. This applies to regular
// (non-headless) Chrome. On headless Chrome, no dialog or output occurs regardless.
chromeOpts.addArguments("--kiosk-printing");
// Latest chrome version 127, has started ignoring alerts and popups when controlled via a
// webdriver.
// https://github.com/SeleniumHQ/selenium/issues/14290
// According to the article above, popups and alerts are still shown in `BiDi` sessions. While we
// don't have latest webdriver library (where the new `enableBiDi` method is exposed), it can be
// toggled by using the `set` method in `capabilities` interface, as it is done here (long URL):
// eslint-disable-next-line max-len
// https://github.com/shs96c/selenium/blob/ff82c4af6a493321d9eaec6ba8fa8589e4aa824d/javascript/node/selenium-webdriver/firefox.js#L415
chromeOpts.set('webSocketUrl', true);
chromeOpts.setUserPreferences({
// Don't show popups to save passwords, which are shown when running against a deployment when

Loading…
Cancel
Save