diff --git a/packages/nc-gui/components/cell/MultiSelect.vue b/packages/nc-gui/components/cell/MultiSelect.vue
index 3a3d5f56fe..f9a1bc59e2 100644
--- a/packages/nc-gui/components/cell/MultiSelect.vue
+++ b/packages/nc-gui/components/cell/MultiSelect.vue
@@ -314,9 +314,14 @@ const handleClose = (e: MouseEvent) => {
useEventListener(document, 'click', handleClose, true)
-// todo: maintain order
const selectedOpts = computed(() => {
- return options.value.filter((o) => vModel.value.includes(o.value!))
+ return options.value.reduce<(SelectOptionType & { index: number })[]>((selectedOptions, option) => {
+ const index = vModel.value.indexOf(option.value!)
+ if (index !== -1) {
+ selectedOptions.push({ ...option, index })
+ }
+ return selectedOptions
+ }, [])
})
@@ -324,7 +329,7 @@ const selectedOpts = computed(() => {
-
+
diff --git a/packages/nc-gui/components/tabs/auth/UserManagement.vue b/packages/nc-gui/components/tabs/auth/UserManagement.vue
index 1dd5b4c037..005469c0a7 100644
--- a/packages/nc-gui/components/tabs/auth/UserManagement.vue
+++ b/packages/nc-gui/components/tabs/auth/UserManagement.vue
@@ -369,9 +369,9 @@ const isSuperAdmin = (user: { main_roles?: string }) => {
{
до зовнішньої бази даних",
+ "extDB": "Створити підключення
до зовнішньої бази даних",
"excel": "Створити проєкт з Excel",
"template": "Створити проєкт з шаблону"
},
- "OkSaveProject": "Підтвердити & Зберегти",
+ "OkSaveProject": "Зберегти",
"upgrade": {
"available": "Доступне оновлення",
"releaseNote": "Список змін",
- "howTo": "Як оновитися?"
+ "howTo": "Як оновитись?"
},
- "translate": "Допоможіть з перекладом",
+ "translate": "Допомогти з перекладом",
"account": {
- "authToken": "Копіювати токен авторизації",
+ "authToken": "Скопіювати токен",
"swagger": "Swagger: REST API",
- "projInfo": "Скопіювати інформацію про проект",
+ "projInfo": "Скопіювати інформацію про проєкт",
"themes": "Теми"
},
"sort": "Сортувати",
"addSort": "Додати параметри сортування",
"filter": "Фільтр",
"addFilter": "Додати фільтр",
- "share": "Поділитися",
+ "share": "Поділитись",
"shareBase": {
"disable": "Вимкнути спільну базу",
"enable": "Будь-хто, хто має посилання",
@@ -374,10 +374,10 @@
"inviteToken": "Токен запрошення",
"newUser": "Новий користувач",
"editUser": "Редагувати користувача",
- "deleteUser": "Видалити користувача з проєкту",
- "resendInvite": "Повторно надіслати запрошення на пошту",
- "copyInviteURL": "Скопіювати URL-адресу запрошення",
- "copyPasswordResetURL": "Скопіювати URL-адресу для оновлення паролю",
+ "deleteUser": "Видалити користувача",
+ "resendInvite": "Повторно надіслати запрошення",
+ "copyInviteURL": "Скопіювати URL-посилання для запрошення",
+ "copyPasswordResetURL": "Скопіювати URL-посилання для відновлення паролю",
"newRole": "Нова роль",
"reloadRoles": "Перезавантажити ролі",
"nextPage": "Наступна сторінка",
@@ -390,7 +390,7 @@
"renameTable": "Перейменувати таблицю",
"deleteTable": "Видалити таблицю",
"addField": "Додати нове поле до цієї таблиці",
- "setDisplay": "Встановити як значення для відображення",
+ "setDisplay": "Встановити як значення для показу",
"addRow": "Додати новий рядок",
"saveRow": "Зберегти рядок",
"saveAndExit": "Зберегти та вийти",
@@ -416,20 +416,20 @@
"fillByCodeScan": "Заповнити за допомогою сканування",
"listSharedView": "Список спільних виглядів",
"ListView": "Список виглядів",
- "copyView": "Копіювати вигляд",
+ "copyView": "Скопіювати вигляд",
"renameView": "Перейменувати вигляд",
"deleteView": "Видалити вигляд",
"createGrid": "Створіть вигляд сітки",
"createGallery": "Створити вигляд галереї",
"createCalendar": "Створити вигляд календаря",
- "createKanban": "Створити Kanban вигляд",
+ "createKanban": "Створити табличний вигляд",
"createForm": "Створити вигляд форми",
"showSystemFields": "Показати системні поля",
"copyUrl": "Копіювати URL-адресу",
"openTab": "Відкрийте нову вкладку",
"iFrame": "Копіювати вбудований HTML-код",
- "addWebhook": "Додати новий Webhook",
- "enableWebhook": "Увімкнути вебхук",
+ "addWebhook": "Додати новий вебхук",
+ "enableWebhook": "Ввімкнути вебхук",
"testWebhook": "Перевірити вебхук",
"copyWebhook": "Скопіювати вебхук",
"deleteWebhook": "Видалити вебхук",
@@ -439,8 +439,8 @@
"metaSync": "Синхронізувати",
"settings": "Налаштування",
"previewAs": "Попередній перегляд як",
- "resetReview": "Скинути попередній перегляд",
- "testDbConn": "Тестове з'єднання з базою даних",
+ "resetReview": "Відновити попередній перегляд",
+ "testDbConn": "Тестове зʼєднання з базою даних",
"removeDbFromEnv": "Видалити базу даних з середовища",
"editConnJson": "Редагувати підключення JSON",
"sponsorUs": "Спонсорувати нас",
@@ -460,38 +460,38 @@
"showPkAndFk": "Показати первинні та зовнішні ключі",
"showSqlViews": "Показати SQL вигляд",
"showMMTables": "Показати таблиці \"багато-до-багатьох\"",
- "showJunctionTableNames": "Показати ім'я таблиці для з'єднання"
+ "showJunctionTableNames": "Показати імʼя таблиці для зʼєднання"
},
"kanban": {
"collapseStack": "Згорнути стек",
"deleteStack": "Видалити стек",
"stackedBy": "Групувати по",
"chooseGroupingField": "Виберіть поле групування",
- "addOrEditStack": "Додати / Редагувати стек"
+ "addOrEditStack": "Додати/Редагувати табличку"
},
"map": {
- "mappedBy": "Mapped By",
+ "mappedBy": "Мапувати по",
"chooseMappingField": "Виберіть поле для мапування",
"openInGoogleMaps": "Google Maps",
- "openInOpenStreetMap": "OSM"
+ "openInOpenStreetMap": "Відкрити в Google Maps"
},
- "toggleMobileMode": "Увімкнути мобільний режим"
+ "toggleMobileMode": "Ввімкнути мобільний режим"
},
"tooltip": {
"saveChanges": "Зберегти зміни",
"xcDB": "Створити новий проєкт",
"extDB": "Підтримує MySQL, PostgreSQL, SQL Server та SQLite",
"apiRest": "Доступно через REST API",
- "apiGQL": "Доступно через API GraphQL",
+ "apiGQL": "Доступно через GraphQL API",
"theme": {
"dark": "Він доступний у чорному кольорі (^⇧B)",
"light": "Чи є він у чорному кольорі? (^⇧B)"
},
"addTable": "Додати нову таблицю",
"inviteMore": "Запросіть більше користувачів",
- "toggleNavDraw": "Ввімвкнути висувне меню",
+ "toggleNavDraw": "Ввімкнути висувне меню",
"reloadApiToken": "Перезавантажити API токен",
- "generateNewApiToken": "Створити новий API токен",
+ "generateNewApiToken": "Згенерувати API токен",
"addRole": "Додати нову роль",
"reloadList": "Перезавантажити список",
"metaSync": "Синхронізувати метаданні",
@@ -538,13 +538,13 @@
"info": {
"pasteNotSupported": "Операція вставки не підтримується в активній комірці",
"roles": {
- "orgCreator": "Розробник може створювати нові проєкти та мати доступ до будь-якого відкритого проєкту.",
- "orgViewer": "Глядач не може створювати нові проєкти, але він може отримати доступ до будь-якого відкритого проєкту."
+ "orgCreator": "Розробник може створювати нові проєкти та мати доступ до будь-якого публічного проєкту.",
+ "orgViewer": "Глядач не може створювати нові проєкти, але він може отримати доступ до будь-якого публічного проєкту."
},
"codeScanner": {
"loadingScanner": "Завантаження сканера...",
"selectColumn": "Виберіть стовпець, QR-код або штрих-код, який ви хочете використовувати для пошуку рядка за допомогою сканування.",
- "moreThanOneRowFoundForCode": "Для цього коду знайдено більше одного рядка. Наразі підтримуються лише унікальні коди.",
+ "moreThanOneRowFoundForCode": "Для цього коду знайдено декілька рядків. Наразі підтримуються лише унікальні коди",
"noRowFoundForCode": "Для цього коду не знайдено жодного рядка у вибраному стовпчику"
},
"map": {
@@ -558,19 +558,19 @@
"excelSupport": "Підтримуються: .xls, .xlsx, .xlsm, .ods, .ots",
"excelURL": "Введіть посилання до файлу Excel",
"csvURL": "Введіть посилання до файлу CSV",
- "footMsg": "# рядків, які потрібно проаналізувати, щоб вивести тип даних",
+ "footMsg": "К-сть рядків для аналізу, щоб визначити тип даних",
"excelImport": "аркуш(і) які доступні для імпорту",
"exportMetadata": "Ви хочете експортувати метадані з мета-таблиць?",
"importMetadata": "Ви хочете імпортувати метадані з мета-таблиць?",
"clearMetadata": "Ви хочете очистити метадані з мета-таблиць?",
- "projectEmptyMessage": "Почніть зі створення нового проекту",
+ "projectEmptyMessage": "Почніть зі створення нового проєкту",
"stopProject": "Ви хочете зупинити проєкт?",
"startProject": "Ви хочете розпочати проєкт?",
"restartProject": "Ви хочете перезапустити проєкт?",
"deleteProject": "Ви хочете видалити проєкт?",
"shareBasePrivate": "Створіть загальнодоступну базу, доступну лише для читання",
"shareBasePublic": "Будь-хто в Інтернеті може переглядати за допомогою цього посилання",
- "userInviteNoSMTP": "Схоже, ви ще не налаштували SMTP! Будь ласка, скопіюйте посилання на запрошення та надішліть його на адресу",
+ "userInviteNoSMTP": "Схоже, ви ще не налаштували SMTP! Будь ласка, скопіюйте посилання на запрошення та надішліть його на пошту.",
"dragDropHide": "Перетягніть поля сюди, щоб приховати",
"formInput": "Введіть назву форми для введення",
"formHelpText": "Додайте допоміжний текст",
@@ -578,7 +578,7 @@
"formDesc": "Додати опис форми",
"beforeEnablePwd": "Обмежити доступ за допомогою пароля",
"afterEnablePwd": "Доступ обмежено паролем",
- "privateLink": "Цим переглядом поділилися через приватне посилання",
+ "privateLink": "Цей перегляд доступний за приватним посиланням",
"privateLinkAdditionalInfo": "Люди з приватним посиланням можуть бачити лише клітини, видимі в цьому вигляді",
"afterFormSubmitted": "Після надсилання форми",
"apiOptions": "Доступ до проєкту через",
@@ -593,9 +593,9 @@
"collabView": "Учасники з дозволом на редагування або вище можуть змінювати конфігурацію перегляду.",
"lockedView": "Ніхто не може відредагувати конфігурацію перегляду, доки вона не розблокована.",
"personalView": "Тільки ви можете відредагувати конфігурацію. Іншим учасникам прихована зміна переглядів за замовчуванням.",
- "ownerDesc": "Може додавати/видаляти редакторів. Також може повністю редагувати структури та поля бази даних.",
+ "ownerDesc": "Може додавати або видаляти редакторів. Також може повністю редагувати структури та поля бази даних.",
"creatorDesc": "Може повністю редагувати структуру бази даних та значення.",
- "editorDesc": "Може редагувати записи, але не може змінити структуру бази даних/полів.",
+ "editorDesc": "Може редагувати записи, але не може змінити структуру бази даних або полів.",
"commenterDesc": "Може переглядати та коментувати записи, але нічого не може редагувати",
"viewerDesc": "Може переглядати записи, але нічого не може редагувати",
"addUser": "Додати нового користувача",
@@ -606,14 +606,14 @@
"metaNoChange": "Не виявлено жодних змін",
"sqlMigration": "Схема міграції буде створена автоматично. Створіть таблицю та оновіть цю сторінку.",
"dbConnectionStatus": "Середовище перевірено",
- "dbConnected": "З'єднання успішне",
+ "dbConnected": "Зʼєднання успішне",
"notifications": {
"no_new": "Немає нових повідомлень",
"clear": "Очистити"
},
"sponsor": {
"header": "Ви можете допомогти нам!",
- "message": "Ми - невелика команда, яка працює на повну ставку, щоб зробити NocoDB відкритим. Ми віримо, що такий інструмент, як NocoDB, повинен бути доступним безкоштовно для кожного розв'язувача проблем в Інтернеті."
+ "message": "Ми - невелика команда, яка працює на повну ставку, щоб зробити NocoDB відкритим. Ми віримо, що такий інструмент, як NocoDB, повинен бути доступним безкоштовно для кожного розвʼязувача проблем в Інтернеті."
},
"loginMsg": "Увійти до NocoDB",
"passwordRecovery": {
@@ -623,22 +623,22 @@
},
"signUp": {
"superAdmin": "Ви будете \"Власником\"",
- "alreadyHaveAccount": "Вже є обліковий запис?",
+ "alreadyHaveAccount": "Вже зареєстровані?",
"workEmail": "Введіть робочу адресу електронної пошти",
"enterPassword": "Введіть ваш пароль",
- "forgotPassword": "Забули власний пароль?",
+ "forgotPassword": "Забули пароль?",
"dontHaveAccount": "Не маєте облікового запису?"
},
"addView": {
"grid": "Додати вигляд сітки",
"gallery": "Додати вигляд галереї",
"form": "Додати вигляд форми",
- "kanban": "Додати вигляд Kanban",
+ "kanban": "Додати вигляд таблички",
"map": "Додати вид мапи",
"calendar": "Додати вигляд календаря"
},
"tablesMetadataInSync": "Таблиці метаданих синхронізуються",
- "addMultipleUsers": "Ви можете додати кілька електронних адрес, розділених комами(,)",
+ "addMultipleUsers": "Ви можете додати кілька електронних адрес через кому",
"enterTableName": "Введіть назву таблиці",
"addDefaultColumns": "Додайте стовпці за замовчуванням",
"tableNameInDb": "Назва таблиці, збережена в базі даних",
@@ -648,7 +648,7 @@
"import": {
"clickOrDrag": "Клацніть або перетягніть файл у цю область, щоб завантажити його"
},
- "metaDataRecreated": "Метадані таблиці успішно відтворено",
+ "metaDataRecreated": "Метадані таблиці відтворено",
"invalidCredentials": "Недійсні облікові дані",
"downloadingMoreFiles": "Завантажте інші файли",
"copiedToClipboard": "Скопійовано в буфер обміну",
@@ -658,7 +658,7 @@
"editingPKnotSupported": "Редагування первинного ключа не підтримується",
"deletedCache": "Кеш успішно видалено",
"cacheEmpty": "Кеш порожній",
- "exportedCache": "Кеш успішно експортовано",
+ "exportedCache": "Кеш експортовано",
"valueAlreadyInList": "Це значення вже є у списку",
"noColumnsToUpdate": "Немає стовпців для оновлення",
"tableDeleted": "Таблицю успішно видалено",
@@ -668,26 +668,26 @@
"showM2mTables": "Показати M2M таблиці",
"showM2mTablesDesc": "Звʼязок \"багато-до-багатьох\" підтримується через таблицю зʼєднань і за замовчуванням прихований. Увімкніть цю опцію, щоб перерахувати всі такі таблиці разом з існуючими.",
"showNullInCells": "Показати NULL в комірках",
- "showNullInCellsDesc": "Відображати тег 'NULL' у клітинках, що містять NULL-значення. Це допомагає відрізнити клітинки, що містять ПУСТИЙ рядок.",
+ "showNullInCellsDesc": "Відображати тег \"NULL\" у клітинках, що містять NULL-значення. Це допомагає відрізнити клітинки, що містять пустий рядок.",
"showNullAndEmptyInFilter": "Показувати NULL та EMPTY у фільтрі",
- "showNullAndEmptyInFilterDesc": "Увімкніть \"додаткові\" фільтри для розрізнення полів, що містять NULL та порожні рядки. За замовчуванням підтримка пропусків однаково обробляє як NULL, так і порожні рядки.",
- "deleteKanbanStackConfirmation": "Видалення цього стека також вилучить опцію вибору `{stackToBeDeleted}` зі стека `{groupingField}`. Записи буде переміщено до не категоризованого стека.",
+ "showNullAndEmptyInFilterDesc": "Ввімкніть \"додаткові\" фільтри для розрізнення полів, що містять NULL та порожні рядки. За замовчуванням підтримка пропусків однаково обробляє як NULL, так і порожні рядки.",
+ "deleteKanbanStackConfirmation": "Видалення цієї таблички також вилучить опцію вибору `{stackToBeDeleted}` з таблички `{groupingField}`. Записи буде переміщено до не категоризованої таблички.",
"computedFieldEditWarning": "Обчислюване поле: вміст доступний лише для читання. Використовуйте меню редагування стовпця для зміни конфігурації",
"computedFieldDeleteWarning": "Обчислюване поле: вміст доступний лише для читання. Не вдалося очистити вміст.",
"noMoreRecords": "Більше записів немає"
},
"error": {
"searchProject": "За вашим запитом {search} не знайдено жодного результату",
- "invalidChar": "Недійсний символ у шляху до теки.",
+ "invalidChar": "Недійсний символ у шляху.",
"invalidDbCredentials": "Неправильні облікові дані бази даних.",
- "unableToConnectToDb": "Неможливо під'єднатися до бази даних, будь ласка, перевірте, чи працює ваша база даних.",
+ "unableToConnectToDb": "Неможливо підʼєднатися до бази даних, будь ласка, перевірте, чи працює ваша база даних.",
"userDoesntHaveSufficientPermission": "Користувач не існує або не має достатніх прав для створення конфігурації.",
"dbConnectionStatus": "Неправильні параметри бази даних",
"dbConnectionFailed": "Помилка з’єднання:",
"signUpRules": {
- "emailReqd": "E-mail є обов'язковим полем",
- "emailInvalid": "E-mail має невірний формат",
- "passwdRequired": "Пароль є обов'язковим",
+ "emailReqd": "Пошта є обовʼязковим полем",
+ "emailInvalid": "Пошта має невірний формат",
+ "passwdRequired": "Пароль є обовʼязковим",
"passwdLength": "Пароль має складатися хоча б з 8 символів",
"passwdMismatch": "Паролі не збігаються",
"completeRuleSet": "Щонайменше 8 символів з однією великою літерою, однією цифрою та одним спеціальним символом",
@@ -704,7 +704,7 @@
"fileUploadFailed": "Не вдалося завантажити файл",
"primaryColumnUpdateFailed": "Не вдалося оновити основний стовпець",
"formDescriptionTooLong": "Занадто довгі дані для опису форми",
- "columnsRequired": "Обов'язковими є наступні стовпці",
+ "columnsRequired": "Обовʼязковими є наступні стовпці",
"selectAtleastOneColumn": "Принаймні один стовпець має бути вибраний",
"columnDescriptionNotFound": "Не вдається знайти стовпець призначення для",
"duplicateMappingFound": "Знайдено дублікат схеми, будь ласка, видаліть одну зі схем",
@@ -723,7 +723,7 @@
"setFormDataFailed": "Не вдалося встановити дані форми",
"formViewUpdateFailed": "Не вдалося оновити вигляд форми",
"tableNameRequired": "Ім'я таблиці є обов'язковим",
- "nameShouldStartWithAnAlphabetOr_": "Ім'я повинно починатися з літери або _",
+ "nameShouldStartWithAnAlphabetOr_": "Імʼя повинно починатися з літери або _",
"followingCharactersAreNotAllowed": "Наступні символи не допускаються",
"columnNameRequired": "Ім'я стовпця є обов'язковим",
"columnNameExceedsCharacters": "Довжина назви стовпця перевищує максимальну кількість в {value} символів",
@@ -741,52 +741,52 @@
"copyToClipboardError": "Не вдалося скопіювати в буфер обміну"
},
"toast": {
- "exportMetadata": "Метадані проєкту успішно експортовано",
- "importMetadata": "Метадані проєкту успішно імпортовано",
- "clearMetadata": "Метадані проєкту успішно очищено",
- "stopProject": "Проєкт успішно зупинений",
- "startProject": "Проєкт успішно запущений",
- "restartProject": "Проєкт успішно перезапущений",
- "deleteProject": "Проєкт успішно видалений",
+ "exportMetadata": "Метадані проєкту експортовано",
+ "importMetadata": "Метадані проєкту імпортовано",
+ "clearMetadata": "Метадані проєкту очищено",
+ "stopProject": "Проєкт зупинений",
+ "startProject": "Проєкт запущений",
+ "restartProject": "Проєкт перезапущений",
+ "deleteProject": "Проєкт видалений",
"authToken": "Токен авторизації скопійовано в буфер обміну",
"projInfo": "Інформацію про проєкт скопійовано до буфера обміну",
"inviteUrlCopy": "Скопійовано запрошення URL в буфер обміну",
- "createView": "Вигляд створено успішно",
- "formEmailSMTP": "Будь ласка, активуйте плагін SMTP в Магазині додатків, щоб увімкнути повідомлення електронної пошти",
- "collabView": "Успішно переведено в режим спільної роботи",
- "lockedView": "Успішно перемкнуто на заблокований вигляд",
+ "createView": "Вигляд створено",
+ "formEmailSMTP": "Будь ласка, активуйте плагін SMTP в магазині додатків, щоб ввімкнути повідомлення на електронну пошту",
+ "collabView": "Переведено в режим спільної роботи",
+ "lockedView": "Переведено в заблокований режим",
"futureRelease": "Незабаром!"
},
"success": {
"columnDuplicated": "Стовпець успішно продубльовано",
- "rowDuplicatedWithoutSavedYet": "Рядок продубльовано (не збережено)",
+ "rowDuplicatedWithoutSavedYet": "Рядок продубльовано, але не збережено",
"updatedUIACL": "Успішно оновлено UI ACL для таблиць",
"pluginUninstalled": "Плагін успішно видалено",
- "pluginSettingsSaved": "Налаштування плагіну успішно збережено",
+ "pluginSettingsSaved": "Налаштування плагіну збережено",
"pluginTested": "Успішно протестовані налаштування плагіну",
"tableRenamed": "Таблицю успішно перейменовано",
- "viewDeleted": "Вигляд успішно видалено",
+ "viewDeleted": "Вигляд видалено",
"primaryColumnUpdated": "Успішно оновлено як основний стовпець",
"tableDataExported": "Успішно експортовано всі дані таблиці",
"updated": "Успішно оновлено",
- "sharedViewDeleted": "Успішно видалено спільний перегляд",
+ "sharedViewDeleted": "Спільний перегляд видалено",
"userDeleted": "Користувача успішно видалено",
- "viewRenamed": "Вигляд успішно перейменовано",
+ "viewRenamed": "Вигляд перейменовано",
"tokenGenerated": "Токен успішно згенеровано",
"tokenDeleted": "Токен успішно видалено",
- "userAddedToProject": "Користувача успішно додано до проєкту",
- "userAdded": "Користувача успішно додано",
- "userDeletedFromProject": "Користувача успішно видалено з проєкту",
- "inviteEmailSent": "Лист запрошення успішно відправлено на електронну пошту",
- "inviteURLCopied": "URL запрошення скопійоване в буфер обміну",
- "commentCopied": "Коментар скопійовано до буфера обміну",
+ "userAddedToProject": "Користувача додано до проєкту",
+ "userAdded": "Користувача додано",
+ "userDeletedFromProject": "Користувача видалено з проєкту",
+ "inviteEmailSent": "Лист запрошення відправлено на електронну пошту",
+ "inviteURLCopied": "URL-посилання для запрошення скопійовано",
+ "commentCopied": "Коментар скопійовано в буфер обміну",
"passwordResetURLCopied": "URL-адресу скидання пароля скопійовано в буфер обміну",
- "shareableURLCopied": "URL адресу спільної бази скопійовано в буфер обміну!",
+ "shareableURLCopied": "URL-посилання спільної бази скопійовано!",
"embeddableHTMLCodeCopied": "Скопійовано вбудований HTML-код!",
- "userDetailsUpdated": "Дані користувача успішно оновлено",
- "tableDataImported": "Дані таблиці успішно імпортовано",
- "webhookUpdated": "Дані Webhook успішно оновлено",
- "webhookDeleted": "Hook успішно видалено",
+ "userDetailsUpdated": "Дані користувача оновлено",
+ "tableDataImported": "Дані таблиці імпортовано",
+ "webhookUpdated": "Дані вебхуку оновлено",
+ "webhookDeleted": "Вебхук видалено",
"webhookTested": "Webhook успішно протестовано",
"columnUpdated": "Стовпець оновлено",
"columnCreated": "Стовпець створено",
diff --git a/packages/nc-gui/lang/zh-Hans.json b/packages/nc-gui/lang/zh-Hans.json
index 93c45580b2..c8aec7fc76 100644
--- a/packages/nc-gui/lang/zh-Hans.json
+++ b/packages/nc-gui/lang/zh-Hans.json
@@ -238,7 +238,7 @@
"action": "操作",
"actions": "操作",
"operation": "操作",
- "operationSub": "Sub Operation",
+ "operationSub": "子操作",
"operationType": "操作类型",
"operationSubType": "子操作类型",
"description": "描述",
@@ -471,11 +471,11 @@
},
"map": {
"mappedBy": "Mapped By",
- "chooseMappingField": "Choose a Mapping Field",
+ "chooseMappingField": "选择映射字段",
"openInGoogleMaps": "谷歌地图",
"openInOpenStreetMap": "OSM"
},
- "toggleMobileMode": "Toggle Mobile Mode"
+ "toggleMobileMode": "切换移动模式"
},
"tooltip": {
"saveChanges": "保存更改",
@@ -779,7 +779,7 @@
"userDeletedFromProject": "踢出用户成功",
"inviteEmailSent": "邀请邮件发送成功",
"inviteURLCopied": "邀请URL已复制到剪贴板",
- "commentCopied": "Comment copied to clipboard",
+ "commentCopied": "已复制评论到剪贴板",
"passwordResetURLCopied": "密码重置网址已复制到剪贴板",
"shareableURLCopied": "已将可共享的基础URL复制到剪贴板!",
"embeddableHTMLCodeCopied": "已复制可嵌入的 HTML 代码!",
diff --git a/packages/noco-docs/content/en/developer-resources/webhooks.md b/packages/noco-docs/content/en/developer-resources/webhooks.md
index eba7f7e86c..39ebb726b6 100644
--- a/packages/noco-docs/content/en/developer-resources/webhooks.md
+++ b/packages/noco-docs/content/en/developer-resources/webhooks.md
@@ -28,7 +28,8 @@ Some types of notifications can be triggered by a webhook after a particular eve
- Webhook Conditional Trigger
- Only records meeting the criteria will trigger webhook
-![Screenshot 2022-09-14 at 10 35 39 AM](https://user-images.githubusercontent.com/86527202/190064668-37245025-81f6-491c-b639-83c8fd131bc3.png)
+
+![Screenshot 2023-04-06 at 11 39 49 AM](https://user-images.githubusercontent.com/86527202/230288581-c613e591-1c32-4151-a2d1-df2bbf1367fd.png)
@@ -222,4 +223,4 @@ Webhook v2 is available after v0.106.0. Here's the differences.
- Support the following bulk operations:
- AFTER BULK INSERT
- AFTER BULK UPDATE
- - AFTER BULK DELETE
\ No newline at end of file
+ - AFTER BULK DELETE
diff --git a/packages/nocodb/Dockerfile.local b/packages/nocodb/Dockerfile.local
new file mode 100644
index 0000000000..bb3e9a5fcd
--- /dev/null
+++ b/packages/nocodb/Dockerfile.local
@@ -0,0 +1,55 @@
+###########
+# Builder
+###########
+FROM node:16.17.0-alpine3.15 as builder
+WORKDIR /usr/src/app
+
+# install node-gyp dependencies
+RUN apk add --no-cache python3 make g++
+
+# Copy application dependency manifests to the container image.
+# A wildcard is used to ensure both package.json AND package-lock.json are copied.
+# Copying this separately prevents re-running npm ci on every code change.
+COPY ./package*.json ./
+COPY ./docker/nc-gui/ ./docker/nc-gui/
+COPY ./docker/main.js ./docker/index.js
+COPY ./docker/start-local.sh /usr/src/appEntry/start.sh
+COPY ./src/lib/public/css/*.css ./docker/public/css/
+COPY ./src/lib/public/js/*.js ./docker/public/js/
+COPY ./src/lib/public/favicon.ico ./docker/public/
+
+# install production dependencies,
+# reduce node_module size with modclean & removing sqlite deps,
+# package built code into app.tar.gz & add execute permission to start.sh
+RUN npm ci --omit=dev --quiet \
+ && npx modclean --patterns="default:*" --ignore="nc-lib-gui/**,dayjs/**,express-status-monitor/**,@azure/msal-node/dist/**" --run \
+ && rm -rf ./node_modules/sqlite3/deps \
+ && tar -czf ../appEntry/app.tar.gz ./* \
+ && chmod +x /usr/src/appEntry/start.sh
+
+##########
+# Runner
+##########
+FROM alpine:3.15
+WORKDIR /usr/src/app
+
+ENV NC_DOCKER 0.6
+ENV NODE_ENV production
+ENV PORT 8080
+ENV NC_TOOL_DIR=/usr/app/data/
+
+RUN apk --update --no-cache add \
+ nodejs \
+ tar \
+ dumb-init \
+ curl \
+ jq
+
+# Copy packaged production code & main entry file
+COPY --from=builder /usr/src/appEntry/ /usr/src/appEntry/
+
+EXPOSE 8080
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+# Start Nocodb
+CMD ["/usr/src/appEntry/start.sh"]
diff --git a/packages/nocodb/docker/start-local.sh b/packages/nocodb/docker/start-local.sh
new file mode 100644
index 0000000000..619e2f58fd
--- /dev/null
+++ b/packages/nocodb/docker/start-local.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+FILE="/usr/src/app/package.json"
+
+if [ ! -z "${NC_TOOL_DIR}" ]; then
+ mkdir -p $NC_TOOL_DIR
+fi
+
+if [ ! -f "$FILE" ]
+then
+ tar -xzf /usr/src/appEntry/app.tar.gz -C /usr/src/app/
+fi
+
+node docker/index.js
diff --git a/packages/nocodb/src/lib/db/sql-client/lib/pg/PgClient.ts b/packages/nocodb/src/lib/db/sql-client/lib/pg/PgClient.ts
index aa26cbe8d8..19de9865a5 100644
--- a/packages/nocodb/src/lib/db/sql-client/lib/pg/PgClient.ts
+++ b/packages/nocodb/src/lib/db/sql-client/lib/pg/PgClient.ts
@@ -474,17 +474,22 @@ class PGClient extends KnexClient {
]);
}
- // if (this.connectionConfig.searchPath && this.connectionConfig.searchPath[0]) {
- await this.sqlClient.raw(
- ` CREATE SCHEMA IF NOT EXISTS ?? AUTHORIZATION ?? `,
- [
- (this.connectionConfig.searchPath &&
- this.connectionConfig.searchPath[0]) ||
- 'public',
- this.connectionConfig.connection.user,
- ]
- );
- // }
+ const schemaName = this.connectionConfig.searchPath?.[0] || 'public';
+
+ // Check schemaExists because `CREATE SCHEMA IF NOT EXISTS` requires permissions of `CREATE ON DATABASE`
+ const schemaExists = !!(
+ await this.sqlClient.raw(
+ `SELECT schema_name FROM information_schema.schemata WHERE schema_name = ?`,
+ [schemaName]
+ )
+ ).rows?.[0];
+
+ if (!schemaExists) {
+ await this.sqlClient.raw(
+ `CREATE SCHEMA IF NOT EXISTS ?? AUTHORIZATION ?? `,
+ [schemaName, this.connectionConfig.connection.user]
+ );
+ }
// this.sqlClient = knex(this.connectionConfig);
} catch (e) {
diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2.ts
index 1aa1dd12c4..f6a93ea247 100644
--- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2.ts
+++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2.ts
@@ -656,7 +656,7 @@ async function _formulaQueryBuilder(
} else if (pt.type === 'Identifier') {
const { builder } = await aliasToColumn?.[pt.name]?.();
if (typeof builder === 'function') {
- return { builder: knex.raw(`??${colAlias}`, await builder(pt.fnName)) };
+ return { builder: knex.raw(`??${colAlias}`, builder(pt.fnName)) };
}
return { builder: knex.raw(`??${colAlias}`, [builder || pt.name]) };
} else if (pt.type === 'BinaryExpression') {
diff --git a/packages/nocodb/src/run/local.ts b/packages/nocodb/src/run/local.ts
new file mode 100644
index 0000000000..f06c6845b8
--- /dev/null
+++ b/packages/nocodb/src/run/local.ts
@@ -0,0 +1,18 @@
+import path from 'path';
+import cors from 'cors';
+import express from 'express';
+
+import Noco from '../lib/Noco';
+
+const server = express();
+server.enable('trust proxy');
+server.use(cors());
+server.use('/dashboard', express.static(path.join(__dirname, 'nc-gui')));
+server.set('view engine', 'ejs');
+
+(async () => {
+ const httpServer = server.listen(process.env.PORT || 8080, () => {
+ console.log(`App started successfully.\nVisit -> ${Noco.dashboardUrl}`);
+ });
+ server.use(await Noco.init({}, httpServer, server));
+})().catch((e) => console.log(e));
diff --git a/packages/nocodb/webpack.local.config.js b/packages/nocodb/webpack.local.config.js
new file mode 100644
index 0000000000..39677bd35d
--- /dev/null
+++ b/packages/nocodb/webpack.local.config.js
@@ -0,0 +1,53 @@
+const nodeExternals = require('webpack-node-externals');
+const webpack = require('webpack');
+const TerserPlugin = require('terser-webpack-plugin');
+
+const path = require('path');
+module.exports = {
+ entry: './src/run/local.ts',
+ // devtool: 'inline-source-map',
+ module: {
+ rules: [
+ {
+ test: /\.tsx?$/,
+ exclude: /node_modules/,
+ use: {
+ loader: 'ts-loader',
+ options: {
+ transpileOnly: true
+ }
+ },
+ },
+ ],
+ },
+
+ optimization: {
+ minimize: true, //Update this to true or false
+ minimizer: [new TerserPlugin()],
+ nodeEnv: false
+ },
+ externals: [nodeExternals({
+ allowlist: ['nocodb-sdk']
+ })],
+ resolve: {
+ extensions: ['.tsx', '.ts', '.js', '.json'],
+ },
+ output: {
+ filename: 'main.js',
+ path: path.resolve(__dirname, 'docker'),
+ library: 'libs',
+ libraryTarget: 'umd',
+ globalObject: "typeof self !== 'undefined' ? self : this"
+ },
+ node: {
+ fs: 'empty',
+ __dirname: false,
+ },
+ plugins: [
+ new webpack.EnvironmentPlugin([
+ 'EE'
+ ]),
+ ],
+
+ target: 'node',
+};