mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) updates from grist-core
This commit is contained in:
commit
055522d374
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: gristlabs
|
67
.github/workflows/main.yml
vendored
67
.github/workflows/main.yml
vendored
@ -10,24 +10,35 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
build_and_test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.9]
|
||||
node-version: [14.x]
|
||||
tests:
|
||||
- ':lint:python:client:common:smoke:'
|
||||
- ':server-1-of-2:'
|
||||
- ':server-2-of-2:'
|
||||
- ':nbrowser-1-of-5:'
|
||||
- ':nbrowser-2-of-5:'
|
||||
- ':nbrowser-3-of-5:'
|
||||
- ':nbrowser-4-of-5:'
|
||||
- ':nbrowser-5-of-5:'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
cache: 'pip'
|
||||
|
||||
- name: Install Python packages
|
||||
run: |
|
||||
@ -38,9 +49,11 @@ jobs:
|
||||
run: yarn install
|
||||
|
||||
- name: Run eslint
|
||||
if: contains(matrix.tests, ':lint:')
|
||||
run: yarn run lint:ci
|
||||
|
||||
- name: Make sure bucket is versioned
|
||||
if: contains(matrix.tests, ':server-')
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: administrator
|
||||
AWS_SECRET_ACCESS_KEY: administrator
|
||||
@ -49,15 +62,27 @@ jobs:
|
||||
- name: Build Node.js code
|
||||
run: yarn run build:prod
|
||||
|
||||
|
||||
- name: Run smoke test
|
||||
if: contains(matrix.tests, ':smoke:')
|
||||
run: VERBOSE=1 DEBUG=1 MOCHA_WEBDRIVER_HEADLESS=1 yarn run test:smoke
|
||||
|
||||
- name: Run python tests
|
||||
if: contains(matrix.tests, ':python:')
|
||||
run: yarn run test:python
|
||||
|
||||
- name: Run client tests
|
||||
if: contains(matrix.tests, ':client:')
|
||||
run: yarn run test:client
|
||||
|
||||
- name: Run common tests
|
||||
if: contains(matrix.tests, ':common:')
|
||||
run: yarn run test:common
|
||||
|
||||
- name: Run server tests with minio and redis
|
||||
run: MOCHA_WEBDRIVER_HEADLESS=1 yarn run test:server
|
||||
if: contains(matrix.tests, ':server-')
|
||||
run: |
|
||||
export TEST_SPLITS=$(echo $TESTS | sed "s/.*:server-\([^:]*\).*/\1/")
|
||||
MOCHA_WEBDRIVER_HEADLESS=1 yarn run test:server
|
||||
env:
|
||||
GRIST_DOCS_MINIO_ACCESS_KEY: administrator
|
||||
GRIST_DOCS_MINIO_SECRET_KEY: administrator
|
||||
@ -68,15 +93,12 @@ jobs:
|
||||
GRIST_DOCS_MINIO_BUCKET: grist-docs-test
|
||||
|
||||
- name: Run main tests without minio and redis
|
||||
run: MOCHA_WEBDRIVER_HEADLESS=1 yarn run test --exclude '_build/test/server/**/*'
|
||||
|
||||
- name: Update candidate branch
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
uses: ad-m/github-push-action@8407731efefc0d8f72af254c74276b7a90be36e1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branch: latest_candidate
|
||||
force: true
|
||||
if: contains(matrix.tests, ':nbrowser-')
|
||||
run: |
|
||||
export TEST_SPLITS=$(echo $TESTS | sed "s/.*:nbrowser-\([^:]*\).*/\1/")
|
||||
MOCHA_WEBDRIVER_HEADLESS=1 yarn run test:nbrowser
|
||||
env:
|
||||
TESTS: ${{ matrix.tests }}
|
||||
|
||||
services:
|
||||
# https://github.com/bitnami/bitnami-docker-minio/issues/16
|
||||
@ -103,3 +125,18 @@ jobs:
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
|
||||
candidate:
|
||||
needs: build_and_test
|
||||
if: ${{ success() && github.event_name == 'push' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fetch new candidate branch
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Update candidate branch
|
||||
uses: ad-m/github-push-action@8407731efefc0d8f72af254c74276b7a90be36e1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branch: latest_candidate
|
||||
force: true
|
||||
|
@ -198,7 +198,7 @@ export class VisibleFieldsConfig extends Disposable {
|
||||
});
|
||||
return [
|
||||
cssHeader(
|
||||
cssFieldListHeader(dom.text((use) => `Visible ${use(this._fieldLabel)}`)),
|
||||
cssFieldListHeader(dom.text((use) => t("Visible {{label}}", {label: use(this._fieldLabel)}))),
|
||||
dom.maybe(
|
||||
(use) => Boolean(use(use(this._section.viewFields).getObservable()).length),
|
||||
() => (
|
||||
@ -215,7 +215,7 @@ export class VisibleFieldsConfig extends Disposable {
|
||||
dom.maybe(this._showVisibleBatchButtons, () =>
|
||||
cssRow(
|
||||
primaryButton(
|
||||
dom.text((use) => `Hide ${use(this._fieldLabel)}`),
|
||||
dom.text((use) => t("Hide {{label}}", {label: use(this._fieldLabel)})),
|
||||
dom.on('click', () => this._removeSelectedFields()),
|
||||
),
|
||||
basicButton(
|
||||
@ -234,7 +234,7 @@ export class VisibleFieldsConfig extends Disposable {
|
||||
testId('collapse-hidden'),
|
||||
),
|
||||
// TODO: show `hidden column` only when some fields are hidden
|
||||
cssFieldListHeader(dom.text((use) => `Hidden ${use(this._fieldLabel)}`)),
|
||||
cssFieldListHeader(dom.text((use) => t("Hidden {{label}}", {label: use(this._fieldLabel)}))),
|
||||
dom.maybe(
|
||||
(use) => Boolean(use(this._hiddenFields.getObservable()).length && !use(this._collapseHiddenFields)),
|
||||
() => (
|
||||
@ -257,7 +257,7 @@ export class VisibleFieldsConfig extends Disposable {
|
||||
dom.maybe(this._showHiddenBatchButtons, () =>
|
||||
cssRow(
|
||||
primaryButton(
|
||||
dom.text((use) => `Show ${use(this._fieldLabel)}`),
|
||||
dom.text((use) => t("Show {{label}}", {label: use(this._fieldLabel)})),
|
||||
dom.on('click', () => this._addSelectedFields()),
|
||||
),
|
||||
basicButton(
|
||||
|
@ -150,7 +150,7 @@ export function select<T>(obs: Observable<T>, optionArray: MaybeObsArray<IOption
|
||||
return weasel.select(obs, optionArray, selectOptions, (op) =>
|
||||
cssOptionRow(
|
||||
op.icon ? cssOptionRowIcon(op.icon) : null,
|
||||
cssOptionLabel(op.label),
|
||||
cssOptionLabel(t(op.label)),
|
||||
renderOptionArgs ? renderOptionArgs(op) : null,
|
||||
testId('select-row')
|
||||
)
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "grist-core",
|
||||
"version": "1.0.7",
|
||||
"version": "1.0.8",
|
||||
"license": "Apache-2.0",
|
||||
"description": "Grist is the evolution of spreadsheets",
|
||||
"homepage": "https://github.com/gristlabs/grist-core",
|
||||
@ -13,10 +13,10 @@
|
||||
"build:prod": "buildtools/build.sh",
|
||||
"start:prod": "sandbox/run.sh",
|
||||
"test": "GRIST_SESSION_COOKIE=grist_test_cookie GRIST_TEST_LOGIN=1 TEST_SUPPORT_API_KEY=api_key_for_support TEST_CLEAN_DATABASE=true NODE_PATH=_build:_build/stubs:_build/ext mocha ${DEBUG:+-b --no-exit} --slow 8000 ${DEBUG:---forbid-only} -g ${GREP_TESTS:-''} '_build/test/common/*.js' '_build/test/client/*.js' '_build/test/nbrowser/*.js' '_build/test/server/**/*.js' '_build/test/gen-server/**/*.js'",
|
||||
"test:nbrowser": "GRIST_SESSION_COOKIE=grist_test_cookie GRIST_TEST_LOGIN=1 TEST_SUPPORT_API_KEY=api_key_for_support TEST_CLEAN_DATABASE=true NODE_PATH=_build:_build/stubs:_build/ext mocha ${DEBUG:+-b --no-exit} ${DEBUG:---forbid-only} -g ${GREP_TESTS:-''} --slow 8000 '_build/test/nbrowser/**/*.js'",
|
||||
"test:nbrowser": "TEST_SUITE=nbrowser TEST_SUITE_FOR_TIMINGS=nbrowser TIMINGS_FILE=test/timings/nbrowser.txt GRIST_SESSION_COOKIE=grist_test_cookie GRIST_TEST_LOGIN=1 TEST_SUPPORT_API_KEY=api_key_for_support TEST_CLEAN_DATABASE=true NODE_PATH=_build:_build/stubs:_build/ext mocha ${DEBUG:+-b --no-exit} ${DEBUG:---forbid-only} -g ${GREP_TESTS:-''} --slow 8000 -R test/xunit-file '_build/test/nbrowser/**/*.js'",
|
||||
"test:client": "GRIST_SESSION_COOKIE=grist_test_cookie NODE_PATH=_build:_build/stubs:_build/ext mocha ${DEBUG:+'-b'} '_build/test/client/**/*.js'",
|
||||
"test:common": "GRIST_SESSION_COOKIE=grist_test_cookie NODE_PATH=_build:_build/stubs:_build/ext mocha ${DEBUG:+'-b'} '_build/test/common/**/*.js'",
|
||||
"test:server": "GRIST_SESSION_COOKIE=grist_test_cookie NODE_PATH=_build:_build/stubs:_build/ext mocha ${DEBUG:+'-b'} '_build/test/server/**/*.js' '_build/test/gen-server/**/*.js'",
|
||||
"test:server": "TEST_SUITE=server TEST_SUITE_FOR_TIMINGS=server TIMINGS_FILE=test/timings/server.txt GRIST_SESSION_COOKIE=grist_test_cookie NODE_PATH=_build:_build/stubs:_build/ext mocha ${DEBUG:+'-b'} -R test/xunit-file '_build/test/server/**/*.js' '_build/test/gen-server/**/*.js'",
|
||||
"test:smoke": "NODE_PATH=_build:_build/stubs:_build/ext mocha _build/test/nbrowser/Smoke.js",
|
||||
"test:docker": "./test/test_under_docker.sh",
|
||||
"test:python": "sandbox_venv3/bin/python sandbox/grist/runtests.py ${GREP_TESTS:+discover -p \"test*${GREP_TESTS}*.py\"}",
|
||||
|
@ -744,7 +744,11 @@
|
||||
"Cannot drop items into Hidden Fields": "Elemente können nicht in ausgeblendeten Feldern abgelegt werden",
|
||||
"Clear": "Klären",
|
||||
"Hidden Fields cannot be reordered": "Ausgeblendete Felder können nicht neu sortiert werden",
|
||||
"Select All": "Alle auswählen"
|
||||
"Select All": "Alle auswählen",
|
||||
"Hide {{label}}": "{{label}} ausblenden",
|
||||
"Hidden {{label}}": "{{label}} Versteckt",
|
||||
"Show {{label}}": "{{label}} anzeigen",
|
||||
"Visible {{label}}": "Sichtbar {{label}}"
|
||||
},
|
||||
"WelcomeQuestions": {
|
||||
"Education": "Bildung",
|
||||
@ -803,7 +807,19 @@
|
||||
"menus": {
|
||||
"* Workspaces are available on team plans. ": "* Arbeitsbereiche sind in Teamplänen verfügbar. ",
|
||||
"Select fields": "Felder auswählen",
|
||||
"Upgrade now": "Jetzt aktualisieren"
|
||||
"Upgrade now": "Jetzt aktualisieren",
|
||||
"Numeric": "Numerisch",
|
||||
"DateTime": "DatumUhrzeit",
|
||||
"Choice List": "Auswahlliste",
|
||||
"Choice": "Auswahl",
|
||||
"Reference": "Referenz",
|
||||
"Reference List": "Referenzliste",
|
||||
"Attachment": "Anhang",
|
||||
"Any": "Jegliche",
|
||||
"Text": "Text",
|
||||
"Integer": "Ganze Zahl",
|
||||
"Toggle": "Umschalten",
|
||||
"Date": "Datum"
|
||||
},
|
||||
"modals": {
|
||||
"Cancel": "Abbrechen",
|
||||
|
@ -688,7 +688,11 @@
|
||||
"Cannot drop items into Hidden Fields": "Cannot drop items into Hidden Fields",
|
||||
"Clear": "Clear",
|
||||
"Hidden Fields cannot be reordered": "Hidden Fields cannot be reordered",
|
||||
"Select All": "Select All"
|
||||
"Select All": "Select All",
|
||||
"Visible {{label}}": "Visible {{label}}",
|
||||
"Hide {{label}}": "Hide {{label}}",
|
||||
"Hidden {{label}}": "Hidden {{label}}",
|
||||
"Show {{label}}": "Show {{label}}"
|
||||
},
|
||||
"WelcomeQuestions": {
|
||||
"Education": "Education",
|
||||
@ -747,7 +751,19 @@
|
||||
"menus": {
|
||||
"* Workspaces are available on team plans. ": "* Workspaces are available on team plans. ",
|
||||
"Select fields": "Select fields",
|
||||
"Upgrade now": "Upgrade now"
|
||||
"Upgrade now": "Upgrade now",
|
||||
"Any": "Any",
|
||||
"Numeric": "Numeric",
|
||||
"Text": "Text",
|
||||
"Integer": "Integer",
|
||||
"Toggle": "Toggle",
|
||||
"Date": "Date",
|
||||
"DateTime": "DateTime",
|
||||
"Choice": "Choice",
|
||||
"Choice List": "Choice List",
|
||||
"Reference": "Reference",
|
||||
"Reference List": "Reference List",
|
||||
"Attachment": "Attachment"
|
||||
},
|
||||
"modals": {
|
||||
"Cancel": "Cancel",
|
||||
|
@ -601,7 +601,11 @@
|
||||
"Cannot drop items into Hidden Fields": "No se pueden colocar elementos en campos ocultos",
|
||||
"Clear": "Limpiar",
|
||||
"Hidden Fields cannot be reordered": "Los campos ocultos no pueden ser reordenados",
|
||||
"Select All": "Seleccionar todo"
|
||||
"Select All": "Seleccionar todo",
|
||||
"Hide {{label}}": "Ocultar {{label}}",
|
||||
"Hidden {{label}}": "{{label}} oculta",
|
||||
"Show {{label}}": "Mostrar {{label}}",
|
||||
"Visible {{label}}": "{{label}} visible"
|
||||
},
|
||||
"WelcomeQuestions": {
|
||||
"Education": "Educación",
|
||||
@ -808,7 +812,19 @@
|
||||
"menus": {
|
||||
"* Workspaces are available on team plans. ": "* Los espacios de trabajo están disponibles en los planes de equipo. ",
|
||||
"Select fields": "Seleccionar campos",
|
||||
"Upgrade now": "Actualizar ahora"
|
||||
"Upgrade now": "Actualizar ahora",
|
||||
"Numeric": "Numérico",
|
||||
"Text": "Texto",
|
||||
"Integer": "Entero",
|
||||
"Date": "Fecha",
|
||||
"DateTime": "Fecha y hora",
|
||||
"Choice": "Elección",
|
||||
"Choice List": "Lista de opciones",
|
||||
"Reference": "Referencia",
|
||||
"Reference List": "Lista de referencia",
|
||||
"Attachment": "Adjunto",
|
||||
"Any": "Cualquiera",
|
||||
"Toggle": "Cambiar"
|
||||
},
|
||||
"modals": {
|
||||
"Cancel": "Cancelar",
|
||||
|
@ -653,7 +653,8 @@
|
||||
"Set formula": "Imposta formula",
|
||||
"Set trigger formula": "Imposta formula trigger",
|
||||
"TRIGGER FORMULA": "FORMULA TRIGGER",
|
||||
"Make into data column": "Trasforma in una colonna di dati"
|
||||
"Make into data column": "Trasforma in una colonna di dati",
|
||||
"DESCRIPTION": "DESCRIZIONE"
|
||||
},
|
||||
"FieldMenus": {
|
||||
"Save as common settings": "Salva come impostazioni comuni",
|
||||
@ -832,7 +833,11 @@
|
||||
"Cannot drop items into Hidden Fields": "Impossibile collocare elementi in campi nascosti",
|
||||
"Clear": "Svuota",
|
||||
"Hidden Fields cannot be reordered": "Impossibile riordinare i campi nascosti",
|
||||
"Select All": "Seleziona tutto"
|
||||
"Select All": "Seleziona tutto",
|
||||
"Hidden {{label}}": "Nascosta {{label}}",
|
||||
"Hide {{label}}": "Nascondi {{label}}",
|
||||
"Visible {{label}}": "Visibile {{label}}",
|
||||
"Show {{label}}": "Mostra {{label}}"
|
||||
},
|
||||
"WidgetTitle": {
|
||||
"Cancel": "Annulla",
|
||||
@ -853,7 +858,19 @@
|
||||
"menus": {
|
||||
"* Workspaces are available on team plans. ": "*Gli spazi di lavoro sono disponibili nel piano per i team. ",
|
||||
"Select fields": "Seleziona campi",
|
||||
"Upgrade now": "Aggiorna ora"
|
||||
"Upgrade now": "Aggiorna ora",
|
||||
"Any": "Qualsiasi",
|
||||
"Text": "Testo",
|
||||
"Integer": "Intero",
|
||||
"Toggle": "Interruttore",
|
||||
"Date": "Data",
|
||||
"DateTime": "Data/ora",
|
||||
"Reference": "Riferimento",
|
||||
"Reference List": "Lista di riferimenti",
|
||||
"Choice List": "Scelta da lista",
|
||||
"Attachment": "Allegato",
|
||||
"Numeric": "Numerico",
|
||||
"Choice": "Scelta"
|
||||
},
|
||||
"modals": {
|
||||
"Cancel": "Annulla",
|
||||
|
@ -344,7 +344,8 @@
|
||||
"Empty Columns_other": "Puste kolumny",
|
||||
"Enter formula": "Wprowadź formułę",
|
||||
"Make into data column": "Zrób z tego kolumnę danych",
|
||||
"Set trigger formula": "Ustawianie formuły wyzwalacza"
|
||||
"Set trigger formula": "Ustawianie formuły wyzwalacza",
|
||||
"DESCRIPTION": "OPIS"
|
||||
},
|
||||
"GridOptions": {
|
||||
"Zebra Stripes": "Paski zebry",
|
||||
@ -412,6 +413,53 @@
|
||||
"All Documents": "Wszystkie dokumenty",
|
||||
"Create Empty Document": "Utwórz pusty dokument",
|
||||
"Create Workspace": "Utwórz przestrzeń roboczą",
|
||||
"Access Details": "Szczegóły dostępu"
|
||||
"Access Details": "Szczegóły dostępu",
|
||||
"Rename": "Zmień nazwę",
|
||||
"Trash": "Kosz",
|
||||
"Workspaces": "Obszary robocze",
|
||||
"Workspace will be moved to Trash.": "Obszar roboczy zostanie przeniesiony do kosza.",
|
||||
"Import Document": "Importuj dokument",
|
||||
"Manage Users": "Zarządzanie użytkownikami"
|
||||
},
|
||||
"Importer": {
|
||||
"Select fields to match on": "Wybierz pola do dopasowania",
|
||||
"Merge rows that match these fields:": "Scal wiersze, które pasują do tych pól:",
|
||||
"Update existing records": "Aktualizowanie istniejących rekordów"
|
||||
},
|
||||
"MakeCopyMenu": {
|
||||
"Update": "Aktualizacja",
|
||||
"Update Original": "Zaktualizuj oryginał",
|
||||
"Workspace": "Obszar roboczy",
|
||||
"You do not have write access to the selected workspace": "Nie masz dostępu do zapisu w wybranej przestrzeni roboczej",
|
||||
"Cancel": "Anuluj",
|
||||
"As Template": "Jako szablon",
|
||||
"Include the structure without any of the data.": "Dołącz strukturę bez żadnych danych.",
|
||||
"Enter document name": "Wprowadź nazwę dokumentu",
|
||||
"However, it appears to be already identical.": "Wydaje się jednak, że jest już identyczny.",
|
||||
"It will be overwritten, losing any content not in this document.": "Zostanie on nadpisany, tracąc wszelkie treści nie znajdujące się w tym dokumencie.",
|
||||
"Name": "Nazwa",
|
||||
"No destination workspace": "Brak docelowej przestrzeni roboczej",
|
||||
"Organization": "Organizacja",
|
||||
"Overwrite": "Nadpisz",
|
||||
"Original Has Modifications": "Oryginał ma modyfikacje",
|
||||
"Original Looks Identical": "Oryginał Wygląda identycznie",
|
||||
"To save your changes, please sign up, then reload this page.": "Aby zapisać zmiany, proszę się zarejestrować, a następnie ponownie załadować tę stronę.",
|
||||
"Replacing the original requires editing rights on the original document.": "Zastąpienie oryginału wymaga uprawnień do edycji oryginalnego dokumentu.",
|
||||
"Sign up": "Zarejestruj się",
|
||||
"The original version of this document will be updated.": "Oryginalna wersja tego dokumentu zostanie zaktualizowana.",
|
||||
"You do not have write access to this site": "Nie masz dostępu do zapisu na tej stronie",
|
||||
"Original Looks Unrelated": "Oryginalny wygląd niepowiązany",
|
||||
"Be careful, the original has changes not in this document. Those changes will be overwritten.": "Uważaj, oryginał ma zmiany, których nie ma w tym dokumencie. Te zmiany zostaną nadpisane."
|
||||
},
|
||||
"NotifyUI": {
|
||||
"Go to your free personal site": "Przejdź do swojej darmowej strony osobistej",
|
||||
"No notifications": "Brak powiadomień",
|
||||
"Ask for help": "Zapytaj o pomoc",
|
||||
"Cannot find personal site, sorry!": "Nie mogę znaleźć osobistej strony, przepraszam!",
|
||||
"Give feedback": "Przekaż opinię",
|
||||
"Notifications": "Powiadomienia"
|
||||
},
|
||||
"LeftPanelCommon": {
|
||||
"Help Center": "Centrum pomocy"
|
||||
}
|
||||
}
|
||||
|
@ -744,7 +744,11 @@
|
||||
"Cannot drop items into Hidden Fields": "Não é possível lançar itens em Campos Ocultos",
|
||||
"Clear": "Limpar",
|
||||
"Hidden Fields cannot be reordered": "Campos ocultos não podem ser reordenados",
|
||||
"Select All": "Selecionar Todos"
|
||||
"Select All": "Selecionar Todos",
|
||||
"Hidden {{label}}": "{{label}} escondido",
|
||||
"Show {{label}}": "Mostrar {{label}}",
|
||||
"Visible {{label}}": "{{label}} visível",
|
||||
"Hide {{label}}": "Ocultar {{label}}"
|
||||
},
|
||||
"WelcomeQuestions": {
|
||||
"Education": "Educação",
|
||||
@ -803,7 +807,19 @@
|
||||
"menus": {
|
||||
"* Workspaces are available on team plans. ": "* As áreas de trabalho estão disponíveis nos planos de equipe. ",
|
||||
"Select fields": "Selecionar campos",
|
||||
"Upgrade now": "Atualizar agora"
|
||||
"Upgrade now": "Atualizar agora",
|
||||
"Numeric": "Numérico",
|
||||
"Text": "Texto",
|
||||
"Integer": "Inteiro",
|
||||
"Toggle": "Alternar",
|
||||
"Date": "Data",
|
||||
"DateTime": "DataHora",
|
||||
"Choice List": "Lista de opções",
|
||||
"Reference List": "Lista de Referências",
|
||||
"Attachment": "Anexo",
|
||||
"Any": "Qualquer",
|
||||
"Choice": "Opção",
|
||||
"Reference": "Referência"
|
||||
},
|
||||
"modals": {
|
||||
"Cancel": "Cancelar",
|
||||
|
@ -4,7 +4,7 @@
|
||||
"Attribute name": "Имя атрибута",
|
||||
"Add Default Rule": "Добавить правило по умолчанию",
|
||||
"Add Column Rule": "Добавить правило столбца",
|
||||
"View As": "Посмотреть как",
|
||||
"View As": "Смотреть как",
|
||||
"Seed rules": "Наследуемые правила",
|
||||
"Add User Attributes": "Добавить атрибуты пользователя",
|
||||
"Add Table Rules": "Добавить правила таблицы",
|
||||
@ -798,7 +798,11 @@
|
||||
"Clear": "Очистить",
|
||||
"Hidden Fields cannot be reordered": "Скрытые поля не могут быть переупорядочены",
|
||||
"Cannot drop items into Hidden Fields": "Невозможно поместить элементы в скрытые поля",
|
||||
"Select All": "Выбрать все"
|
||||
"Select All": "Выбрать все",
|
||||
"Hide {{label}}": "Скрыть {{label}}",
|
||||
"Hidden {{label}}": "Скрытый {{label}}",
|
||||
"Show {{label}}": "Показать {{label}}",
|
||||
"Visible {{label}}": "Видимый {{label}}"
|
||||
},
|
||||
"WelcomeQuestions": {
|
||||
"Marketing": "Маркетинг",
|
||||
@ -826,7 +830,19 @@
|
||||
"menus": {
|
||||
"Select fields": "Выберите поля",
|
||||
"Upgrade now": "Обновитесь сейчас",
|
||||
"* Workspaces are available on team plans. ": "* Рабочие пространства доступны в командных тарифах. "
|
||||
"* Workspaces are available on team plans. ": "* Рабочие пространства доступны в командных тарифах. ",
|
||||
"Any": "Любые",
|
||||
"Numeric": "Численный",
|
||||
"Text": "Текст",
|
||||
"Toggle": "Переключатель",
|
||||
"Date": "Дата",
|
||||
"Choice": "Выбор",
|
||||
"Reference List": "Ссылки списком",
|
||||
"Choice List": "Выбор списком",
|
||||
"Attachment": "Вложения",
|
||||
"DateTime": "Дата и Время",
|
||||
"Integer": "Целочисленный",
|
||||
"Reference": "Ссылка"
|
||||
},
|
||||
"modals": {
|
||||
"Cancel": "Отмена",
|
||||
|
@ -1,4 +1,5 @@
|
||||
--require source-map-support/register
|
||||
test/report-why-tests-hang
|
||||
test/init-mocha-webdriver
|
||||
test/split-tests
|
||||
test/chai-as-promised
|
||||
|
121
test/split-tests.js
Normal file
121
test/split-tests.js
Normal file
@ -0,0 +1,121 @@
|
||||
/**
|
||||
* This module handles splitting tests for parallelizing them. This module is imported by any run
|
||||
* of mocha, due by being listed in test/mocha.opts.
|
||||
*
|
||||
* It only does anything if TEST_SPLITS is set, which must have the form "3-of-8".
|
||||
*
|
||||
* If TEST_SPLITS is set to M-of-N, it is used to divide up all test suites in this mocha run into
|
||||
* N groups, and runs the Mth of them. Note that M is 1-based, i.e. in [1..N] range. To have all
|
||||
* tests run, each of the groups 1-of-N through N-of-N must run on the same total set of tests.
|
||||
*
|
||||
* The actual breaking into groups is informed by a timings file, defaulting to
|
||||
* test/timings-all.txt. This has the format "<top-suite> <file-suite-title> <duration-in-ms>".
|
||||
* Only those lines whose <top-suite> matches process.env.TEST_SUITE_FOR_TIMINGS will be used.
|
||||
*
|
||||
* The timings for test/timings-all.txt are prepared by our test reporter and written during
|
||||
* Jenkins run as the timings/timings-all.txt artifact. After tests are added or changed, if
|
||||
* timings may have changed significantly, it's good to update test/timings-all.txt, so that the
|
||||
* parallel groups can be evened out as much as possible.
|
||||
*/
|
||||
|
||||
/* global before */
|
||||
const fs = require('fs');
|
||||
const { assert } = require('chai');
|
||||
|
||||
const testSuite = process.env.TEST_SUITE_FOR_TIMINGS || "unset_suite";
|
||||
const timingsFile = process.env.TIMINGS_FILE || "test/timings-all.txt";
|
||||
|
||||
before(function() {
|
||||
const testSplits = process.env.TEST_SPLITS;
|
||||
if (!testSplits) {
|
||||
return;
|
||||
}
|
||||
const match = testSplits.match(/^(\d+)-of-(\d+)$/);
|
||||
if (!match) {
|
||||
assert.fail(`Invalid test split spec '${testSplits}': use format 'N-of-M'`);
|
||||
}
|
||||
|
||||
const group = Number(match[1]);
|
||||
const groupCount = Number(match[2]);
|
||||
if (!(group >= 1 && group <= groupCount)) {
|
||||
assert.fail(`Invalid test split spec '${testSplits}': index must be in range 1..{groupCount}`);
|
||||
}
|
||||
|
||||
const testParent = this.test.parent;
|
||||
const timings = getTimings();
|
||||
const groups = groupSuites(testParent.suites, timings, groupCount);
|
||||
|
||||
testParent.suites = groups[group - 1]; // Convert to a 0-based index.
|
||||
console.log(`Split tests groups; will run group ${group} of ${groupCount}`);
|
||||
});
|
||||
|
||||
/**
|
||||
* Read timings from timingsFile into a Map mapping file-suite-title to duration.
|
||||
*/
|
||||
function getTimings() {
|
||||
const timings = new Map();
|
||||
try {
|
||||
const content = fs.readFileSync(timingsFile, {encoding: 'utf8'})
|
||||
for (const line of content.split(/\r?\n/)) {
|
||||
const [bigSuite, fileSuite, duration] = line.split(/\s+/);
|
||||
if (bigSuite === testSuite && !isNaN(Number(duration))) {
|
||||
timings.set(fileSuite, Number(duration));
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.code === 'ENOENT') {
|
||||
console.warn(`No timings found in ${timingsFile}; proceeding without timings`);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return timings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits suites into groups and returns the list of them.
|
||||
*
|
||||
* The algorithm to group tests into suites starts goes one by one from longest to shortest,
|
||||
* adding them to the least filled-up group.
|
||||
*/
|
||||
function groupSuites(suites, timings, groupCount) {
|
||||
// Calculate a fallback value for durations as the average of existing durations.
|
||||
const totalDuration = Array.from(timings.values()).reduce(((s, dur) => s + dur), 0);
|
||||
if (!totalDuration) {
|
||||
console.warn("No timings; assuming all tests are equally long");
|
||||
}
|
||||
const fallbackDuration = totalDuration ? totalDuration / timings.size : 1000;
|
||||
|
||||
const groups = Array.from(Array(groupCount), () => []);
|
||||
const groupDurations = groups.map(() => 0);
|
||||
|
||||
// Check for duplicate suite titles.
|
||||
const suitesByTitle = new Map(suites.map(s => [s.title, s]));
|
||||
for (const suite of suites) {
|
||||
if (suitesByTitle.get(suite.title) !== suite) {
|
||||
assert.fail(`Please fix duplicate suite title: ${suite.title}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Get timing for the given suite, falling back to fallbackDuration.
|
||||
function getTiming(suite) {
|
||||
const value = timings.get(suite.title);
|
||||
return (typeof value !== 'number' || isNaN(value)) ? fallbackDuration : value;
|
||||
}
|
||||
|
||||
// Sort suites by descending duration.
|
||||
const sortedSuites = suites.slice().sort((a, b) => getTiming(b) - getTiming(a));
|
||||
|
||||
for (const suite of sortedSuites) {
|
||||
// Pick a least-duration group.
|
||||
const index = groupDurations.indexOf(Math.min(...groupDurations));
|
||||
groups[index].push(suite);
|
||||
groupDurations[index] += getTiming(suite);
|
||||
}
|
||||
|
||||
// Sort each group alphabetically by title.
|
||||
for (const group of groups) {
|
||||
group.sort((a, b) => a.title < b.title ? -1 : 1);
|
||||
}
|
||||
return groups;
|
||||
}
|
28
test/timings/nbrowser.txt
Normal file
28
test/timings/nbrowser.txt
Normal file
@ -0,0 +1,28 @@
|
||||
nbrowser ActionLog 14737
|
||||
nbrowser ChoiceList 33037
|
||||
nbrowser CustomView 22055
|
||||
nbrowser CustomWidgets 14958
|
||||
nbrowser CustomWidgetsConfig 48287
|
||||
nbrowser DescriptionColumn 4649
|
||||
nbrowser DuplicateDocument 14042
|
||||
nbrowser Fork 112089
|
||||
nbrowser HomeIntro 44706
|
||||
nbrowser LanguageSettings 25427
|
||||
nbrowser Localization 10069
|
||||
nbrowser MultiColumn 455648
|
||||
nbrowser Pages 24986
|
||||
nbrowser ReferenceColumns 27590
|
||||
nbrowser ReferenceList 34333
|
||||
nbrowser RefTransforms 9072
|
||||
nbrowser RightPanel 10530
|
||||
nbrowser RightPanelSelectBy 6255
|
||||
nbrowser RowMenu 3702
|
||||
nbrowser saveViewSection 7596
|
||||
nbrowser SelectBy 5846
|
||||
nbrowser SelectByRefList 15186
|
||||
nbrowser SelectByRightPanel 3531
|
||||
nbrowser SelectBySummary 17516
|
||||
nbrowser SelectBySummaryRef 5382
|
||||
nbrowser SelectionSummary 6833
|
||||
nbrowser Smoke 1800
|
||||
nbrowser ToggleColumns 6530
|
7
test/timings/server.txt
Normal file
7
test/timings/server.txt
Normal file
@ -0,0 +1,7 @@
|
||||
server Comm 9557
|
||||
server generateInitialDocSql 1304
|
||||
server Authorizer 2375
|
||||
server DocApi 94358
|
||||
server DocApi2 730
|
||||
server HostedStorageManager 220307
|
||||
server backupSqliteDatabase 4348
|
Loading…
Reference in New Issue
Block a user