diff --git a/packages/nc-gui/components/dashboard/settings/AuditTab.vue b/packages/nc-gui/components/dashboard/settings/AuditTab.vue index 389b5e02f6..b5a4edef5a 100644 --- a/packages/nc-gui/components/dashboard/settings/AuditTab.vue +++ b/packages/nc-gui/components/dashboard/settings/AuditTab.vue @@ -1,7 +1,7 @@ diff --git a/packages/nc-gui/composables/useGlobal/state.ts b/packages/nc-gui/composables/useGlobal/state.ts index 2b1f7bc036..df6e886e85 100644 --- a/packages/nc-gui/composables/useGlobal/state.ts +++ b/packages/nc-gui/composables/useGlobal/state.ts @@ -94,6 +94,7 @@ export function useGlobalState(storageKey = 'nocodb-gui-v2'): State { oneClick: false, projectHasAdmin: false, teleEnabled: true, + auditEnabled: true, type: 'nocodb', version: '0.0.0', ncAttachmentFieldSize: 20, diff --git a/packages/nc-gui/composables/useGlobal/types.ts b/packages/nc-gui/composables/useGlobal/types.ts index 9ef6ab3ddb..584b2ca9ec 100644 --- a/packages/nc-gui/composables/useGlobal/types.ts +++ b/packages/nc-gui/composables/useGlobal/types.ts @@ -16,6 +16,7 @@ export interface AppInfo { oneClick: boolean projectHasAdmin: boolean teleEnabled: boolean + auditEnabled: boolean type: string version: string ee?: boolean diff --git a/packages/nc-gui/lang/ar.json b/packages/nc-gui/lang/ar.json index e696c04abd..bfa90afd4c 100644 --- a/packages/nc-gui/lang/ar.json +++ b/packages/nc-gui/lang/ar.json @@ -380,6 +380,7 @@ "renameTable": "إعادة تسمية الجدول", "deleteTable": "حذف الجدول", "addField": "إضافة حقل جديد إلى هذا الجدول", + "setDisplay": "Set as Display value", "addRow": "إضافة صف جديد", "saveRow": "حفظ الصف", "saveAndExit": "Save & Exit", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "هل أنت متأكد من أنك تريد حذف هذا العرض؟", "deleteTableConfirmation": "هل تريد حذف الجدول", "showM2mTables": "إظهار جداول M2M", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.", "computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure", "computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.", diff --git a/packages/nc-gui/lang/bn_IN.json b/packages/nc-gui/lang/bn_IN.json index 64f499703f..e4cabed1bd 100644 --- a/packages/nc-gui/lang/bn_IN.json +++ b/packages/nc-gui/lang/bn_IN.json @@ -380,6 +380,7 @@ "renameTable": "টেবিল নাম পরিবর্তন", "deleteTable": "टेबल मिटाये", "addField": "এই টেবিলে নতুন ক্ষেত্র যুক্ত করুন", + "setDisplay": "Set as Display value", "addRow": "নতুন সারি যুক্ত করুন", "saveRow": "সারি সংরক্ষণ করুন", "saveAndExit": "Save & Exit", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Are you sure you want to delete this view?", "deleteTableConfirmation": "Do you want to delete the table", "showM2mTables": "Show M2M Tables", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.", "computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure", "computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.", diff --git a/packages/nc-gui/lang/cs.json b/packages/nc-gui/lang/cs.json index a1b1bf8b78..1d2e0f228e 100644 --- a/packages/nc-gui/lang/cs.json +++ b/packages/nc-gui/lang/cs.json @@ -380,6 +380,7 @@ "renameTable": "Přejmenování tabulky", "deleteTable": "Tabulka Odstranit", "addField": "Přidání nového pole do této tabulky", + "setDisplay": "Set as Display value", "addRow": "Přidat nový řádek", "saveRow": "Uložit řádek", "saveAndExit": "Uložit a odejít", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Opravdu chcete toto zobrazení odstranit?", "deleteTableConfirmation": "Chcete odstranit tabulku", "showM2mTables": "Zobrazit tabulky M2M", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Odstraněním tohoto zásobníku se také odstraní možnost výběru `{stackToBeDeleted}` z `{groupingField}`. Záznamy se přesunou do zásobníku nezařazených záznamů.", "computedFieldEditWarning": "Vypočtené pole: obsah je určen pouze pro čtení. Ke změně konfigurace sloupce použijte nabídku úprav sloupce", "computedFieldDeleteWarning": "Vypočtené pole: obsah je určen pouze pro čtení. Nelze vymazat obsah.", diff --git a/packages/nc-gui/lang/da.json b/packages/nc-gui/lang/da.json index a3bfd15136..7c499612ed 100644 --- a/packages/nc-gui/lang/da.json +++ b/packages/nc-gui/lang/da.json @@ -380,6 +380,7 @@ "renameTable": "Bord omdøb", "deleteTable": "TABEL DELETE.", "addField": "Tilføj nyt felt til denne tabel", + "setDisplay": "Set as Display value", "addRow": "Tilføj ny række", "saveRow": "Gem ro", "saveAndExit": "Gem og afslutning", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Er du sikker på, at du vil slette denne visning?", "deleteTableConfirmation": "Ønsker du at slette tabellen", "showM2mTables": "Vis M2M-tabeller", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Hvis du sletter denne stak, fjernes også valgmuligheden `{stackToBeDeleted}` fra `{groupingField}`. Posterne vil blive flyttet til stakken \"uncategorized\".", "computedFieldEditWarning": "Beregnet felt: indholdet er skrivebeskyttet. Brug kolonne-redigeringsmenuen til at omkonfigurere", "computedFieldDeleteWarning": "Beregnet felt: indholdet er skrivebeskyttet. Det er ikke muligt at slette indholdet.", diff --git a/packages/nc-gui/lang/de.json b/packages/nc-gui/lang/de.json index 5824629bbd..0e37ab87b5 100644 --- a/packages/nc-gui/lang/de.json +++ b/packages/nc-gui/lang/de.json @@ -380,6 +380,7 @@ "renameTable": "Tabelle umbenennen", "deleteTable": "Tabelle löschen", "addField": "Neues Feld zu dieser Tabelle hinzufügen", + "setDisplay": "Set as Display value", "addRow": "Neue Zeile hinzufügen", "saveRow": "Zeile speichern", "saveAndExit": "Speichern & Verlassen", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Sind Sie sicher, dass Sie diese Ansicht löschen möchten?", "deleteTableConfirmation": "Möchten Sie die Tabelle löschen", "showM2mTables": "M2M Tabellen anzeigen", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Wenn Sie diesen Stapel löschen, wird auch die Auswahloption \"{stackToBeDeleted}\" von der Seite \"{groupingField}\" entfernt. Die Datensätze werden in den nicht kategorisierten Stapel verschoben.", "computedFieldEditWarning": "Berechnetes Feld: Der Inhalt ist schreibgeschützt. Verwenden Sie das Menü \"Spalten bearbeiten\", um das Feld neu zu konfigurieren.", "computedFieldDeleteWarning": "Berechnetes Feld: Inhalt ist schreibgeschützt. Inhalt kann nicht gelöscht werden.", diff --git a/packages/nc-gui/lang/es.json b/packages/nc-gui/lang/es.json index 754016be56..85b274ee59 100644 --- a/packages/nc-gui/lang/es.json +++ b/packages/nc-gui/lang/es.json @@ -380,6 +380,7 @@ "renameTable": "Cambiar el nombre de la tabla", "deleteTable": "Borrar tabla", "addField": "Añadir nuevo campo a esta tabla", + "setDisplay": "Set as Display value", "addRow": "Añadir nueva fila", "saveRow": "Grabar la fila", "saveAndExit": "Guardar y salir", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "¿Está seguro de que desea eliminar esta vista?", "deleteTableConfirmation": "¿Desea eliminar la tabla", "showM2mTables": "Mostrar tablas M2M", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Al eliminar esta pila también se eliminará la opción de selección `{stackToBeDeleted}` de la `{groupingField}`. Los registros pasarán a la pila de no categorizados.", "computedFieldEditWarning": "Campo calculado: el contenido es de sólo lectura. Utilice el menú de edición de columnas para reconfigurar", "computedFieldDeleteWarning": "Campo calculado: el contenido es de sólo lectura. No se puede borrar el contenido.", diff --git a/packages/nc-gui/lang/eu.json b/packages/nc-gui/lang/eu.json index bc70e36e2d..1527721ea3 100644 --- a/packages/nc-gui/lang/eu.json +++ b/packages/nc-gui/lang/eu.json @@ -380,6 +380,7 @@ "renameTable": "Table Rename", "deleteTable": "Table Delete", "addField": "Add new field to this table", + "setDisplay": "Set as Display value", "addRow": "Add new row", "saveRow": "Save row", "saveAndExit": "Save & Exit", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Are you sure you want to delete this view?", "deleteTableConfirmation": "Do you want to delete the table", "showM2mTables": "Show M2M Tables", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.", "computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure", "computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.", diff --git a/packages/nc-gui/lang/fa.json b/packages/nc-gui/lang/fa.json index 04edb17a07..475643336f 100644 --- a/packages/nc-gui/lang/fa.json +++ b/packages/nc-gui/lang/fa.json @@ -380,6 +380,7 @@ "renameTable": "تغییر نام جدول", "deleteTable": "حذف جدول", "addField": "اضافه کردن فیلد جدید به این جدول", + "setDisplay": "Set as Display value", "addRow": "اضافه کردن ردیف جدید", "saveRow": "دخیره ردیف", "saveAndExit": "Save & Exit", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Are you sure you want to delete this view?", "deleteTableConfirmation": "Do you want to delete the table", "showM2mTables": "Show M2M Tables", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.", "computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure", "computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.", diff --git a/packages/nc-gui/lang/fi.json b/packages/nc-gui/lang/fi.json index 13db0b3a1a..e1e4dbc96d 100644 --- a/packages/nc-gui/lang/fi.json +++ b/packages/nc-gui/lang/fi.json @@ -380,6 +380,7 @@ "renameTable": "Taulukko uudelleen", "deleteTable": "Taulukko poistaa", "addField": "Lisää uusi kenttä tähän taulukkoon", + "setDisplay": "Set as Display value", "addRow": "Lisää uusi rivi", "saveRow": "Tallenna rivi", "saveAndExit": "Tallenna & poistu", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Haluatko varmasti poistaa tämän näkymän?", "deleteTableConfirmation": "Haluatko poistaa taulukon", "showM2mTables": "Näytä M2M-taulukot", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Tämän pinon poistaminen poistaa myös valintavaihtoehdon `{stackToBeDeleted}` valikosta `{groupingField}`. Tietueet siirtyvät luokittelemattomaan pinoon.", "computedFieldEditWarning": "Laskettu kenttä: sisältö on vain luettavissa. Käytä sarakkeen muokkausvalikkoa uudelleenmäärittämiseen", "computedFieldDeleteWarning": "Laskettu kenttä: sisältö on vain luettavissa. Sisältöä ei voi tyhjentää.", diff --git a/packages/nc-gui/lang/fr.json b/packages/nc-gui/lang/fr.json index 9b4607bc6e..b622e88f73 100644 --- a/packages/nc-gui/lang/fr.json +++ b/packages/nc-gui/lang/fr.json @@ -380,6 +380,7 @@ "renameTable": "Renommer le tableau", "deleteTable": "Supprimer le tableau", "addField": "Ajouter un nouveau champ à ce tableau", + "setDisplay": "Set as Display value", "addRow": "Ajouter une nouvelle ligne", "saveRow": "Enregistrer la ligne", "saveAndExit": "Enregistrer et quitter", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Êtes-vous sûr de vouloir effacer cette vue ?", "deleteTableConfirmation": "Voulez-vous supprimer ce tableau", "showM2mTables": "Afficher les tables plusieurs à plusieurs", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "La suppression de cette pile entraînera également la suppression de l'option de sélection `{stackToBeDeleted}` de la pile `{groupingField}`. Les enregistrements seront déplacés vers la pile non catégorisée.", "computedFieldEditWarning": "Champ calculé : le contenu est en lecture seule. Utilisez le menu d'édition des colonnes pour reconfigurer", "computedFieldDeleteWarning": "Champ calculé : le contenu est en lecture seule. Impossible d'effacer le contenu.", diff --git a/packages/nc-gui/lang/he.json b/packages/nc-gui/lang/he.json index 0796b06903..612d3d7b90 100644 --- a/packages/nc-gui/lang/he.json +++ b/packages/nc-gui/lang/he.json @@ -380,6 +380,7 @@ "renameTable": "שולחן שינוי שם", "deleteTable": "טבלה מחיקה", "addField": "הוסף שדה חדש לטבלה זו", + "setDisplay": "Set as Display value", "addRow": "הוסף שורה חדשה", "saveRow": "שמור שורה", "saveAndExit": "Save & Exit", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Are you sure you want to delete this view?", "deleteTableConfirmation": "Do you want to delete the table", "showM2mTables": "Show M2M Tables", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.", "computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure", "computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.", diff --git a/packages/nc-gui/lang/hi.json b/packages/nc-gui/lang/hi.json index 76e74135c3..66c393a922 100644 --- a/packages/nc-gui/lang/hi.json +++ b/packages/nc-gui/lang/hi.json @@ -380,6 +380,7 @@ "renameTable": "तालिका का नाम", "deleteTable": "टेबल मिटाये", "addField": "इस तालिका में नया फ़ील्ड जोड़ें", + "setDisplay": "Set as Display value", "addRow": "नई पंक्ति जोड़ें", "saveRow": "पंक्ति सहेजें", "saveAndExit": "Save & Exit", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Are you sure you want to delete this view?", "deleteTableConfirmation": "Do you want to delete the table", "showM2mTables": "Show M2M Tables", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.", "computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure", "computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.", diff --git a/packages/nc-gui/lang/hr.json b/packages/nc-gui/lang/hr.json index 450d411657..953fa0869b 100644 --- a/packages/nc-gui/lang/hr.json +++ b/packages/nc-gui/lang/hr.json @@ -380,6 +380,7 @@ "renameTable": "Preimenovati stolom", "deleteTable": "Obriši tablicu", "addField": "Dodajte novo polje na ovu tablicu", + "setDisplay": "Set as Display value", "addRow": "Dodaj novi red", "saveRow": "Spremanje retka", "saveAndExit": "Save & Exit", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Are you sure you want to delete this view?", "deleteTableConfirmation": "Do you want to delete the table", "showM2mTables": "Show M2M Tables", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.", "computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure", "computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.", diff --git a/packages/nc-gui/lang/id.json b/packages/nc-gui/lang/id.json index 8c2d9141c6..dda93cd5c0 100644 --- a/packages/nc-gui/lang/id.json +++ b/packages/nc-gui/lang/id.json @@ -380,6 +380,7 @@ "renameTable": "Ganti nama meja", "deleteTable": "Table Delete.", "addField": "Tambahkan bidang baru ke tabel ini", + "setDisplay": "Set as Display value", "addRow": "Tambahkan baris baru", "saveRow": "Hemat Baris", "saveAndExit": "Simpan & Keluar", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Apakah Anda yakin ingin menghapus tampilan ini?", "deleteTableConfirmation": "Apakah Anda ingin menghapus tabel", "showM2mTables": "Tampilkan Tabel M2M", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Menghapus tumpukan ini juga akan menghapus opsi pilihan `{stackToBeDeleted}` dari `{groupingField}`. Catatan akan berpindah ke tumpukan yang tidak dikategorikan.", "computedFieldEditWarning": "Bidang yang dihitung: isinya hanya dapat dibaca. Gunakan menu edit kolom untuk mengkonfigurasi ulang", "computedFieldDeleteWarning": "Bidang yang dihitung: isinya hanya dapat dibaca. Tidak dapat menghapus konten.", diff --git a/packages/nc-gui/lang/it.json b/packages/nc-gui/lang/it.json index d158168071..07423e524e 100644 --- a/packages/nc-gui/lang/it.json +++ b/packages/nc-gui/lang/it.json @@ -380,6 +380,7 @@ "renameTable": "Rinomina tabella", "deleteTable": "Elimina tabella", "addField": "Aggiungi un nuovo campo a questa tabella", + "setDisplay": "Set as Display value", "addRow": "Aggiungi nuova riga", "saveRow": "Salva riga", "saveAndExit": "Salvare e uscire", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "È sicuro di voler eliminare questa vista?", "deleteTableConfirmation": "Vuole eliminare la tabella", "showM2mTables": "Mostra tabelle M2M", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "L'eliminazione di questa pila rimuoverà anche l'opzione di selezione `{stackToBeDeleted}` da `{groupingField}`. I record si sposteranno nella pila non categorizzata.", "computedFieldEditWarning": "Campo calcolato: il contenuto è di sola lettura. Utilizzi il menu di modifica della colonna per riconfigurare", "computedFieldDeleteWarning": "Campo calcolato: il contenuto è di sola lettura. Impossibile cancellare il contenuto.", diff --git a/packages/nc-gui/lang/ja.json b/packages/nc-gui/lang/ja.json index f2cdde17ac..7cde87decc 100644 --- a/packages/nc-gui/lang/ja.json +++ b/packages/nc-gui/lang/ja.json @@ -380,6 +380,7 @@ "renameTable": "テーブル名の変更", "deleteTable": "テーブルを削除", "addField": "新しいフィールドを追加", + "setDisplay": "Set as Display value", "addRow": "行を追加", "saveRow": "行を保存", "saveAndExit": "保存して終了", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "このビューを本当に削除しますか?", "deleteTableConfirmation": "テーブルを削除しますか?", "showM2mTables": "M2Mテーブルを表示する", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "スタックを削除すると、`{stackToBeDeleted}`から選択肢`{groupingField}`も削除されます。レコードは未分類スタックに移動します。", "computedFieldEditWarning": "計算フィールド: コンテンツは読み取り専用です。列編集メニューを使用して再設定してください。", "computedFieldDeleteWarning": "計算フィールド: コンテンツは読み取り専用です。コンテンツを消去できません。", diff --git a/packages/nc-gui/lang/ko.json b/packages/nc-gui/lang/ko.json index 39b91f6f37..999a8ed615 100644 --- a/packages/nc-gui/lang/ko.json +++ b/packages/nc-gui/lang/ko.json @@ -380,6 +380,7 @@ "renameTable": "테이블 이름 바꾸기", "deleteTable": "테이블 삭제", "addField": "테이블에 새 필드 추가", + "setDisplay": "Set as Display value", "addRow": "행 추가", "saveRow": "행 저장", "saveAndExit": "Save & Exit", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Are you sure you want to delete this view?", "deleteTableConfirmation": "Do you want to delete the table", "showM2mTables": "Show M2M Tables", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.", "computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure", "computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.", diff --git a/packages/nc-gui/lang/lv.json b/packages/nc-gui/lang/lv.json index 70b9722285..8e0da88a4f 100644 --- a/packages/nc-gui/lang/lv.json +++ b/packages/nc-gui/lang/lv.json @@ -380,6 +380,7 @@ "renameTable": "Tabulas pārdēvēšana", "deleteTable": "Tabulas dzēšana", "addField": "Jauna lauka pievienošana", + "setDisplay": "Set as Display value", "addRow": "Pievienot ierakstu", "saveRow": "Saglabāt ierakstu", "saveAndExit": "Saglabāt un iziet", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Vai esat pārliecināts, ka vēlaties dzēst šo skatījumu?", "deleteTableConfirmation": "Vai vēlaties izdzēst tabulu", "showM2mTables": "Rādīt M2M tabulas", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Dzēšot šo kaudzīti, no `{groupingField}` tiks noņemta arī atlases opcija `{stackToBeDeleted}`. Ieraksti tiks pārvietoti uz neklasificēto kaudzi.", "computedFieldEditWarning": "Izrēķināts lauks: saturs ir tikai lasāms. Izmantojiet kolonnas rediģēšanas izvēlni, lai mainītu konfigurāciju", "computedFieldDeleteWarning": "Izrēķināts lauks: saturs ir tikai lasāms. Nevar dzēst saturu.", diff --git a/packages/nc-gui/lang/nl.json b/packages/nc-gui/lang/nl.json index f1c0bb68f2..0b12f95e1b 100644 --- a/packages/nc-gui/lang/nl.json +++ b/packages/nc-gui/lang/nl.json @@ -380,6 +380,7 @@ "renameTable": "Tabel hernoemen", "deleteTable": "Tabel verwijderen", "addField": "Voeg nieuw veld toe aan deze tabel", + "setDisplay": "Set as Display value", "addRow": "Nieuwe rij toevoegen", "saveRow": "Sla rij op", "saveAndExit": "Opslaan en afsluiten", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Weet u zeker dat u deze weergave wilt verwijderen?", "deleteTableConfirmation": "Wilt u de tabel verwijderen", "showM2mTables": "Toon M2M-tabellen", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Door deze stapel te verwijderen wordt ook de selectieoptie `{stackToBeDeleted}` van de `{groupingField}` verwijderd. De records worden verplaatst naar de ongecategoriseerde stapel.", "computedFieldEditWarning": "Berekend veld: de inhoud is alleen leesbaar. Gebruik het kolombewerkingsmenu om opnieuw te configureren", "computedFieldDeleteWarning": "Berekend veld: inhoud is alleen-lezen. Kan inhoud niet wissen.", diff --git a/packages/nc-gui/lang/no.json b/packages/nc-gui/lang/no.json index c7af1b9fac..62f9b897d2 100644 --- a/packages/nc-gui/lang/no.json +++ b/packages/nc-gui/lang/no.json @@ -380,6 +380,7 @@ "renameTable": "Tabell omdøpe", "deleteTable": "Bordet slett", "addField": "Legg til nytt felt i denne tabellen", + "setDisplay": "Set as Display value", "addRow": "Legg til ny rad", "saveRow": "Lagre rad", "saveAndExit": "Save & Exit", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Are you sure you want to delete this view?", "deleteTableConfirmation": "Do you want to delete the table", "showM2mTables": "Show M2M Tables", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.", "computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure", "computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.", diff --git a/packages/nc-gui/lang/pl.json b/packages/nc-gui/lang/pl.json index 83df241b48..082bf75fa7 100644 --- a/packages/nc-gui/lang/pl.json +++ b/packages/nc-gui/lang/pl.json @@ -380,6 +380,7 @@ "renameTable": "Zmień nazwę tabeli.", "deleteTable": "Usuń tabelę", "addField": "Dodaj nowe pole do tej tabeli", + "setDisplay": "Set as Display value", "addRow": "Dodaj nowy rząd", "saveRow": "Zapisz wiersz", "saveAndExit": "Zapisz i wyjdź", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Czy na pewno chcesz usunąć ten widok?", "deleteTableConfirmation": "Czy chcesz usunąć tabelę", "showM2mTables": "Pokaż tabele M2M", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Usunięcie tego stosu spowoduje również usunięcie wybranej opcji `{stackToBeDeleted}` z `{groupingField}`. Rekordy przeniosą się do nieskategoryzowanego stosu.", "computedFieldEditWarning": "Pole obliczeniowe: zawartość jest tylko do odczytu. Do rekonfiguracji należy użyć menu edycji kolumny", "computedFieldDeleteWarning": "Pole obliczeniowe: zawartość jest tylko do odczytu. Nie można wyczyścić zawartości.", diff --git a/packages/nc-gui/lang/pt.json b/packages/nc-gui/lang/pt.json index e5ca35262b..1444dbe424 100644 --- a/packages/nc-gui/lang/pt.json +++ b/packages/nc-gui/lang/pt.json @@ -380,6 +380,7 @@ "renameTable": "Tabela Renomear", "deleteTable": "Tabela Delete.", "addField": "Adicionar novo campo a esta tabela", + "setDisplay": "Set as Display value", "addRow": "Adicionar nova linha", "saveRow": "Salvar linha", "saveAndExit": "Salvar & Sair", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Tem a certeza de que quer apagar esta vista?", "deleteTableConfirmation": "Deseja apagar a tabela", "showM2mTables": "Mostrar Mesas M2M", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "A eliminação desta pilha irá também remover a opção seleccionada `{stackToBeDeleted}` do `{groupingField}`. Os registos serão movidos para a pilha não categorizada.", "computedFieldEditWarning": "Campo computorizado: o conteúdo é apenas de leitura. Utilizar o menu de edição de colunas para reconfigurar", "computedFieldDeleteWarning": "Campo computorizado: o conteúdo é apenas de leitura. Incapaz de limpar o conteúdo.", diff --git a/packages/nc-gui/lang/pt_BR.json b/packages/nc-gui/lang/pt_BR.json index 1966cadb71..3e090fa336 100644 --- a/packages/nc-gui/lang/pt_BR.json +++ b/packages/nc-gui/lang/pt_BR.json @@ -380,6 +380,7 @@ "renameTable": "Tabela Renomear", "deleteTable": "Tabela Delete.", "addField": "Adicionar novo campo a esta tabela", + "setDisplay": "Set as Display value", "addRow": "Adicionar nova linha", "saveRow": "Salvar linha", "saveAndExit": "Salvar & Sair", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Tem a certeza de que quer apagar esta vista?", "deleteTableConfirmation": "Deseja apagar a tabela", "showM2mTables": "Mostrar Mesas M2M", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "A eliminação desta pilha irá também remover a opção seleccionada `{stackToBeDeleted}` do `{groupingField}`. Os registos serão movidos para a pilha não categorizada.", "computedFieldEditWarning": "Campo computorizado: o conteúdo é apenas de leitura. Utilizar o menu de edição de colunas para reconfigurar", "computedFieldDeleteWarning": "Campo computorizado: o conteúdo é apenas de leitura. Incapaz de limpar o conteúdo.", diff --git a/packages/nc-gui/lang/ru.json b/packages/nc-gui/lang/ru.json index 86aeec735d..f67403136d 100644 --- a/packages/nc-gui/lang/ru.json +++ b/packages/nc-gui/lang/ru.json @@ -380,6 +380,7 @@ "renameTable": "Переименовать таблицу", "deleteTable": "Удалить таблицу", "addField": "Добавить новое поле в эту таблицу", + "setDisplay": "Set as Display value", "addRow": "Добавить новую строку", "saveRow": "Сохранить строку", "saveAndExit": "Сохранить и выйти", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Вы действительно хотите удалить это представление?", "deleteTableConfirmation": "Вы действительно хотите удалить эту таблицу", "showM2mTables": "Показать таблицы M2M", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Удаление этого стека также удалит опцию выбора `{stackToBeDeleted}` из `{groupingField}`. Записи переместятся в стек без категории.", "computedFieldEditWarning": "Вычисляемое поле: содержимое доступно только для чтения. Используйте меню редактирования столбцов для изменения конфигурации", "computedFieldDeleteWarning": "Вычисляемое поле: содержимое доступно только для чтения. Невозможно очистить содержимое.", diff --git a/packages/nc-gui/lang/sk.json b/packages/nc-gui/lang/sk.json index 3b31f34bb4..080d3f3a1b 100644 --- a/packages/nc-gui/lang/sk.json +++ b/packages/nc-gui/lang/sk.json @@ -380,6 +380,7 @@ "renameTable": "Premenovanie tabuľky", "deleteTable": "Tabuľka Vymazať", "addField": "Pridanie nového poľa do tejto tabuľky", + "setDisplay": "Set as Display value", "addRow": "Pridanie nového riadku", "saveRow": "Uložiť riadok", "saveAndExit": "Uložiť a ukončiť", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Ste si istí, že chcete toto zobrazenie odstrániť?", "deleteTableConfirmation": "Chcete odstrániť tabuľku", "showM2mTables": "Zobraziť tabuľky M2M", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Odstránením tohto zásobníka sa odstráni aj možnosť výberu `{stackToBeDeleted}` z `{groupingField}`. Záznamy sa presunú do zásobníka bez kategórií.", "computedFieldEditWarning": "Vypočítané pole: obsah je len na čítanie. Na zmenu konfigurácie použite ponuku úprav stĺpcov", "computedFieldDeleteWarning": "Vypočítané pole: obsah je len na čítanie. Nie je možné vymazať obsah.", diff --git a/packages/nc-gui/lang/sl.json b/packages/nc-gui/lang/sl.json index e93d48f62c..61b37fbc8a 100644 --- a/packages/nc-gui/lang/sl.json +++ b/packages/nc-gui/lang/sl.json @@ -380,6 +380,7 @@ "renameTable": "Preimenuj tabele", "deleteTable": "Tabela Delete.", "addField": "V to tabelo dodajte novo polje", + "setDisplay": "Set as Display value", "addRow": "Dodaj novo vrstico", "saveRow": "Shrani vrstico", "saveAndExit": "Shranjevanje in izhod", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Ste prepričani, da želite izbrisati ta pogled?", "deleteTableConfirmation": "Ali želite izbrisati tabelo", "showM2mTables": "Prikaži tabele M2M", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Z brisanjem tega sklada se odstrani tudi možnost izbire `{stackToBeDeleted}` iz `{groupingField}`. Zapisi se bodo premaknili v kup nekategoriziranih zapisov.", "computedFieldEditWarning": "Izračunano polje: vsebina je namenjena samo branju. Uporabite meni za urejanje stolpcev, da ponovno konfigurirate", "computedFieldDeleteWarning": "Izračunano polje: vsebina je namenjena samo branju. Vsebine ni mogoče izbrisati.", diff --git a/packages/nc-gui/lang/sv.json b/packages/nc-gui/lang/sv.json index 9ed31dde81..de04bf3d48 100644 --- a/packages/nc-gui/lang/sv.json +++ b/packages/nc-gui/lang/sv.json @@ -380,6 +380,7 @@ "renameTable": "Bordsbyte", "deleteTable": "Bord radera", "addField": "Lägg till nytt fält till den här tabellen", + "setDisplay": "Set as Display value", "addRow": "Lägg till ny rad", "saveRow": "Spara rad", "saveAndExit": "Spara och avsluta", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Är du säker på att du vill ta bort den här vyn?", "deleteTableConfirmation": "Vill du radera tabellen?", "showM2mTables": "Visa M2M-tabeller", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Om du raderar denna stapel kommer även alternativet \"{stackToBeDeleted}\" att tas bort från \"{groupingField}\". Posterna kommer att flyttas till stapeln \"uncategorized\".", "computedFieldEditWarning": "Beräknat fält: innehållet är skrivskyddat. Använd kolumnredigeringsmenyn för att konfigurera om.", "computedFieldDeleteWarning": "Beräknat fält: innehållet är skrivskyddat. Det går inte att rensa innehållet.", diff --git a/packages/nc-gui/lang/th.json b/packages/nc-gui/lang/th.json index edb45ae050..a08a489270 100644 --- a/packages/nc-gui/lang/th.json +++ b/packages/nc-gui/lang/th.json @@ -380,6 +380,7 @@ "renameTable": "ตารางเปลี่ยนชื่อ", "deleteTable": "ลบตาราง", "addField": "เพิ่มฟิลด์ใหม่ลงในตารางนี้", + "setDisplay": "Set as Display value", "addRow": "เพิ่มแถวใหม่", "saveRow": "บันทึกแถว", "saveAndExit": "Save & Exit", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Are you sure you want to delete this view?", "deleteTableConfirmation": "Do you want to delete the table", "showM2mTables": "Show M2M Tables", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.", "computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure", "computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.", diff --git a/packages/nc-gui/lang/tr.json b/packages/nc-gui/lang/tr.json index 6e6a1c0cb2..1ecc9d6aac 100644 --- a/packages/nc-gui/lang/tr.json +++ b/packages/nc-gui/lang/tr.json @@ -380,6 +380,7 @@ "renameTable": "Tabloyu Yeniden Adlandır", "deleteTable": "Tabloyu Sil", "addField": "Tabloya yeni alan ekle", + "setDisplay": "Set as Display value", "addRow": "Yeni satır ekle", "saveRow": "Satırı kaydet", "saveAndExit": "Kaydet ve Çık", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Bu görünümü silmek istediğinizden emin misiniz?", "deleteTableConfirmation": "Tabloyu silmek istiyor musunuz", "showM2mTables": "M2M Tablolarını Göster", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Bu yığının silinmesi `{stackToBeDeleted}` seçim seçeneğini `{groupingField}` adresinden de kaldıracaktır. Kayıtlar kategorize edilmemiş yığına taşınacaktır.", "computedFieldEditWarning": "Hesaplanan alan: içerik salt okunurdur. Yeniden yapılandırmak için sütun düzenleme menüsünü kullanın", "computedFieldDeleteWarning": "Hesaplanan alan: içerik salt okunurdur. İçerik temizlenemiyor.", diff --git a/packages/nc-gui/lang/uk.json b/packages/nc-gui/lang/uk.json index e3f6329059..4720215934 100644 --- a/packages/nc-gui/lang/uk.json +++ b/packages/nc-gui/lang/uk.json @@ -380,6 +380,7 @@ "renameTable": "Перейменувати таблицю", "deleteTable": "Видалити таблицю", "addField": "Додати нове поле до цієї таблиці", + "setDisplay": "Set as Display value", "addRow": "Додати новий рядок", "saveRow": "Зберегти рядок", "saveAndExit": "Зберегти та вийти", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Ви впевнені, що хочете видалити цей вигляд?", "deleteTableConfirmation": "Ви хочете видалити таблицю", "showM2mTables": "Показати M2M таблиці", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Видалення цього стека також вилучить опцію вибору `{stackToBeDeleted}` зі стека `{groupingField}`. Записи буде переміщено до не категоризованого стека.", "computedFieldEditWarning": "Обчислюване поле: вміст доступний лише для читання. Використовуйте меню редагування стовпця для зміни конфігурації", "computedFieldDeleteWarning": "Обчислюване поле: вміст доступний лише для читання. Не вдалося очистити вміст.", diff --git a/packages/nc-gui/lang/vi.json b/packages/nc-gui/lang/vi.json index 35157784a5..8d2e9ba7be 100644 --- a/packages/nc-gui/lang/vi.json +++ b/packages/nc-gui/lang/vi.json @@ -380,6 +380,7 @@ "renameTable": "Đổi tên bảng.", "deleteTable": "Bảng xóa", "addField": "Thêm trường mới vào bảng này", + "setDisplay": "Set as Display value", "addRow": "Thêm hàng mới", "saveRow": "Lưu hàng.", "saveAndExit": "Save & Exit", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "Are you sure you want to delete this view?", "deleteTableConfirmation": "Do you want to delete the table", "showM2mTables": "Show M2M Tables", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.", "computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure", "computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.", diff --git a/packages/nc-gui/lang/zh-Hans.json b/packages/nc-gui/lang/zh-Hans.json index 296a860a17..3c52639863 100644 --- a/packages/nc-gui/lang/zh-Hans.json +++ b/packages/nc-gui/lang/zh-Hans.json @@ -380,6 +380,7 @@ "renameTable": "重命名表格", "deleteTable": "删除表格", "addField": "添加新字段", + "setDisplay": "Set as Display value", "addRow": "添加新行", "saveRow": "保存行", "saveAndExit": "保存并退出", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "您确定要删除此视图?", "deleteTableConfirmation": "您想要删除该表吗?", "showM2mTables": "显示中间表", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "删除这个类别标签也将从 \"{groupingField}\"中删除选择选项 \"{stackToBeDeleted}\"。这类记录将移到未分类的类别中。", "computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure", "computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.", diff --git a/packages/nc-gui/lang/zh-Hant.json b/packages/nc-gui/lang/zh-Hant.json index a57c3d6361..e51d2eedd5 100644 --- a/packages/nc-gui/lang/zh-Hant.json +++ b/packages/nc-gui/lang/zh-Hant.json @@ -380,6 +380,7 @@ "renameTable": "表重命名", "deleteTable": "表刪除", "addField": "將新字段添加到此表", + "setDisplay": "Set as Display value", "addRow": "新增行", "saveRow": "儲存行", "saveAndExit": "儲存並結束", @@ -630,6 +631,11 @@ "deleteViewConfirmation": "是否確定要刪除此檢視?", "deleteTableConfirmation": "你想刪除此資料表", "showM2mTables": "顯示多對多資料表", + "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", + "showNullInCells": "Show NULL in Cells", + "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", + "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", + "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", "deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.", "computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure", "computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.", diff --git a/packages/nc-gui/lib/constants.ts b/packages/nc-gui/lib/constants.ts index bb98afbaeb..bfaa00720d 100644 --- a/packages/nc-gui/lib/constants.ts +++ b/packages/nc-gui/lib/constants.ts @@ -57,6 +57,7 @@ export const rolePermissions = { fieldsSync: true, gridColUpdate: true, filterSync: true, + filterChildrenRead: true, csvImport: true, apiDocs: true, projectSettings: true, diff --git a/packages/nc-gui/package-lock.json b/packages/nc-gui/package-lock.json index cb872b72ec..760ec39993 100644 --- a/packages/nc-gui/package-lock.json +++ b/packages/nc-gui/package-lock.json @@ -29,7 +29,7 @@ "jwt-decode": "^3.1.2", "locale-codes": "^1.3.1", "monaco-editor": "^0.33.0", - "nocodb-sdk": "0.105.2", + "nocodb-sdk": "file:../nocodb-sdk", "papaparse": "^5.3.2", "qrcode": "^1.5.1", "socket.io-client": "^4.5.1", @@ -98,7 +98,6 @@ }, "../nocodb-sdk": { "version": "0.105.2", - "extraneous": true, "license": "AGPL-3.0-or-later", "dependencies": { "axios": "^0.21.1", @@ -8555,6 +8554,7 @@ "version": "1.15.1", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", + "devOptional": true, "funding": [ { "type": "individual", @@ -11970,21 +11970,8 @@ } }, "node_modules/nocodb-sdk": { - "version": "0.105.2", - "resolved": "https://registry.npmjs.org/nocodb-sdk/-/nocodb-sdk-0.105.2.tgz", - "integrity": "sha512-Mvk8JKgDT53aVYJbA6FwGlZyDOpVKmmrPUPopXeTL4wfiztkGD2/roUq+3pt6x9/STkOTdsUI5R1D4Kjle7XSA==", - "dependencies": { - "axios": "^0.21.1", - "jsep": "^1.3.6" - } - }, - "node_modules/nocodb-sdk/node_modules/axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "dependencies": { - "follow-redirects": "^1.14.0" - } + "resolved": "../nocodb-sdk", + "link": true }, "node_modules/node-abi": { "version": "3.23.0", @@ -23975,7 +23962,8 @@ "follow-redirects": { "version": "1.15.1", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", - "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==" + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", + "devOptional": true }, "form-data": { "version": "4.0.0", @@ -26448,22 +26436,22 @@ } }, "nocodb-sdk": { - "version": "0.105.2", - "resolved": "https://registry.npmjs.org/nocodb-sdk/-/nocodb-sdk-0.105.2.tgz", - "integrity": "sha512-Mvk8JKgDT53aVYJbA6FwGlZyDOpVKmmrPUPopXeTL4wfiztkGD2/roUq+3pt6x9/STkOTdsUI5R1D4Kjle7XSA==", + "version": "file:../nocodb-sdk", "requires": { + "@typescript-eslint/eslint-plugin": "^4.0.1", + "@typescript-eslint/parser": "^4.0.1", "axios": "^0.21.1", - "jsep": "^1.3.6" - }, - "dependencies": { - "axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "requires": { - "follow-redirects": "^1.14.0" - } - } + "cspell": "^4.1.0", + "eslint": "^7.8.0", + "eslint-config-prettier": "^6.11.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-functional": "^3.0.2", + "eslint-plugin-import": "^2.22.0", + "eslint-plugin-prettier": "^4.0.0", + "jsep": "^1.3.6", + "npm-run-all": "^4.1.5", + "prettier": "^2.1.1", + "typescript": "^4.0.2" } }, "node-abi": { diff --git a/packages/nc-gui/package.json b/packages/nc-gui/package.json index d032d68f3c..b37773df3f 100644 --- a/packages/nc-gui/package.json +++ b/packages/nc-gui/package.json @@ -52,7 +52,7 @@ "jwt-decode": "^3.1.2", "locale-codes": "^1.3.1", "monaco-editor": "^0.33.0", - "nocodb-sdk": "0.105.2", + "nocodb-sdk": "file:../nocodb-sdk", "papaparse": "^5.3.2", "qrcode": "^1.5.1", "socket.io-client": "^4.5.1", diff --git a/packages/noco-docs/content/en/FAQs.md b/packages/noco-docs/content/en/FAQs.md index cce8e070fa..4d881c7323 100644 --- a/packages/noco-docs/content/en/FAQs.md +++ b/packages/noco-docs/content/en/FAQs.md @@ -65,7 +65,7 @@ Auth Token is a JWT Token generated based on the logged-in user. By default, the API Token is a Nano ID with a length of 40. If you are passing API Token, make sure that the header is called `xc-token`. -## Do you plan to have Enterprise Edition ? +## Do we plan to have an Enterprise Edition? For features that make sense for enterprises like below - yes - SSO, SLA, Organisation wide reports and analytics, - Advanced Audit or ACL, @@ -78,3 +78,17 @@ And increasing number of our customers are requesting it. - Depends on the effort and whether the intended users are enterprises. +## What are the official socials for NocoDB? + +- Youtube: https://www.youtube.com/@nocodb +- Twitter: https://twitter.com/nocodb +- Discord: http://discord.nocodb.com/ +- GitHub: https://github.com/nocodb/nocodb +- Community Forums: https://community.nocodb.com/ +- LinkedIn: https://www.linkedin.com/company/nocodb +- Reddit: https://www.reddit.com/r/NocoDB/ + +## Is NocoDB available on the cloud? + +Soon! NocoDB is currently developing cloud infrastructure. +To join the upcoming FREE private beta program, [fill out this form here](https://docs.google.com/forms/d/e/1FAIpQLSfKLe8Rcrq0uo2_jM5W1kbVBbzDiQ3IvlP8Iov61FTekVAvzA/viewform) and be the first to try it! diff --git a/packages/noco-docs/content/en/developer-resources/accessing-apis.md b/packages/noco-docs/content/en/developer-resources/accessing-apis.md index 713d8d441d..e59d99396e 100644 --- a/packages/noco-docs/content/en/developer-resources/accessing-apis.md +++ b/packages/noco-docs/content/en/developer-resources/accessing-apis.md @@ -18,23 +18,7 @@ Auth Token is a JWT Token generated based on the logged-in user. By default, the ## API Token -NocoDB allows creating API tokens which allow it to be integrated seamlessly with 3rd party apps. API Token is a Nano ID with a length of 40. If you are passing API Token, make sure that the header is called `xc-token`. - -- Open `Project Menu`, click on `Team & Settings` - -image - -- Click `API Tokens Management` tab under `Team & Auth` section - -- Click Add New Token - -![Screenshot 2022-09-14 at 10 20 00 AM](https://user-images.githubusercontent.com/86527202/190062728-9c09934f-b5e4-4fec-b4d2-0cd3648bbb39.png) - -- Type an recognizable name for your token and click `Generate` - -![Screenshot 2022-09-14 at 10 20 10 AM](https://user-images.githubusercontent.com/86527202/190062801-db3fab83-7974-4dfe-9c83-bf0d8a7dba1e.png) - -- Copy API token to your clipboard; use action menu to the right of token list +API tokens allows us to integrate seamlessly with 3rd party apps. See [API Tokens Management](../setup-and-usages/team-and-auth#api-tokens-management) for more. ## Swagger UI diff --git a/packages/noco-docs/content/en/getting-started/environment-variables.md b/packages/noco-docs/content/en/getting-started/environment-variables.md index 19cf938fe2..5ce104419c 100644 --- a/packages/noco-docs/content/en/getting-started/environment-variables.md +++ b/packages/noco-docs/content/en/getting-started/environment-variables.md @@ -13,54 +13,55 @@ For production usecases, it is **recommended** to configure - `NC_PUBLIC_URL`, - `NC_REDIS_URL` -| Variable | Comments | If absent | | -|------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------|---| -| NC_DB | See our database URLs | A local SQLite will be created in root folder if `NC_DB` is not provided | | -| NC_DB_JSON | Can be used instead of `NC_DB` and value should be valid knex connection JSON | | | -| NC_DB_JSON_FILE | Can be used instead of `NC_DB` and value should be a valid path to knex connection JSON | | | -| DATABASE_URL | JDBC URL Format. Can be used instead of NC_DB. | | | -| DATABASE_URL_FILE | Can be used instead of DATABASE_URL: path to file containing JDBC URL Format. | | | -| NC_AUTH_JWT_SECRET | JWT secret used for auth and storing other secrets | A random secret will be generated | | -| PORT | For setting app running port | `8080` | | -| DB_QUERY_LIMIT_DEFAULT | Default pagination limit | 25 | | -| DB_QUERY_LIMIT_MAX | Maximum allowed pagination limit | 1000 | | -| DB_QUERY_LIMIT_MIN | Minimum allowed pagination limit | 1 | | -| NC_TOOL_DIR | App directory to keep metadata and app related files | Defaults to current working directory. In docker maps to `/usr/app/data/` for mounting volume. | | -| NC_PUBLIC_URL | Used for sending Email invitations | Best guess from http request params | | -| NC_JWT_EXPIRES_IN | JWT token expiry time | `10h` | | -| NC_CONNECT_TO_EXTERNAL_DB_DISABLED | Disable Project creation with external database | | | -| NC_INVITE_ONLY_SIGNUP | Removed since version 0.99.0 and now it's recommended to use [super admin settings menu](/setup-and-usages/account-settings#enable--disable-signup). Allow users to signup only via invite url, value should be any non-empty string. | | | -| NUXT_PUBLIC_NC_BACKEND_URL | Custom Backend URL | ``http://localhost:8080`` will be used | | -| NC_REQUEST_BODY_SIZE | Request body size [limit](https://expressjs.com/en/resources/middleware/body-parser.html#limit) | `1048576` | | -| NC_EXPORT_MAX_TIMEOUT | After NC_EXPORT_MAX_TIMEOUT csv gets downloaded in batches | Default value 5000(in millisecond) will be used | | -| NC_DISABLE_TELE | Disable telemetry | | | -| NC_DASHBOARD_URL | Custom dashboard url path | `/dashboard` | | -| NC_GOOGLE_CLIENT_ID | Google client id to enable google authentication | | | -| NC_GOOGLE_CLIENT_SECRET | Google client secret to enable google authentication | | | -| NC_MIGRATIONS_DISABLED | Disable NocoDB migration | | | -| NC_MIN | If set to any non-empty string the default splash screen(initial welcome animation) and matrix screensaver will disable | | | -| NC_SENTRY_DSN | For Sentry monitoring | | | -| NC_REDIS_URL | Custom Redis URL. Example: `redis://:authpassword@127.0.0.1:6380/4` | Meta data will be stored in memory | | -| NC_DISABLE_ERR_REPORT | Disable error reporting | | | -| NC_DISABLE_CACHE | To be used only while debugging. On setting this to `true` - meta data be fetched from db instead of redis/cache. | `false` | | -| NC_BASEURL_INTERNAL | Used as base url for internal(server) API calls | Default value in docker will be `http://localhost:$PORT` and in all other case it's populated from request object | | -| AWS_ACCESS_KEY_ID | For Litestream - S3 access key id | If Litestream is configured and `NC_DB` is not present. SQLite gets backed up to S3 | | -| AWS_SECRET_ACCESS_KEY | For Litestream - S3 secret access key | If Litestream is configured and `NC_DB` is not present. SQLite gets backed up to S3 | | -| AWS_BUCKET | For Litestream - S3 bucket | If Litestream is configured and `NC_DB` is not present. SQLite gets backed up to S3 | | -| AWS_BUCKET_PATH | For Litestream - S3 bucket path (like folder within S3 bucket) | If Litestream is configured and `NC_DB` is not present. SQLite gets backed up to S3 | | -| NC_SMTP_FROM | For SMTP plugin - Email sender address | | | -| NC_SMTP_HOST | For SMTP plugin - SMTP host value | | | -| NC_SMTP_PORT | For SMTP plugin - SMTP port value | | | -| NC_SMTP_USERNAME | For SMTP plugin (Optional) - SMTP username value for authentication | | | -| NC_SMTP_PASSWORD | For SMTP plugin (Optional) - SMTP password value for authentication | | | -| NC_SMTP_SECURE | For SMTP plugin (Optional) - To enable secure set value as `true` any other value treated as false | | | -| NC_SMTP_IGNORE_TLS | For SMTP plugin (Optional) - To ignore tls set value as `true` any other value treated as false. For more info visit https://nodemailer.com/smtp/ | | | -| NC_S3_BUCKET_NAME | For S3 storage plugin - AWS S3 bucket name | | | -| NC_S3_REGION | For S3 storage plugin - AWS S3 region | | | -| NC_S3_ACCESS_KEY | For S3 storage plugin - AWS access key credential for accessing resource | | | -| NC_S3_ACCESS_SECRET | For S3 storage plugin - AWS access secret credential for accessing resource | | | -| NC_ADMIN_EMAIL | For updating/creating super admin with provided email and password | | | -| NC_ATTACHMENT_FIELD_SIZE | For setting the attachment field size(in Bytes) | Defaults to 20MB | | -| NC_ADMIN_PASSWORD | For updating/creating super admin with provided email and password. Your password should have at least 8 letters with one uppercase, one number and one special letter(Allowed special chars $&+,:;=?@#\|'.^*()%!_-" ) | | | -| NODE_OPTIONS | For passing Node.js [options](https://nodejs.org/api/cli.html#node_optionsoptions) to instance | | | -| NC_MINIMAL_DBS | Create a new SQLite file for each project. All the db files are stored in `nc_minimal_dbs` folder in current working directory. (This option restricts project creation on external sources) | | | +| Variable | Comments | If absent | | +|---|---|---|---| +| NC_DB | See our database URLs | A local SQLite will be created in root folder if `NC_DB` is not provided | | +| NC_DB_JSON | Can be used instead of `NC_DB` and value should be valid knex connection JSON | | | +| NC_DB_JSON_FILE | Can be used instead of `NC_DB` and value should be a valid path to knex connection JSON | | | +| DATABASE_URL | JDBC URL Format. Can be used instead of NC_DB. | | | +| DATABASE_URL_FILE | Can be used instead of DATABASE_URL: path to file containing JDBC URL Format. | | | +| NC_AUTH_JWT_SECRET | JWT secret used for auth and storing other secrets | A random secret will be generated | | +| PORT | For setting app running port | `8080` | | +| DB_QUERY_LIMIT_DEFAULT | Default pagination limit | 25 | | +| DB_QUERY_LIMIT_MAX | Maximum allowed pagination limit | 1000 | | +| DB_QUERY_LIMIT_MIN | Minimum allowed pagination limit | 1 | | +| NC_TOOL_DIR | App directory to keep metadata and app related files | Defaults to current working directory. In docker maps to `/usr/app/data/` for mounting volume. | | +| NC_PUBLIC_URL | Used for sending Email invitations | Best guess from http request params | | +| NC_JWT_EXPIRES_IN | JWT token expiry time | `10h` | | +| NC_CONNECT_TO_EXTERNAL_DB_DISABLED | Disable Project creation with external database | | | +| NC_INVITE_ONLY_SIGNUP | Removed since version 0.99.0 and now it's recommended to use [super admin settings menu](/setup-and-usages/account-settings#enable--disable-signup). Allow users to signup only via invite url, value should be any non-empty string. | | | +| NUXT_PUBLIC_NC_BACKEND_URL | Custom Backend URL | ``http://localhost:8080`` will be used | | +| NC_REQUEST_BODY_SIZE | Request body size [limit](https://expressjs.com/en/resources/middleware/body-parser.html#limit) | `1048576` | | +| NC_EXPORT_MAX_TIMEOUT | After NC_EXPORT_MAX_TIMEOUT csv gets downloaded in batches | Default value 5000(in millisecond) will be used | | +| NC_DISABLE_TELE | Disable telemetry | | | +| NC_DASHBOARD_URL | Custom dashboard url path | `/dashboard` | | +| NC_GOOGLE_CLIENT_ID | Google client id to enable google authentication | | | +| NC_GOOGLE_CLIENT_SECRET | Google client secret to enable google authentication | | | +| NC_MIGRATIONS_DISABLED | Disable NocoDB migration | | | +| NC_MIN | If set to any non-empty string the default splash screen(initial welcome animation) and matrix screensaver will disable | | | +| NC_SENTRY_DSN | For Sentry monitoring | | | +| NC_REDIS_URL | Custom Redis URL. Example: `redis://:authpassword@127.0.0.1:6380/4` | Meta data will be stored in memory | | +| NC_DISABLE_ERR_REPORT | Disable error reporting | | | +| NC_DISABLE_CACHE | To be used only while debugging. On setting this to `true` - meta data be fetched from db instead of redis/cache. | `false` | | +| NC_BASEURL_INTERNAL | Used as base url for internal(server) API calls | Default value in docker will be `http://localhost:$PORT` and in all other case it's populated from request object | | +| AWS_ACCESS_KEY_ID | For Litestream - S3 access key id | If Litestream is configured and `NC_DB` is not present. SQLite gets backed up to S3 | | +| AWS_SECRET_ACCESS_KEY | For Litestream - S3 secret access key | If Litestream is configured and `NC_DB` is not present. SQLite gets backed up to S3 | | +| AWS_BUCKET | For Litestream - S3 bucket | If Litestream is configured and `NC_DB` is not present. SQLite gets backed up to S3 | | +| AWS_BUCKET_PATH | For Litestream - S3 bucket path (like folder within S3 bucket) | If Litestream is configured and `NC_DB` is not present. SQLite gets backed up to S3 | | +| NC_SMTP_FROM | For SMTP plugin - Email sender address | | | +| NC_SMTP_HOST | For SMTP plugin - SMTP host value | | | +| NC_SMTP_PORT | For SMTP plugin - SMTP port value | | | +| NC_SMTP_USERNAME | For SMTP plugin (Optional) - SMTP username value for authentication | | | +| NC_SMTP_PASSWORD | For SMTP plugin (Optional) - SMTP password value for authentication | | | +| NC_SMTP_SECURE | For SMTP plugin (Optional) - To enable secure set value as `true` any other value treated as false | | | +| NC_SMTP_IGNORE_TLS | For SMTP plugin (Optional) - To ignore tls set value as `true` any other value treated as false. For more info visit https://nodemailer.com/smtp/ | | | +| NC_S3_BUCKET_NAME | For S3 storage plugin - AWS S3 bucket name | | | +| NC_S3_REGION | For S3 storage plugin - AWS S3 region | | | +| NC_S3_ACCESS_KEY | For S3 storage plugin - AWS access key credential for accessing resource | | | +| NC_S3_ACCESS_SECRET | For S3 storage plugin - AWS access secret credential for accessing resource | | | +| NC_ADMIN_EMAIL | For updating/creating super admin with provided email and password | | | +| NC_ATTACHMENT_FIELD_SIZE | For setting the attachment field size(in Bytes) | Defaults to 20MB | | +| NC_ADMIN_PASSWORD | For updating/creating super admin with provided email and password. Your password should have at least 8 letters with one uppercase, one number and one special letter(Allowed special chars $&+,:;=?@#\|'.^*()%!_-" ) | | | +| NODE_OPTIONS | For passing Node.js [options](https://nodejs.org/api/cli.html#node_optionsoptions) to instance | | | +| NC_MINIMAL_DBS | Create a new SQLite file for each project. All the db files are stored in `nc_minimal_dbs` folder in current working directory. (This option restricts project creation on external sources) | | | +| NC_DISABLE_AUDIT | Disable Audit Log | `false` | | \ No newline at end of file diff --git a/packages/noco-docs/content/en/index.md b/packages/noco-docs/content/en/index.md index 728e391265..d79a6c3020 100644 --- a/packages/noco-docs/content/en/index.md +++ b/packages/noco-docs/content/en/index.md @@ -63,3 +63,15 @@ Our mission is to provide the most powerful no-code interface for databases whic Please refer to [here](https://github.com/nocodb/nocodb/blob/develop/.github/CONTRIBUTING.md) for the contribution guidelines. + +## Where can I join the NocoDB community? + +Follow us for daily updates, content, and other activities with our community: + +- [Youtube](https://www.youtube.com/@nocodb) +- [Twitter](https://twitter.com/nocodb) +- [Discord](http://discord.nocodb.com/) +- [GitHub](https://github.com/nocodb/nocodb) +- [Community Forums](https://community.nocodb.com/) +- [LinkedIn](https://www.linkedin.com/company/nocodb) +- [Reddit](https://www.reddit.com/r/NocoDB/) diff --git a/packages/noco-docs/content/en/setup-and-usages/account-settings.md b/packages/noco-docs/content/en/setup-and-usages/account-settings.md index 29491b242e..fc9664168d 100644 --- a/packages/noco-docs/content/en/setup-and-usages/account-settings.md +++ b/packages/noco-docs/content/en/setup-and-usages/account-settings.md @@ -54,10 +54,16 @@ Signup without an invitation is disabled by default and can be managed from UI b ## App Store -You can also manage the app store plugins here. - ![image](https://user-images.githubusercontent.com/35857179/203267619-24a8f5f5-1c8c-4419-a7a1-be4377fe6216.png) +We provide different integrations in three main categories. + +| Category | App Name | +|---|---| +| Chat | Microsoft Teams
Discord
Twilio
Whatsapp Twilio
Mattermost
Slack | +| Email | SMTP
MailerSend
AWS SES | +| Storage | AWS S3
Minio
Google Cloud Storage
Spaces
Backblaze B2
Vultr Object Storage
OvhCloud Object Storage
Linode Object Storage
UpCloud Object Storage
Scaleway Object Storage | + ## License You can configure NocoDB Enterprise `License key` here diff --git a/packages/noco-docs/content/en/setup-and-usages/app-store.md b/packages/noco-docs/content/en/setup-and-usages/app-store.md deleted file mode 100644 index ac6e464e37..0000000000 --- a/packages/noco-docs/content/en/setup-and-usages/app-store.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: 'Account Settings > App Store' -description: 'NocoDB provides different integrations in three main categories in App Store' -position: 590 -category: 'Product' -menuTitle: 'Account Settings > App Store' ---- - -## Overview - -To access it, click the down arrow button next to Project Name on the top left side, then select `Account Settings` and clicking `App Store`. - -Screenshot 2023-02-07 at 5 14 11 PM | Screenshot 2023-02-07 at 5 14 30 PM -|--|--| - -We provide different integrations in three main categories. - -| Category | App Name | -|---|---| -| Chat | Microsoft Teams
Discord
Twilio
Whatsapp Twilio
Mattermost
Slack | -| Email | SMTP
MailerSend
AWS SES | -| Storage | AWS S3
Minio
Google Cloud Storage
Spaces
Backblaze B2
Vultr Object Storage
OvhCloud Object Storage
Linode Object Storage
UpCloud Object Storage
Scaleway Object Storage | diff --git a/packages/noco-docs/content/en/setup-and-usages/audit.md b/packages/noco-docs/content/en/setup-and-usages/audit.md index 23b3c0e96e..191b5e7d9d 100644 --- a/packages/noco-docs/content/en/setup-and-usages/audit.md +++ b/packages/noco-docs/content/en/setup-and-usages/audit.md @@ -10,6 +10,10 @@ menuTitle: 'Team & Settings > Audit' We are keeping all the user operation logs under Audit. To access it, click the down arrow button next to Project Name on the top left side, then select `Team & Settings`. + +We can disable audit logs by setting `NC_DISABLE_AUDIT` to `true`. + + image Then, under SETTINGS, click `Audit`. diff --git a/packages/noco-docs/content/en/setup-and-usages/dashboard.md b/packages/noco-docs/content/en/setup-and-usages/dashboard.md index 76c833b79d..5483015606 100644 --- a/packages/noco-docs/content/en/setup-and-usages/dashboard.md +++ b/packages/noco-docs/content/en/setup-and-usages/dashboard.md @@ -44,19 +44,16 @@ Click on three-dot menu adjacent to `BASES`. Pick required database option from Tip: If you are running NocoDB on Docker and your local DB is running on your host machine, your Host Address would be host.docker.internal instead of localhost. - - - + ![Screenshot 2022-12-29 at 2 55 39 PM](https://user-images.githubusercontent.com/86527202/209933294-9327ff16-21db-4aca-bf16-8cea8a1eb415.png) Above menu is also accessible from `Team & Settings` > `Data Sources`. Click on `New` button to add existing database. - -![Screenshot 2022-12-29 at 3 16 36 PM](https://user-images.githubusercontent.com/86527202/209936942-f82a293f-2e91-48da-b9cd-79ec143d7d6f.png) - +![image](https://user-images.githubusercontent.com/35857179/219841162-6456c5cf-fd26-4a88-8de6-e8742c043607.png) + You need to specify the project name, API type, and other database parameters. -![Screenshot 2022-12-29 at 2 56 25 PM](https://user-images.githubusercontent.com/86527202/209933326-e76eee13-4942-4ba8-b184-a28099c089ab.png) +![image](https://user-images.githubusercontent.com/35857179/219841283-1a42f9f6-4677-4e25-8ca9-a060753d1e1e.png) Currently it supports MySQL, Postgres, MSSQL and SQLite. diff --git a/packages/noco-docs/content/en/setup-and-usages/meta-management.md b/packages/noco-docs/content/en/setup-and-usages/meta-management.md index cb496382c2..3c6825bf80 100644 --- a/packages/noco-docs/content/en/setup-and-usages/meta-management.md +++ b/packages/noco-docs/content/en/setup-and-usages/meta-management.md @@ -6,6 +6,8 @@ category: 'Product' menuTitle: 'Team & Settings > Data Sources' --- +## Overview + `Data Sources` sub-menu includes - Database Metadata - UI Access Control @@ -14,46 +16,33 @@ menuTitle: 'Team & Settings > Data Sources' - Edit existing data source configuration - Edit data source visibility options - Note that, currently only one external data source can be added per project. -To access it, click the down arrow button next to Project Name on the top left side, then select `Team & Settings` and clicking `Data Sources`. - - -![Screenshot 2022-12-29 at 4 29 24 PM](https://user-images.githubusercontent.com/86527202/209941906-a9c8d48d-d604-4a2f-8ffb-7a9a494bac6b.png) -![Screenshot 2022-12-29 at 4 27 14 PM](https://user-images.githubusercontent.com/86527202/209941716-70f2aaa7-b035-42b2-835e-eb2ca348be42.png) +## Accessing Data Sources +To access it, click the down arrow button next to Project Name on the top left side, then select `Team & Settings` and clicking `Data Sources`. - - - - -![Screenshot 2022-12-29 at 4 15 00 PM](https://user-images.githubusercontent.com/86527202/209940452-5b867b71-b9f1-4e64-af69-14715ab73be7.png) - +image +![image](https://user-images.githubusercontent.com/35857179/219833316-1fb234f0-583f-4ab8-b8d7-a6e249e7cd97.png) ## Sync Metadata Go to `Data Sources`, click ``Sync Metadata``, you can see your metadata sync status. If it is out of sync, you can sync the schema. See Sync Schema for more.0 -![Screenshot 2022-12-29 at 4 19 35 PM](https://user-images.githubusercontent.com/86527202/209940903-396650b4-e219-494a-863f-c3f1beb51c5e.png) - - - +![image](https://user-images.githubusercontent.com/35857179/219833485-3bcaa6ec-88bc-47cc-b938-5abb4835dc31.png) ## UI Access Control Go to `Data Sources`, click ``UI ACL``, you can control the access to each table by roles. - -![Screenshot 2022-12-29 at 4 20 57 PM](https://user-images.githubusercontent.com/86527202/209941141-deed80a9-7682-48e1-8de9-9c965c990d2d.png) +![image](https://user-images.githubusercontent.com/35857179/219833072-20e9f4ad-fd1c-4e96-9112-6edda1447ec6.png) ## ERD Go to `Data Sources`, click ``ERD``, you can see the ERD of your database. -![Screenshot 2022-12-29 at 4 21 55 PM](https://user-images.githubusercontent.com/86527202/209941168-b53d2898-8448-47fa-a8b3-6f3572f6b3a2.png) - +![image](https://user-images.githubusercontent.com/35857179/219832288-f6266544-a259-4667-95d9-0e5ce7ac5d27.png) ### Junction table names within ERD @@ -61,32 +50,23 @@ Go to `Data Sources`, click ``ERD``, you can see the ERD of your database. - Double click on `Show Columns` to see additional checkboxes get enabled. - Enabling which you should be able to see junction tables and their table names. -Show Junction table names for many to many table +![image](https://user-images.githubusercontent.com/35857179/219832436-9c1311c3-854c-4b31-9c94-8035dfba2a2b.png) ## Edit external database configuration parameters Go to `Data Sources`, click ``Edit``, you can re-configure database credentials. Please make sure database configuration parameters are valid. Any incorrect parameters could lead to schema loss! - -![Screenshot 2022-12-29 at 4 22 08 PM](https://user-images.githubusercontent.com/86527202/209941211-de9670c9-a73c-4719-9957-eeaf05f3a7ee.png) - +![image](https://user-images.githubusercontent.com/35857179/219832592-14209cbf-d980-4e14-9a59-bda1b778a74e.png) ## Unlink data source Go to `Data Sources`, click ``Delete`` against the data source that you wish to un-link. -![Screenshot 2022-12-29 at 4 31 16 PM](https://user-images.githubusercontent.com/86527202/209942178-5ae40f14-0e87-41f7-9630-e2bf6f59a906.png) +![image](https://user-images.githubusercontent.com/35857179/219832810-a3e9ed88-f732-4f30-9228-ff782be0b9d6.png) ## Data source visibility Go to `Data Sources`, toggle ``Radio-button`` against the data source that you wish to hide/un-hide. -![Screenshot 2022-12-29 at 4 31 16 PM 2](https://user-images.githubusercontent.com/86527202/209942198-627f7f14-761b-4709-b9ca-fde5111fa207.png) - - +![image](https://user-images.githubusercontent.com/35857179/219832914-f485099c-423f-4df8-bf00-b509288efe6d.png) \ No newline at end of file diff --git a/packages/noco-docs/content/en/setup-and-usages/project-settings.md b/packages/noco-docs/content/en/setup-and-usages/project-settings.md index 611fa80015..48fce3da98 100644 --- a/packages/noco-docs/content/en/setup-and-usages/project-settings.md +++ b/packages/noco-docs/content/en/setup-and-usages/project-settings.md @@ -14,8 +14,4 @@ Generic project configuration options are retained under `Project Settings` menu Then, under SETTINGS, click `Project Settings`. -## Miscellaneous - -- Enabling, `Show M2M Tables` will show junction tables between many to many tables. - -![Screenshot 2022-12-29 at 7 05 04 PM](https://user-images.githubusercontent.com/86527202/209961654-ffe8ddc6-c7e2-4c0d-9762-2b57fb883cfa.png) +![image](https://user-images.githubusercontent.com/35857179/219830971-9518fa21-a45c-4d49-af3f-2f933d779ecd.png) diff --git a/packages/noco-docs/content/en/setup-and-usages/sync-schema.md b/packages/noco-docs/content/en/setup-and-usages/sync-schema.md index 3ce8c23e98..6257c95974 100644 --- a/packages/noco-docs/content/en/setup-and-usages/sync-schema.md +++ b/packages/noco-docs/content/en/setup-and-usages/sync-schema.md @@ -16,17 +16,19 @@ Below are the steps to sync schema changes. image -### 2. Click `Project Metadata` under SETTINGS, access `Metadata` tab +### 2. Click `Data Source` under SETTINGS, click `Sync Metadata` on the target base -image +![image](https://user-images.githubusercontent.com/35857179/219831352-e6692ba5-5c94-4331-94ce-5796e57f87a1.png) + +![image](https://user-images.githubusercontent.com/35857179/219831634-bbb6f256-45fb-4224-9f82-bc1bed6082db.png) ### 3. Changes carried outside GUI, identified by NocoDB are listed under `Sync state` + - If changes made to the database are not visible, click `Reload` - Identified schema changes are identified for each table in `red` - `Sync now` button gets activated, if Schema changes are identified by NocoDB -![Screenshot 2022-09-13 at 10 42 12 AM](https://user-images.githubusercontent.com/86527202/189814648-ca28f28d-b0ed-4652-a5da-e6472bfd9407.png) - +![image](https://user-images.githubusercontent.com/35857179/219831855-bcac229c-41b6-4689-b7e1-c3cdfe23a0a1.png) ### 4. Click `Sync Now` to complete Schema sync procedure diff --git a/packages/noco-docs/content/en/setup-and-usages/team-and-auth.md b/packages/noco-docs/content/en/setup-and-usages/team-and-auth.md index b6baf4bc04..4fba8a7900 100644 --- a/packages/noco-docs/content/en/setup-and-usages/team-and-auth.md +++ b/packages/noco-docs/content/en/setup-and-usages/team-and-auth.md @@ -6,18 +6,21 @@ category: 'Product' menuTitle: 'Team & Settings > Team & Auth' --- -# Accessing Team & Auth +## Accessing Team & Auth - Click on `Team & Settings` from the `Project Menu` - Access `Team & Auth` under `Settings` image -## How to Add a User +## User Management + +### How to Add a User 1. Go to `Team & Auth`, click on `Invite Team` -image +![image](https://user-images.githubusercontent.com/35857179/219830800-481f372f-86b1-4e2f-865d-3fb7c10663f7.png) + 2. Enter the user's `E-mail`. Select `User Role`, and Click `Invite`. @@ -32,18 +35,16 @@ If you do not have an SMTP sender configured, make sure to copy the invite link ![Screenshot 2022-09-13 at 10 54 22 AM](https://user-images.githubusercontent.com/86527202/189817156-f3dab634-dc25-4f9b-8126-865187aae254.png) -## How to Update user permissions +### How to Update user permissions 1. Use `Edit` <1> menu to assign a different role to existing user 2. Use `Delete` <2> menu to remove a user from accessing current project -![Screenshot 2022-09-13 at 11 06 16 AM](https://user-images.githubusercontent.com/86527202/189818302-80a05245-9dc1-4364-b380-7bd698e5b9e0.png) - +![image](https://user-images.githubusercontent.com/35857179/219830858-be7a4656-9f3b-440c-9a79-165f919223d7.png) ------ - -# User Role Permissions +### User Role Permissions ### Advanced Options & Configurations |                                                     |     Owner    |     Creator     |     Editor    | Commenter |     Viewer    | @@ -106,6 +107,25 @@ If you do not have an SMTP sender configured, make sure to copy the invite link | Project Info | ✅ | ✅ | ✅ | ✅ | ✅ | | Swagger API | ✅ | ✅ | ✅ | ✅ | ✅ | +## API Tokens Management + +NocoDB allows creating API tokens which allow it to be integrated seamlessly with 3rd party apps. API Token is a Nano ID with a length of 40. If you are passing API Token, make sure that the header is called `xc-token`. + +- Open `Project Menu`, click on `Team & Settings` + +image + +- Click `API Tokens Management` tab under `Team & Auth` section + +- Click Add New Token + +![image](https://user-images.githubusercontent.com/35857179/219835108-037127bd-4bf6-4d96-b691-139bd141631c.png) + +- Type an recognizable name for your token and click `Generate` + +![Screenshot 2022-09-14 at 10 20 10 AM](https://user-images.githubusercontent.com/86527202/190062801-db3fab83-7974-4dfe-9c83-bf0d8a7dba1e.png) + +- Copy API token to your clipboard; use action menu to the right of token list + --> \ No newline at end of file diff --git a/packages/nocodb-sdk/package-lock.json b/packages/nocodb-sdk/package-lock.json index a922f9f642..e9169032f3 100644 --- a/packages/nocodb-sdk/package-lock.json +++ b/packages/nocodb-sdk/package-lock.json @@ -1,12 +1,12 @@ { "name": "nocodb-sdk", - "version": "0.105.1", + "version": "0.105.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "nocodb-sdk", - "version": "0.105.1", + "version": "0.105.2", "license": "AGPL-3.0-or-later", "dependencies": { "axios": "^0.21.1", diff --git a/packages/nocodb-sdk/src/lib/Api.ts b/packages/nocodb-sdk/src/lib/Api.ts index 93ae72c9ec..a72029e453 100644 --- a/packages/nocodb-sdk/src/lib/Api.ts +++ b/packages/nocodb-sdk/src/lib/Api.ts @@ -502,7 +502,7 @@ export interface HookType { description?: string; env?: string; type?: string; - event?: 'After' | 'Before'; + event?: 'after' | 'before'; operation?: 'insert' | 'delete' | 'update'; async?: boolean; payload?: string; diff --git a/packages/nocodb/package-lock.json b/packages/nocodb/package-lock.json index ce70a47a4c..fd244d0f9b 100644 --- a/packages/nocodb/package-lock.json +++ b/packages/nocodb/package-lock.json @@ -68,7 +68,7 @@ "nc-lib-gui": "0.105.2", "nc-plugin": "0.1.2", "ncp": "^2.0.0", - "nocodb-sdk": "0.105.2", + "nocodb-sdk": "file:../nocodb-sdk", "nodemailer": "^6.4.10", "object-hash": "^3.0.0", "os-locale": "^5.0.0", @@ -155,7 +155,6 @@ }, "../nocodb-sdk": { "version": "0.105.2", - "extraneous": true, "license": "AGPL-3.0-or-later", "dependencies": { "axios": "^0.21.1", @@ -11319,13 +11318,8 @@ "dev": true }, "node_modules/nocodb-sdk": { - "version": "0.105.2", - "resolved": "https://registry.npmjs.org/nocodb-sdk/-/nocodb-sdk-0.105.2.tgz", - "integrity": "sha512-Mvk8JKgDT53aVYJbA6FwGlZyDOpVKmmrPUPopXeTL4wfiztkGD2/roUq+3pt6x9/STkOTdsUI5R1D4Kjle7XSA==", - "dependencies": { - "axios": "^0.21.1", - "jsep": "^1.3.6" - } + "resolved": "../nocodb-sdk", + "link": true }, "node_modules/node-abort-controller": { "version": "3.0.1", @@ -27930,12 +27924,22 @@ "dev": true }, "nocodb-sdk": { - "version": "0.105.2", - "resolved": "https://registry.npmjs.org/nocodb-sdk/-/nocodb-sdk-0.105.2.tgz", - "integrity": "sha512-Mvk8JKgDT53aVYJbA6FwGlZyDOpVKmmrPUPopXeTL4wfiztkGD2/roUq+3pt6x9/STkOTdsUI5R1D4Kjle7XSA==", + "version": "file:../nocodb-sdk", "requires": { + "@typescript-eslint/eslint-plugin": "^4.0.1", + "@typescript-eslint/parser": "^4.0.1", "axios": "^0.21.1", - "jsep": "^1.3.6" + "cspell": "^4.1.0", + "eslint": "^7.8.0", + "eslint-config-prettier": "^6.11.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-functional": "^3.0.2", + "eslint-plugin-import": "^2.22.0", + "eslint-plugin-prettier": "^4.0.0", + "jsep": "^1.3.6", + "npm-run-all": "^4.1.5", + "prettier": "^2.1.1", + "typescript": "^4.0.2" } }, "node-abort-controller": { diff --git a/packages/nocodb/package.json b/packages/nocodb/package.json index 0f71040ae9..ebb9842020 100644 --- a/packages/nocodb/package.json +++ b/packages/nocodb/package.json @@ -108,7 +108,7 @@ "nc-lib-gui": "0.105.2", "nc-plugin": "0.1.2", "ncp": "^2.0.0", - "nocodb-sdk": "0.105.2", + "nocodb-sdk": "file:../nocodb-sdk", "nodemailer": "^6.4.10", "object-hash": "^3.0.0", "os-locale": "^5.0.0", @@ -184,4 +184,4 @@ "prettier": { "singleQuote": true } -} \ No newline at end of file +} diff --git a/packages/nocodb/src/lib/Noco.ts b/packages/nocodb/src/lib/Noco.ts index 6c7ead8acd..b66287a446 100644 --- a/packages/nocodb/src/lib/Noco.ts +++ b/packages/nocodb/src/lib/Noco.ts @@ -105,7 +105,7 @@ export default class Noco { constructor() { process.env.PORT = process.env.PORT || '8080'; // todo: move - process.env.NC_VERSION = '0104004'; + process.env.NC_VERSION = '0105002'; // if env variable NC_MINIMAL_DBS is set, then disable project creation with external sources if (process.env.NC_MINIMAL_DBS) { diff --git a/packages/nocodb/src/lib/db/sql-client/lib/oracle/OracleClient.ts b/packages/nocodb/src/lib/db/sql-client/lib/oracle/OracleClient.ts index 34779ebbe8..4f01353ba0 100644 --- a/packages/nocodb/src/lib/db/sql-client/lib/oracle/OracleClient.ts +++ b/packages/nocodb/src/lib/db/sql-client/lib/oracle/OracleClient.ts @@ -1913,7 +1913,7 @@ class OracleClient extends KnexClient { * @returns {Number} code * @returns {String} message */ - async totalRecords(_args: any = {}) { + async totalRecords(_args: any = {}): Promise { // @ts-ignore const func = this.totalRecords.name; throw new Error('Function not supported for oracle yet'); diff --git a/packages/nocodb/src/lib/db/sql-mgr/SqlMgr.ts b/packages/nocodb/src/lib/db/sql-mgr/SqlMgr.ts index 9bbd2fa238..3f6a85b9c2 100644 --- a/packages/nocodb/src/lib/db/sql-mgr/SqlMgr.ts +++ b/packages/nocodb/src/lib/db/sql-mgr/SqlMgr.ts @@ -17,6 +17,14 @@ import NcConnectionMgr from '../../utils/common/NcConnectionMgr'; import { customAlphabet } from 'nanoid'; import Debug from '../util/Debug'; import Result from '../util/Result'; + +import type MssqlClient from '../sql-client/lib/mssql/MssqlClient'; +import type MysqlClient from '../sql-client/lib/mysql/MysqlClient'; +import type OracleClient from '../sql-client/lib/oracle/OracleClient'; +import type PGClient from '../sql-client/lib/pg/PgClient'; +import type SnowflakeClient from '../sql-client/lib/snowflake/SnowflakeClient'; +import type SqliteClient from '../sql-client/lib/sqlite/SqliteClient'; + const randomID = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz_', 20); const log = new Debug('SqlMgr'); @@ -337,7 +345,16 @@ export default class SqlMgr { * @returns * @memberof SqlMgr */ - public async projectGetSqlClient(args) { + public async projectGetSqlClient( + args + ): Promise< + | SnowflakeClient + | MysqlClient + | SqliteClient + | MssqlClient + | OracleClient + | PGClient + > { const func = this.projectGetSqlClient.name; log.api(`${func}:args:`, args); diff --git a/packages/nocodb/src/lib/db/sql-mgr/v2/SqlMgrv2.ts b/packages/nocodb/src/lib/db/sql-mgr/v2/SqlMgrv2.ts index 89ee530036..8c7d189461 100644 --- a/packages/nocodb/src/lib/db/sql-mgr/v2/SqlMgrv2.ts +++ b/packages/nocodb/src/lib/db/sql-mgr/v2/SqlMgrv2.ts @@ -118,7 +118,7 @@ export default class SqlMgrv2 { return sqlMigrationStatements; } - protected async getSqlClient(base: Base): Promise { + protected async getSqlClient(base: Base) { return NcConnectionMgrv2.getSqlClient(base); } } diff --git a/packages/nocodb/src/lib/db/sql-mgr/v2/SqlMgrv2Trans.ts b/packages/nocodb/src/lib/db/sql-mgr/v2/SqlMgrv2Trans.ts index a5def5c184..82852fed52 100644 --- a/packages/nocodb/src/lib/db/sql-mgr/v2/SqlMgrv2Trans.ts +++ b/packages/nocodb/src/lib/db/sql-mgr/v2/SqlMgrv2Trans.ts @@ -52,7 +52,7 @@ export default class SqlMgrv2Trans extends SqlMgrv2 { } } - protected async getSqlClient(base: Base): Promise { + protected async getSqlClient(base: Base) { return NcConnectionMgrv2.getSqlClient(base, this.trx); } diff --git a/packages/nocodb/src/lib/db/sql-migrator/lib/KnexMigratorv2.ts b/packages/nocodb/src/lib/db/sql-migrator/lib/KnexMigratorv2.ts index cc1ad02a34..d32a40d1d0 100644 --- a/packages/nocodb/src/lib/db/sql-migrator/lib/KnexMigratorv2.ts +++ b/packages/nocodb/src/lib/db/sql-migrator/lib/KnexMigratorv2.ts @@ -1,6 +1,7 @@ import fs from 'fs'; import path from 'path'; import { promisify } from 'util'; +import { Knex } from 'knex'; import glob from 'glob'; import SqlClientFactory from '../../sql-client/lib/SqlClientFactory'; @@ -428,7 +429,7 @@ export default class KnexMigratorv2 { // } } - protected async getSqlClient(base: Base): Promise { + protected async getSqlClient(base: Base) { return NcConnectionMgrv2.getSqlClient(base); } @@ -753,7 +754,7 @@ export default class KnexMigratorv2 { const vm = this; const trx = sqlClient.knex.isTransaction - ? sqlClient.knex + ? (sqlClient.knex as Knex.Transaction) : await sqlClient.knex.transaction(); try { for (const query of upStatements) { @@ -920,7 +921,7 @@ export default class KnexMigratorv2 { const vm = this; const trx = sqlClient.knex.isTransaction - ? sqlClient.knex + ? (sqlClient.knex as Knex.Transaction) : await sqlClient.knex.transaction(); try { for (const query of downStatements) { diff --git a/packages/nocodb/src/lib/db/sql-migrator/lib/KnexMigratorv2Tans.ts b/packages/nocodb/src/lib/db/sql-migrator/lib/KnexMigratorv2Tans.ts index 7bfe6a2bdc..87204964a0 100644 --- a/packages/nocodb/src/lib/db/sql-migrator/lib/KnexMigratorv2Tans.ts +++ b/packages/nocodb/src/lib/db/sql-migrator/lib/KnexMigratorv2Tans.ts @@ -11,6 +11,13 @@ import Noco from '../../../Noco'; import { XKnex } from '../../sql-data-mapper'; import NcMetaIO from '../../../meta/NcMetaIO'; +import type MssqlClient from '../../sql-client/lib/mssql/MssqlClient'; +import type MysqlClient from '../../sql-client/lib/mysql/MysqlClient'; +import type OracleClient from '../../sql-client/lib/oracle/OracleClient'; +import type PGClient from '../../sql-client/lib/pg/PgClient'; +import type SnowflakeClient from '../../sql-client/lib/snowflake/SnowflakeClient'; +import type SqliteClient from '../../sql-client/lib/sqlite/SqliteClient'; + export default class KnexMigratorv2Tans extends KnexMigratorv2 { protected sqlClient: any; protected ncMeta: NcMetaIO; @@ -24,7 +31,16 @@ export default class KnexMigratorv2Tans extends KnexMigratorv2 { protected get metaDb(): XKnex { return this.ncMeta.knex || Noco.ncMeta.knex; } - protected async getSqlClient(base: Base): Promise { + protected async getSqlClient( + base: Base + ): Promise< + | SnowflakeClient + | MysqlClient + | SqliteClient + | MssqlClient + | OracleClient + | PGClient + > { return this.sqlClient || NcConnectionMgrv2.getSqlClient(base); } } diff --git a/packages/nocodb/src/lib/meta/NcMetaMgr.ts b/packages/nocodb/src/lib/meta/NcMetaMgr.ts index 02b2d7b607..aecaff7189 100644 --- a/packages/nocodb/src/lib/meta/NcMetaMgr.ts +++ b/packages/nocodb/src/lib/meta/NcMetaMgr.ts @@ -2909,7 +2909,7 @@ export default class NcMetaMgr { } } - protected async projectGetSqlClient(args): Promise { + protected async projectGetSqlClient(args) { const builder = this.getBuilder(args); return builder?.getSqlClient(); } diff --git a/packages/nocodb/src/lib/meta/api/attachmentApis.ts b/packages/nocodb/src/lib/meta/api/attachmentApis.ts index 0053b99304..88097286b4 100644 --- a/packages/nocodb/src/lib/meta/api/attachmentApis.ts +++ b/packages/nocodb/src/lib/meta/api/attachmentApis.ts @@ -14,6 +14,7 @@ import catchError, { NcError } from '../helpers/catchError'; import NcPluginMgrv2 from '../helpers/NcPluginMgrv2'; import Local from '../../v1-legacy/plugins/adapters/storage/Local'; import { NC_ATTACHMENT_FIELD_SIZE } from '../../constants'; +import { getCacheMiddleware } from './helpers'; const isUploadAllowed = async (req: Request, _res: Response, next: any) => { if (!req['user']?.id) { @@ -161,32 +162,36 @@ export async function fileRead(req, res) { const router = Router({ mergeParams: true }); -router.get(/^\/dl\/([^/]+)\/([^/]+)\/(.+)$/, async (req, res) => { - try { - // const type = mimetypes[path.extname(req.params.fileName).slice(1)] || 'text/plain'; - const type = - mimetypes[path.extname(req.params[2]).split('/').pop().slice(1)] || - 'text/plain'; - - const storageAdapter = await NcPluginMgrv2.storageAdapter(); - // const img = await this.storageAdapter.fileRead(slash(path.join('nc', req.params.projectId, req.params.dbAlias, 'uploads', req.params.fileName))); - const img = await storageAdapter.fileRead( - slash( - path.join( - 'nc', - req.params[0], - req.params[1], - 'uploads', - ...req.params[2].split('/') +router.get( + /^\/dl\/([^/]+)\/([^/]+)\/(.+)$/, + getCacheMiddleware(), + async (req, res) => { + try { + // const type = mimetypes[path.extname(req.params.fileName).slice(1)] || 'text/plain'; + const type = + mimetypes[path.extname(req.params[2]).split('/').pop().slice(1)] || + 'text/plain'; + + const storageAdapter = await NcPluginMgrv2.storageAdapter(); + // const img = await this.storageAdapter.fileRead(slash(path.join('nc', req.params.projectId, req.params.dbAlias, 'uploads', req.params.fileName))); + const img = await storageAdapter.fileRead( + slash( + path.join( + 'nc', + req.params[0], + req.params[1], + 'uploads', + ...req.params[2].split('/') + ) ) - ) - ); - res.writeHead(200, { 'Content-Type': type }); - res.end(img, 'binary'); - } catch (e) { - res.status(404).send('Not found'); + ); + res.writeHead(200, { 'Content-Type': type }); + res.end(img, 'binary'); + } catch (e) { + res.status(404).send('Not found'); + } } -}); +); export function sanitizeUrlPath(paths) { return paths.map((url) => url.replace(/[/.?#]+/g, '_')); @@ -217,6 +222,6 @@ router.post( ] ); -router.get(/^\/download\/(.+)$/, catchError(fileRead)); +router.get(/^\/download\/(.+)$/, getCacheMiddleware(), catchError(fileRead)); export default router; diff --git a/packages/nocodb/src/lib/meta/api/helpers/cacheHelpers.ts b/packages/nocodb/src/lib/meta/api/helpers/cacheHelpers.ts new file mode 100644 index 0000000000..40fa30c064 --- /dev/null +++ b/packages/nocodb/src/lib/meta/api/helpers/cacheHelpers.ts @@ -0,0 +1,13 @@ +// return a middleware to set cache-control header +// default period is 30 days +export const getCacheMiddleware = (period: string | number = 2592000) => { + return async (req, res, next) => { + const { method } = req; + // only cache GET requests + if (method === 'GET') { + // set cache-control header + res.set('Cache-Control', `public, max-age=${period}`); + } + next(); + }; +}; diff --git a/packages/nocodb/src/lib/meta/api/helpers/index.ts b/packages/nocodb/src/lib/meta/api/helpers/index.ts index 1fd8d4367b..ee77b070e2 100644 --- a/packages/nocodb/src/lib/meta/api/helpers/index.ts +++ b/packages/nocodb/src/lib/meta/api/helpers/index.ts @@ -1,5 +1,6 @@ import { populateMeta } from './populateMeta'; export * from './columnHelpers'; export * from './apiHelpers'; +export * from './cacheHelpers'; export { populateMeta }; diff --git a/packages/nocodb/src/lib/meta/api/helpers/populateMeta.ts b/packages/nocodb/src/lib/meta/api/helpers/populateMeta.ts index ff7861a529..ffe246a131 100644 --- a/packages/nocodb/src/lib/meta/api/helpers/populateMeta.ts +++ b/packages/nocodb/src/lib/meta/api/helpers/populateMeta.ts @@ -229,6 +229,8 @@ export async function populateMeta(base: Base, project: Project): Promise { const columns = (await sqlClient.columnList({ tn: table.table_name })) ?.data?.list; + mapDefaultDisplayValue(columns); + /* create nc_models and its rows if it doesn't exists */ models2[table.table_name] = await Model.insert(project.id, base.id, { table_name: table.table_name, diff --git a/packages/nocodb/src/lib/meta/api/utilApis.ts b/packages/nocodb/src/lib/meta/api/utilApis.ts index b7a9f0d601..8bafe86ce4 100644 --- a/packages/nocodb/src/lib/meta/api/utilApis.ts +++ b/packages/nocodb/src/lib/meta/api/utilApis.ts @@ -53,7 +53,8 @@ export async function appInfo(req: Request, res: Response) { ), timezone: defaultConnectionConfig.timezone, ncMin: !!process.env.NC_MIN, - teleEnabled: !process.env.NC_DISABLE_TELE, + teleEnabled: process.env.NC_DISABLE_TELE === 'true' ? false : true, + auditEnabled: process.env.NC_DISABLE_AUDIT === 'true' ? false : true, ncSiteUrl: (req as any).ncSiteUrl, ee: Noco.isEE(), ncAttachmentFieldSize: NC_ATTACHMENT_FIELD_SIZE, diff --git a/packages/nocodb/src/lib/meta/helpers/mapDefaultDisplayValue.ts b/packages/nocodb/src/lib/meta/helpers/mapDefaultDisplayValue.ts index 8f12d40d13..a661f21818 100644 --- a/packages/nocodb/src/lib/meta/helpers/mapDefaultDisplayValue.ts +++ b/packages/nocodb/src/lib/meta/helpers/mapDefaultDisplayValue.ts @@ -4,31 +4,27 @@ export default function mapDefaultDisplayValue( columnsArr: Array ): void | T { if (!columnsArr.some((column) => column.pv)) { - let len = columnsArr.length; - let pkIndex = -1; - - while (len--) { - if (columnsArr[len].pk) { - pkIndex = len; - break; - } - } + const pkIndex = columnsArr.findIndex((column) => column.pk); // if PK is at the end of table if (pkIndex === columnsArr.length - 1) { if (pkIndex > 0) { columnsArr[pkIndex - 1].pv = true; return columnsArr[pkIndex - 1]; + } else if (columnsArr.length > 0) { + columnsArr[0].pv = true; + return columnsArr[0]; } - } - // pk is not at the end of table - else if (pkIndex > -1) { + // pk is not at the end of table + } else if (pkIndex > -1) { columnsArr[pkIndex + 1].pv = true; return columnsArr[pkIndex + 1]; - } - // no pk at all - else { - // todo: + // no pk at all + } else { + if (columnsArr.length > 0) { + columnsArr[0].pv = true; + return columnsArr[0]; + } } } } diff --git a/packages/nocodb/src/lib/models/Audit.ts b/packages/nocodb/src/lib/models/Audit.ts index ae2c9f2f6a..9ea8e589d2 100644 --- a/packages/nocodb/src/lib/models/Audit.ts +++ b/packages/nocodb/src/lib/models/Audit.ts @@ -2,6 +2,7 @@ import { AuditOperationTypes, AuditType } from 'nocodb-sdk'; import { MetaTable } from '../utils/globals'; import Noco from '../Noco'; import Model from './Model'; +import { extractProps } from '../meta/helpers/extractProps'; export default class Audit implements AuditType { id?: string; @@ -44,28 +45,32 @@ export default class Audit implements AuditType { forceAwait: process.env['TEST'] === 'true', } ) { + if (process.env.NC_DISABLE_AUDIT === 'true') { + return; + } const insertAudit = async () => { - if (!audit.project_id && audit.fk_model_id) { - audit.project_id = ( - await Model.getByIdOrName({ id: audit.fk_model_id }, ncMeta) + const insertObj = extractProps(audit, [ + 'user', + 'ip', + 'base_id', + 'project_id', + 'row_id', + 'fk_model_id', + 'op_type', + 'op_sub_type', + 'status', + 'description', + 'details', + 'created_at', + 'updated_at', + ]); + if (!insertObj.project_id && insertObj.fk_model_id) { + insertObj.project_id = ( + await Model.getByIdOrName({ id: insertObj.fk_model_id }, ncMeta) ).project_id; } - return await ncMeta.metaInsert2(null, null, MetaTable.AUDIT, { - user: audit.user, - ip: audit.ip, - base_id: audit.base_id, - project_id: audit.project_id, - row_id: audit.row_id, - fk_model_id: audit.fk_model_id, - op_type: audit.op_type, - op_sub_type: audit.op_sub_type, - status: audit.status, - description: audit.description, - details: audit.details, - created_at: audit.created_at, - updated_at: audit.updated_at, - }); + return await ncMeta.metaInsert2(null, null, MetaTable.AUDIT, insertObj); }; if (forceAwait) { diff --git a/packages/nocodb/src/lib/models/BarcodeColumn.ts b/packages/nocodb/src/lib/models/BarcodeColumn.ts index 6f274f3f86..745de9200c 100644 --- a/packages/nocodb/src/lib/models/BarcodeColumn.ts +++ b/packages/nocodb/src/lib/models/BarcodeColumn.ts @@ -14,16 +14,17 @@ export default class BarcodeColumn { } public static async insert( - data: Partial, + barcodeColumn: Partial, ncMeta = Noco.ncMeta ) { - await ncMeta.metaInsert2(null, null, MetaTable.COL_BARCODE, { - fk_column_id: data.fk_column_id, - fk_barcode_value_column_id: data.fk_barcode_value_column_id, - barcode_format: data.barcode_format, - }); + const insertObj = extractProps(barcodeColumn, [ + 'fk_column_id', + 'fk_barcode_value_column_id', + 'barcode_format', + ]); + await ncMeta.metaInsert2(null, null, MetaTable.COL_BARCODE, insertObj); - return this.read(data.fk_column_id, ncMeta); + return this.read(barcodeColumn.fk_column_id, ncMeta); } public static async read(columnId: string, ncMeta = Noco.ncMeta) { let column = diff --git a/packages/nocodb/src/lib/models/Column.ts b/packages/nocodb/src/lib/models/Column.ts index 6d7b2d5345..154e0a4098 100644 --- a/packages/nocodb/src/lib/models/Column.ts +++ b/packages/nocodb/src/lib/models/Column.ts @@ -25,6 +25,7 @@ import addFormulaErrorIfMissingColumn from '../meta/helpers/addFormulaErrorIfMis import { NcError } from '../meta/helpers/catchError'; import QrCodeColumn from './QrCodeColumn'; import BarcodeColumn from './BarcodeColumn'; +import { extractProps } from '../meta/helpers/extractProps'; export default class Column implements ColumnType { public fk_model_id: string; @@ -85,41 +86,50 @@ export default class Column implements ColumnType { ) { if (!column.fk_model_id) NcError.badRequest('Missing model id'); - const insertObj: any = { - id: column?.id, - fk_model_id: column.fk_model_id, - column_name: column.column_name || column.cn, - title: column.title || column._cn, - uidt: column.uidt, - dt: column.dt, - np: column.np, - ns: column.ns, - clen: column.clen, - cop: column.cop, - pk: column.pk, - rqd: column.rqd, - un: column.un, - ct: column.ct, - ai: column.ai, - unique: column.unique, - cdf: column.cdf, - cc: column.cc, - csn: column.csn, - dtx: column.dtx, - dtxp: column.dtxp, - dtxs: column.dtxs, - au: column.au, - pv: column.pv, - order: column.order, - project_id: column.project_id, - base_id: column.base_id, - system: column.system, - meta: - column.meta && typeof column.meta === 'object' - ? JSON.stringify(column.meta) - : column.meta, - }; + // TODO: fix type + const insertObj = extractProps(column as any, [ + 'id', + 'fk_model_id', + 'column_name', + 'title', + 'uidt', + 'dt', + 'np', + 'ns', + 'clen', + 'cop', + 'pk', + 'rqd', + 'un', + 'ct', + 'ai', + 'unique', + 'cdf', + 'cc', + 'csn', + 'dtx', + 'dtxp', + 'dtxs', + 'au', + 'pv', + 'order', + 'project_id', + 'base_id', + 'system', + 'meta', + ]); + + if (!insertObj.column_name) { + insertObj.column_name = column.cn; + } + + if (!insertObj.title) { + insertObj.title = column._cn; + } + if (insertObj.meta && typeof insertObj.meta === 'object') { + insertObj.meta = JSON.stringify(insertObj.meta); + } if (column.validate) { if (typeof column.validate === 'string') insertObj.validate = column.validate; @@ -873,7 +883,11 @@ export default class Column implements ColumnType { ); } - static async update(colId: string, column: any, ncMeta = Noco.ncMeta) { + static async update( + colId: string, + column: Partial, + ncMeta = Noco.ncMeta + ) { const oldCol = await Column.get({ colId }, ncMeta); switch (oldCol.uidt) { @@ -965,33 +979,34 @@ export default class Column implements ColumnType { break; } } - const updateObj = { - column_name: column.column_name, - title: column.title, - uidt: column.uidt, - dt: column.dt, - np: column.np, - ns: column.ns, - clen: column.clen, - cop: column.cop, - pk: column.pk, - rqd: column.rqd, - un: column.un, - ct: column.ct, - ai: column.ai, - unique: column.unique, - cdf: column.cdf, - cc: column.cc, - csn: column.csn, - dtx: column.dtx, - dtxp: column.dtxp, - dtxs: column.dtxs, - au: column.au, - pv: column.pv, - system: column.system, - validate: null, - meta: column.meta, - }; + + const updateObj = extractProps(column, [ + 'column_name', + 'title', + 'uidt', + 'dt', + 'np', + 'ns', + 'clen', + 'cop', + 'pk', + 'rqd', + 'un', + 'ct', + 'ai', + 'unique', + 'cdf', + 'cc', + 'csn', + 'dtx', + 'dtxp', + 'dtxs', + 'au', + 'pv', + 'system', + 'validate', + 'meta', + ]); if (column.validate) { if (typeof column.validate === 'string') diff --git a/packages/nocodb/src/lib/models/Filter.ts b/packages/nocodb/src/lib/models/Filter.ts index 619b6a741d..1e6a0dfaee 100644 --- a/packages/nocodb/src/lib/models/Filter.ts +++ b/packages/nocodb/src/lib/models/Filter.ts @@ -77,29 +77,30 @@ export default class Filter { } public static async insert( - filter: Partial, + filter: Partial & { order?: number }, ncMeta = Noco.ncMeta ) { - const insertObj = { - id: filter.id, - fk_view_id: filter.fk_view_id, - fk_hook_id: filter.fk_hook_id, - fk_column_id: filter.fk_column_id, - comparison_op: filter.comparison_op, - value: filter.value, - fk_parent_id: filter.fk_parent_id, - - is_group: filter.is_group, - logical_op: filter.logical_op, - - project_id: filter.project_id, - base_id: filter.base_id, - order: await ncMeta.metaGetNextOrder(MetaTable.FILTER_EXP, { - [filter.fk_hook_id ? 'fk_hook_id' : 'fk_view_id']: filter.fk_hook_id - ? filter.fk_hook_id - : filter.fk_view_id, - }), - }; + const insertObj = extractProps(filter, [ + 'id', + 'fk_view_id', + 'fk_hook_id', + 'fk_column_id', + 'comparison_op', + 'value', + 'fk_parent_id', + 'is_group', + 'logical_op', + 'project_id', + 'base_id', + 'order', + ]); + + insertObj.order = await ncMeta.metaGetNextOrder(MetaTable.FILTER_EXP, { + [filter.fk_hook_id ? 'fk_hook_id' : 'fk_view_id']: filter.fk_hook_id + ? filter.fk_hook_id + : filter.fk_view_id, + }); + if (!(filter.project_id && filter.base_id)) { let model: { project_id?: string; base_id?: string }; if (filter.fk_view_id) { diff --git a/packages/nocodb/src/lib/models/FormView.ts b/packages/nocodb/src/lib/models/FormView.ts index 49ee5c4da2..ad155f4434 100644 --- a/packages/nocodb/src/lib/models/FormView.ts +++ b/packages/nocodb/src/lib/models/FormView.ts @@ -5,6 +5,7 @@ import { deserializeJSON, serializeJSON } from '../utils/serialize'; import FormViewColumn from './FormViewColumn'; import View from './View'; import NocoCache from '../cache/NocoCache'; +import { extractProps } from '../meta/helpers/extractProps'; export default class FormView implements FormType { show: boolean; @@ -53,22 +54,25 @@ export default class FormView implements FormType { } static async insert(view: Partial, ncMeta = Noco.ncMeta) { - const insertObj = { - fk_view_id: view.fk_view_id, - project_id: view.project_id, - base_id: view.base_id, - heading: view.heading, - subheading: view.subheading, - success_msg: view.success_msg, - redirect_url: view.redirect_url, - redirect_after_secs: view.redirect_after_secs, - email: view.email, - banner_image_url: view.banner_image_url, - logo_url: view.logo_url, - submit_another_form: view.submit_another_form, - show_blank_form: view.show_blank_form, - meta: serializeJSON(view.meta), - }; + const insertObj = extractProps(view, [ + 'fk_view_id', + 'project_id', + 'base_id', + 'heading', + 'subheading', + 'success_msg', + 'redirect_url', + 'redirect_after_secs', + 'email', + 'banner_image_url', + 'logo_url', + 'submit_another_form', + 'show_blank_form', + 'meta', + ]); + if (insertObj.meta) { + insertObj.meta = serializeJSON(insertObj.meta); + } if (!(view.project_id && view.base_id)) { const viewRef = await View.get(view.fk_view_id); insertObj.project_id = viewRef.project_id; @@ -86,44 +90,35 @@ export default class FormView implements FormType { ) { // get existing cache const key = `${CacheScope.FORM_VIEW}:${formId}`; - const o = await NocoCache.get(key, CacheGetType.TYPE_OBJECT); + let o = await NocoCache.get(key, CacheGetType.TYPE_OBJECT); + const updateObj = extractProps(body, [ + 'heading', + 'subheading', + 'success_msg', + 'redirect_url', + 'redirect_after_secs', + 'email', + 'banner_image_url', + 'logo_url', + 'submit_another_form', + 'show_blank_form', + 'meta', + ]); + if (o) { - o.heading = body.heading; - o.subheading = body.subheading; - o.success_msg = body.success_msg; - o.redirect_url = body.redirect_url; - o.redirect_after_secs = body.redirect_after_secs; - o.email = body.email; - o.banner_image_url = body.banner_image_url; - o.logo_url = body.logo_url; - o.submit_another_form = body.submit_another_form; - o.show_blank_form = body.show_blank_form; - o.meta = body.meta; + o = { ...o, ...updateObj }; // set cache await NocoCache.set(key, o); - o.meta = serializeJSON(body.meta); } + + if (updateObj.meta) { + updateObj.meta = serializeJSON(updateObj.meta); + } + // update meta - return await ncMeta.metaUpdate( - null, - null, - MetaTable.FORM_VIEW, - { - heading: body.heading, - subheading: body.subheading, - success_msg: body.success_msg, - redirect_url: body.redirect_url, - redirect_after_secs: body.redirect_after_secs, - email: body.email, - banner_image_url: body.banner_image_url, - logo_url: body.logo_url, - submit_another_form: body.submit_another_form, - show_blank_form: body.show_blank_form, - }, - { - fk_view_id: formId, - } - ); + return await ncMeta.metaUpdate(null, null, MetaTable.FORM_VIEW, updateObj, { + fk_view_id: formId, + }); } async getColumns(ncMeta = Noco.ncMeta) { diff --git a/packages/nocodb/src/lib/models/FormViewColumn.ts b/packages/nocodb/src/lib/models/FormViewColumn.ts index 8cd3fb3efe..577d5ad5ca 100644 --- a/packages/nocodb/src/lib/models/FormViewColumn.ts +++ b/packages/nocodb/src/lib/models/FormViewColumn.ts @@ -55,27 +55,32 @@ export default class FormViewColumn implements FormColumnType { } static async insert(column: Partial, ncMeta = Noco.ncMeta) { - const insertObj: Partial = { - fk_view_id: column.fk_view_id, - fk_column_id: column.fk_column_id, - order: await ncMeta.metaGetNextOrder(MetaTable.FORM_VIEW_COLUMNS, { - fk_view_id: column.fk_view_id, - }), - show: column.show, - project_id: column.project_id, - base_id: column.base_id, - label: column.label, - help: column.help, - description: column.description, - required: column.required, - }; - - if (column.meta) { - insertObj.meta = serializeJSON(column.meta); + const insertObj = extractProps(column, [ + 'fk_view_id', + 'fk_column_id', + 'show', + 'project_id', + 'base_id', + 'label', + 'help', + 'description', + 'required', + 'meta', + ]); + + insertObj.order = await ncMeta.metaGetNextOrder( + MetaTable.FORM_VIEW_COLUMNS, + { + fk_view_id: insertObj.fk_view_id, + } + ); + + if (insertObj.meta) { + insertObj.meta = serializeJSON(insertObj.meta); } - if (!(column.project_id && column.base_id)) { - const viewRef = await View.get(column.fk_view_id, ncMeta); + if (!(insertObj.project_id && insertObj.base_id)) { + const viewRef = await View.get(insertObj.fk_view_id, ncMeta); insertObj.project_id = viewRef.project_id; insertObj.base_id = viewRef.base_id; } @@ -150,7 +155,7 @@ export default class FormViewColumn implements FormColumnType { body: Partial, ncMeta = Noco.ncMeta ) { - const insertObj = extractProps(body, [ + const updateObj = extractProps(body, [ 'label', 'help', 'description', @@ -164,13 +169,13 @@ export default class FormViewColumn implements FormColumnType { const key = `${CacheScope.FORM_VIEW_COLUMN}:${columnId}`; const o = await NocoCache.get(key, CacheGetType.TYPE_OBJECT); if (o) { - Object.assign(o, insertObj); + Object.assign(o, updateObj); // set cache await NocoCache.set(key, o); } - if (insertObj.meta) { - insertObj.meta = serializeJSON(insertObj.meta); + if (updateObj.meta) { + updateObj.meta = serializeJSON(updateObj.meta); } // update meta @@ -178,7 +183,7 @@ export default class FormViewColumn implements FormColumnType { null, null, MetaTable.FORM_VIEW_COLUMNS, - insertObj, + updateObj, columnId ); } diff --git a/packages/nocodb/src/lib/models/FormulaColumn.ts b/packages/nocodb/src/lib/models/FormulaColumn.ts index 106b78934c..90e4f22c61 100644 --- a/packages/nocodb/src/lib/models/FormulaColumn.ts +++ b/packages/nocodb/src/lib/models/FormulaColumn.ts @@ -14,17 +14,18 @@ export default class FormulaColumn { } public static async insert( - data: Partial, + formulaColumn: Partial, ncMeta = Noco.ncMeta ) { - await ncMeta.metaInsert2(null, null, MetaTable.COL_FORMULA, { - fk_column_id: data.fk_column_id, - formula_raw: data.formula_raw, - formula: data.formula, - error: data.error, - }); + const insertObj = extractProps(formulaColumn, [ + 'fk_column_id', + 'formula_raw', + 'formula', + 'error', + ]); + await ncMeta.metaInsert2(null, null, MetaTable.COL_FORMULA, insertObj); - return this.read(data.fk_column_id, ncMeta); + return this.read(formulaColumn.fk_column_id, ncMeta); } public static async read(columnId: string, ncMeta = Noco.ncMeta) { let column = diff --git a/packages/nocodb/src/lib/models/GalleryView.ts b/packages/nocodb/src/lib/models/GalleryView.ts index 9c76f1de8e..2cf2f6ce8f 100644 --- a/packages/nocodb/src/lib/models/GalleryView.ts +++ b/packages/nocodb/src/lib/models/GalleryView.ts @@ -3,6 +3,7 @@ import { CacheGetType, CacheScope, MetaTable } from '../utils/globals'; import { GalleryColumnType, GalleryType, UITypes } from 'nocodb-sdk'; import View from './View'; import NocoCache from '../cache/NocoCache'; +import { extractProps } from '../meta/helpers/extractProps'; export default class GalleryView implements GalleryType { fk_view_id?: string; @@ -51,21 +52,23 @@ export default class GalleryView implements GalleryType { .then((v) => v?.getModel(ncMeta)) .then((m) => m.getColumns(ncMeta)); - const insertObj = { - project_id: view.project_id, - base_id: view.base_id, - fk_view_id: view.fk_view_id, - fk_cover_image_col_id: - view?.fk_cover_image_col_id || - columns?.find((c) => c.uidt === UITypes.Attachment)?.id, - next_enabled: view.next_enabled, - prev_enabled: view.prev_enabled, - cover_image_idx: view.cover_image_idx, - cover_image: view.cover_image, - restrict_types: view.restrict_types, - restrict_size: view.restrict_size, - restrict_number: view.restrict_number, - }; + const insertObj = extractProps(view, [ + 'project_id', + 'base_id', + 'fk_view_id', + 'next_enabled', + 'prev_enabled', + 'cover_image_idx', + 'cover_image', + 'restrict_types', + 'restrict_size', + 'restrict_number', + ]); + + insertObj.fk_cover_image_col_id = + view?.fk_cover_image_col_id || + columns?.find((c) => c.uidt === UITypes.Attachment)?.id; + if (!(view.project_id && view.base_id)) { const viewRef = await View.get(view.fk_view_id); insertObj.project_id = viewRef.project_id; @@ -90,16 +93,19 @@ export default class GalleryView implements GalleryType { ) { // get existing cache const key = `${CacheScope.GALLERY_VIEW}:${galleryId}`; - const o = await NocoCache.get(key, CacheGetType.TYPE_OBJECT); + let o = await NocoCache.get(key, CacheGetType.TYPE_OBJECT); + const updateObj = extractProps(body, [ + 'next_enabled', + 'prev_enabled', + 'cover_image_idx', + 'cover_image', + 'restrict_types', + 'restrict_size', + 'restrict_number', + 'fk_cover_image_col_id', + ]); if (o) { - o.next_enabled = body.next_enabled; - o.prev_enabled = body.prev_enabled; - o.cover_image_idx = body.cover_image_idx; - o.cover_image = body.cover_image; - o.restrict_types = body.restrict_types; - o.restrict_size = body.restrict_size; - o.restrict_number = body.restrict_number; - o.fk_cover_image_col_id = body.fk_cover_image_col_id; + o = { ...o, ...updateObj }; // set cache await NocoCache.set(key, o); } @@ -108,16 +114,7 @@ export default class GalleryView implements GalleryType { null, null, MetaTable.GALLERY_VIEW, - { - next_enabled: body.next_enabled, - prev_enabled: body.prev_enabled, - cover_image_idx: body.cover_image_idx, - cover_image: body.cover_image, - restrict_types: body.restrict_types, - restrict_size: body.restrict_size, - restrict_number: body.restrict_number, - fk_cover_image_col_id: body.fk_cover_image_col_id, - }, + updateObj, { fk_view_id: galleryId, } diff --git a/packages/nocodb/src/lib/models/GalleryViewColumn.ts b/packages/nocodb/src/lib/models/GalleryViewColumn.ts index 75ca96f4f1..3ccc1e73c3 100644 --- a/packages/nocodb/src/lib/models/GalleryViewColumn.ts +++ b/packages/nocodb/src/lib/models/GalleryViewColumn.ts @@ -2,6 +2,7 @@ import Noco from '../Noco'; import { CacheGetType, CacheScope, MetaTable } from '../utils/globals'; import View from './View'; import NocoCache from '../cache/NocoCache'; +import { extractProps } from '../meta/helpers/extractProps'; export default class GalleryViewColumn { id: string; @@ -43,16 +44,20 @@ export default class GalleryViewColumn { column: Partial, ncMeta = Noco.ncMeta ) { - const insertObj = { - fk_view_id: column.fk_view_id, - fk_column_id: column.fk_column_id, - order: await ncMeta.metaGetNextOrder(MetaTable.GALLERY_VIEW_COLUMNS, { + const insertObj = extractProps(column, [ + 'fk_view_id', + 'fk_column_id', + 'show', + 'project_id', + 'base_id', + ]); + + insertObj.order = await ncMeta.metaGetNextOrder( + MetaTable.GALLERY_VIEW_COLUMNS, + { fk_view_id: column.fk_view_id, - }), - show: column.show, - project_id: column.project_id, - base_id: column.base_id, - }; + } + ); if (!(column.project_id && column.base_id)) { const viewRef = await View.get(column.fk_view_id, ncMeta); diff --git a/packages/nocodb/src/lib/models/GridView.ts b/packages/nocodb/src/lib/models/GridView.ts index 40a98b0c9e..880254261a 100644 --- a/packages/nocodb/src/lib/models/GridView.ts +++ b/packages/nocodb/src/lib/models/GridView.ts @@ -3,6 +3,7 @@ import { CacheGetType, CacheScope, MetaTable } from '../utils/globals'; import GridViewColumn from './GridViewColumn'; import View from './View'; import NocoCache from '../cache/NocoCache'; +import { extractProps } from '../meta/helpers/extractProps'; export default class GridView { fk_view_id: string; @@ -40,14 +41,15 @@ export default class GridView { } static async insert(view: Partial, ncMeta = Noco.ncMeta) { - const insertObj = { - fk_view_id: view.fk_view_id, - project_id: view.project_id, - base_id: view.base_id, - row_height: view.row_height, - }; - if (!(view.project_id && view.base_id)) { - const viewRef = await View.get(view.fk_view_id, ncMeta); + const insertObj = extractProps(view, [ + 'fk_view_id', + 'project_id', + 'base_id', + 'row_height', + ]); + + if (!(insertObj.project_id && insertObj.base_id)) { + const viewRef = await View.get(insertObj.fk_view_id, ncMeta); insertObj.project_id = viewRef.project_id; insertObj.base_id = viewRef.base_id; } @@ -69,23 +71,16 @@ export default class GridView { ) { // get existing cache const key = `${CacheScope.GRID_VIEW}:${viewId}`; - const o = await NocoCache.get(key, CacheGetType.TYPE_OBJECT); + let o = await NocoCache.get(key, CacheGetType.TYPE_OBJECT); + const updateObj = extractProps(body, ['row_height']); if (o) { - o.row_height = body.row_height; + o = { ...o, ...updateObj }; // set cache await NocoCache.set(key, o); } // update meta - return await ncMeta.metaUpdate( - null, - null, - MetaTable.GRID_VIEW, - { - row_height: body.row_height, - }, - { - fk_view_id: viewId, - } - ); + return await ncMeta.metaUpdate(null, null, MetaTable.GRID_VIEW, updateObj, { + fk_view_id: viewId, + }); } } diff --git a/packages/nocodb/src/lib/models/GridViewColumn.ts b/packages/nocodb/src/lib/models/GridViewColumn.ts index e1d0398276..f3a3385a70 100644 --- a/packages/nocodb/src/lib/models/GridViewColumn.ts +++ b/packages/nocodb/src/lib/models/GridViewColumn.ts @@ -67,18 +67,19 @@ export default class GridViewColumn implements GridColumnType { } static async insert(column: Partial, ncMeta = Noco.ncMeta) { - const insertObj = { - fk_view_id: column.fk_view_id, - fk_column_id: column.fk_column_id, - order: - column?.order ?? - (await ncMeta.metaGetNextOrder(MetaTable.GRID_VIEW_COLUMNS, { - fk_view_id: column.fk_view_id, - })), - show: column.show, - project_id: column.project_id, - base_id: column.base_id, - }; + const insertObj = extractProps(column, [ + 'fk_view_id', + 'fk_column_id', + 'show', + 'project_id', + 'base_id', + ]); + + insertObj.order = + column?.order ?? + (await ncMeta.metaGetNextOrder(MetaTable.GRID_VIEW_COLUMNS, { + fk_view_id: column.fk_view_id, + })); if (!(column.project_id && column.base_id)) { const viewRef = await View.get(column.fk_view_id, ncMeta); diff --git a/packages/nocodb/src/lib/models/Hook.ts b/packages/nocodb/src/lib/models/Hook.ts index d87aa994bf..7c32d09bbd 100644 --- a/packages/nocodb/src/lib/models/Hook.ts +++ b/packages/nocodb/src/lib/models/Hook.ts @@ -10,6 +10,7 @@ import Model from './Model'; import NocoCache from '../cache/NocoCache'; import Filter from './Filter'; import HookFilter from './HookFilter'; +import { extractProps } from '../meta/helpers/extractProps'; export default class Hook implements HookType { id?: string; @@ -18,7 +19,7 @@ export default class Hook implements HookType { description?: string; env?: string; type?: string; - event?: 'After' | 'Before'; + event?: 'after' | 'before'; operation?: 'insert' | 'delete' | 'update'; async?: boolean; payload?: string; @@ -121,32 +122,42 @@ export default class Hook implements HookType { >, ncMeta = Noco.ncMeta ) { - const insertObj = { - fk_model_id: hook.fk_model_id, - title: hook.title, - description: hook.description, - env: hook.env, - type: hook.type, - event: hook.event?.toLowerCase?.(), - operation: hook.operation?.toLowerCase?.(), - async: hook.async, - payload: !!hook.payload, - url: hook.url, - headers: hook.headers, - condition: hook.condition, - notification: - hook.notification && typeof hook.notification === 'object' - ? JSON.stringify(hook.notification) - : hook.notification, - retries: hook.retries, - retry_interval: hook.retry_interval, - timeout: hook.timeout, - active: hook.active, - project_id: hook.project_id, - base_id: hook.base_id, - created_at: hook.created_at, - updated_at: hook.updated_at, - }; + const insertObj = extractProps(hook, [ + 'fk_model_id', + 'title', + 'description', + 'env', + 'type', + 'event', + 'operation', + 'async', + 'url', + 'headers', + 'notification', + 'retries', + 'retry_interval', + 'timeout', + 'active', + 'project_id', + 'base_id', + 'created_at', + 'updated_at', + ]); + + if (insertObj.event) { + insertObj.event = insertObj.event.toLowerCase() as 'after' | 'before'; + } + + if (insertObj.operation) { + insertObj.operation = insertObj.operation.toLowerCase() as + | 'insert' + | 'delete' + | 'update'; + } + + if (insertObj.notification && typeof insertObj.notification === 'object') { + insertObj.notification = JSON.stringify(insertObj.notification); + } if (!(hook.project_id && hook.base_id)) { const model = await Model.getByIdOrName({ id: hook.fk_model_id }, ncMeta); @@ -175,27 +186,39 @@ export default class Hook implements HookType { hook: Partial, ncMeta = Noco.ncMeta ) { - const updateObj = { - title: hook.title, - description: hook.description, - env: hook.env, - type: hook.type, - event: hook.event?.toLowerCase?.(), - operation: hook.operation?.toLowerCase?.(), - async: hook.async, - payload: !!hook.payload, - url: hook.url, - headers: hook.headers, - condition: !!hook.condition, - notification: - hook.notification && typeof hook.notification === 'object' - ? JSON.stringify(hook.notification) - : hook.notification, - retries: hook.retries, - retry_interval: hook.retry_interval, - timeout: hook.timeout, - active: hook.active, - }; + const updateObj = extractProps(hook, [ + 'title', + 'description', + 'env', + 'type', + 'event', + 'operation', + 'async', + 'payload', + 'url', + 'headers', + 'condition', + 'notification', + 'retries', + 'retry_interval', + 'timeout', + 'active', + ]); + + if (updateObj.event) { + updateObj.event = updateObj.event.toLowerCase() as 'after' | 'before'; + } + + if (updateObj.operation) { + updateObj.operation = updateObj.operation.toLowerCase() as + | 'insert' + | 'delete' + | 'update'; + } + + if (updateObj.notification && typeof updateObj.notification === 'object') { + updateObj.notification = JSON.stringify(updateObj.notification); + } // get existing cache const key = `${CacheScope.HOOK}:${hookId}`; @@ -203,6 +226,7 @@ export default class Hook implements HookType { if (o) { // update data o = { ...o, ...updateObj }; + // replace notification o.notification = updateObj.notification; // set cache await NocoCache.set(key, o); diff --git a/packages/nocodb/src/lib/models/HookFilter.ts b/packages/nocodb/src/lib/models/HookFilter.ts index 956df57f8c..81167954d2 100644 --- a/packages/nocodb/src/lib/models/HookFilter.ts +++ b/packages/nocodb/src/lib/models/HookFilter.ts @@ -10,6 +10,7 @@ import { import View from './View'; import { FilterType, UITypes } from 'nocodb-sdk'; import NocoCache from '../cache/NocoCache'; +import { extractProps } from '../meta/helpers/extractProps'; export default class Filter { id: string; @@ -48,20 +49,19 @@ export default class Filter { filter: Partial, ncMeta = Noco.ncMeta ) { - const insertObj = { - id: filter.id, - fk_view_id: filter.fk_view_id, - fk_column_id: filter.fk_column_id, - comparison_op: filter.comparison_op, - value: filter.value, - fk_parent_id: filter.fk_parent_id, - - is_group: filter.is_group, - logical_op: filter.logical_op, + const insertObj = extractProps(filter, [ + 'id', + 'fk_view_id', + 'fk_column_id', + 'comparison_op', + 'value', + 'fk_parent_id', + 'is_group', + 'logical_op', + 'project_id', + 'base_id', + ]); - project_id: filter.project_id, - base_id: filter.base_id, - }; if (!(filter.project_id && filter.base_id)) { const model = await Column.get({ colId: filter.fk_column_id }, ncMeta); insertObj.project_id = model.project_id; @@ -138,15 +138,14 @@ export default class Filter { } static async update(id, filter: Partial, ncMeta = Noco.ncMeta) { - const updateObj = { - fk_column_id: filter.fk_column_id, - comparison_op: filter.comparison_op, - value: filter.value, - fk_parent_id: filter.fk_parent_id, - - is_group: filter.is_group, - logical_op: filter.logical_op, - }; + const updateObj = extractProps(filter, [ + 'fk_column_id', + 'comparison_op', + 'value', + 'fk_parent_id', + 'is_group', + 'logical_op', + ]); // get existing cache const key = `${CacheScope.FILTER_EXP}:${id}`; let o = await NocoCache.get(key, CacheGetType.TYPE_OBJECT); diff --git a/packages/nocodb/src/lib/models/KanbanView.ts b/packages/nocodb/src/lib/models/KanbanView.ts index 52bd2bf088..6ac1b65d09 100644 --- a/packages/nocodb/src/lib/models/KanbanView.ts +++ b/packages/nocodb/src/lib/models/KanbanView.ts @@ -3,6 +3,7 @@ import { KanbanType, UITypes } from 'nocodb-sdk'; import { CacheGetType, CacheScope, MetaTable } from '../utils/globals'; import View from './View'; import NocoCache from '../cache/NocoCache'; +import { extractProps } from '../meta/helpers/extractProps'; export default class KanbanView implements KanbanType { fk_view_id: string; @@ -63,16 +64,17 @@ export default class KanbanView implements KanbanType { .then((v) => v?.getModel(ncMeta)) .then((m) => m.getColumns(ncMeta)); - const insertObj = { - project_id: view.project_id, - base_id: view.base_id, - fk_view_id: view.fk_view_id, - fk_grp_col_id: view.fk_grp_col_id, - fk_cover_image_col_id: - view?.fk_cover_image_col_id || - columns?.find((c) => c.uidt === UITypes.Attachment)?.id, - meta: view.meta, - }; + const insertObj = extractProps(view, [ + 'project_id', + 'base_id', + 'fk_view_id', + 'fk_grp_col_id', + 'meta', + ]); + + insertObj.fk_cover_image_col_id = + view?.fk_cover_image_col_id || + columns?.find((c) => c.uidt === UITypes.Attachment)?.id; if (!(view.project_id && view.base_id)) { const viewRef = await View.get(view.fk_view_id); @@ -99,13 +101,17 @@ export default class KanbanView implements KanbanType { // get existing cache const key = `${CacheScope.KANBAN_VIEW}:${kanbanId}`; let o = await NocoCache.get(key, CacheGetType.TYPE_OBJECT); - const updateObj = { - ...body, - meta: - typeof body.meta === 'string' - ? body.meta - : JSON.stringify(body.meta ?? {}), - }; + + const updateObj = extractProps(body, [ + 'title', + 'fk_cover_image_col_id', + 'meta', + ]); + + if (updateObj.meta && typeof updateObj.meta === 'object') { + updateObj.meta = JSON.stringify(updateObj.meta ?? {}); + } + if (o) { o = { ...o, ...updateObj }; // set cache diff --git a/packages/nocodb/src/lib/models/KanbanViewColumn.ts b/packages/nocodb/src/lib/models/KanbanViewColumn.ts index 87d58fe285..c86e5a2f14 100644 --- a/packages/nocodb/src/lib/models/KanbanViewColumn.ts +++ b/packages/nocodb/src/lib/models/KanbanViewColumn.ts @@ -2,6 +2,7 @@ import Noco from '../Noco'; import { CacheGetType, CacheScope, MetaTable } from '../utils/globals'; import View from './View'; import NocoCache from '../cache/NocoCache'; +import { extractProps } from '../meta/helpers/extractProps'; export default class KanbanViewColumn { id: string; @@ -40,16 +41,20 @@ export default class KanbanViewColumn { return view && new KanbanViewColumn(view); } static async insert(column: Partial, ncMeta = Noco.ncMeta) { - const insertObj = { - fk_view_id: column.fk_view_id, - fk_column_id: column.fk_column_id, - order: await ncMeta.metaGetNextOrder(MetaTable.KANBAN_VIEW_COLUMNS, { + const insertObj = extractProps(column, [ + 'fk_view_id', + 'fk_column_id', + 'show', + 'project_id', + 'base_id', + ]); + + insertObj.order = await ncMeta.metaGetNextOrder( + MetaTable.KANBAN_VIEW_COLUMNS, + { fk_view_id: column.fk_view_id, - }), - show: column.show, - project_id: column.project_id, - base_id: column.base_id, - }; + } + ); if (!(column.project_id && column.base_id)) { const viewRef = await View.get(column.fk_view_id, ncMeta); diff --git a/packages/nocodb/src/lib/models/LinkToAnotherRecordColumn.ts b/packages/nocodb/src/lib/models/LinkToAnotherRecordColumn.ts index 1234ed1e86..bbed654ea2 100644 --- a/packages/nocodb/src/lib/models/LinkToAnotherRecordColumn.ts +++ b/packages/nocodb/src/lib/models/LinkToAnotherRecordColumn.ts @@ -1,9 +1,9 @@ import Noco from '../Noco'; import Column from './Column'; import Model from './Model'; -// import NocoCache from '../cache/NocoCache'; import { CacheGetType, CacheScope, MetaTable } from '../utils/globals'; import NocoCache from '../cache/NocoCache'; +import { extractProps } from '../meta/helpers/extractProps'; export default class LinkToAnotherRecordColumn { fk_column_id?: string; @@ -89,27 +89,21 @@ export default class LinkToAnotherRecordColumn { data: Partial, ncMeta = Noco.ncMeta ) { - await ncMeta.metaInsert2(null, null, MetaTable.COL_RELATIONS, { - fk_column_id: data.fk_column_id, - - // ref_db_alias - type: data.type, - // db_type: - - fk_child_column_id: data.fk_child_column_id, - fk_parent_column_id: data.fk_parent_column_id, - - fk_mm_model_id: data.fk_mm_model_id, - fk_mm_child_column_id: data.fk_mm_child_column_id, - fk_mm_parent_column_id: data.fk_mm_parent_column_id, - - ur: data.ur, - dr: data.dr, - - fk_index_name: data.fk_index_name, - fk_related_model_id: data.fk_related_model_id, - virtual: data.virtual, - }); + const insertObj = extractProps(data, [ + 'fk_column_id', + 'type', + 'fk_child_column_id', + 'fk_parent_column_id', + 'fk_mm_model_id', + 'fk_mm_child_column_id', + 'fk_mm_parent_column_id', + 'ur', + 'dr', + 'fk_index_name', + 'fk_related_model_id', + 'virtual', + ]); + await ncMeta.metaInsert2(null, null, MetaTable.COL_RELATIONS, insertObj); return this.read(data.fk_column_id, ncMeta); } diff --git a/packages/nocodb/src/lib/models/LookupColumn.ts b/packages/nocodb/src/lib/models/LookupColumn.ts index 3737afc5bd..91c51e9a67 100644 --- a/packages/nocodb/src/lib/models/LookupColumn.ts +++ b/packages/nocodb/src/lib/models/LookupColumn.ts @@ -1,8 +1,8 @@ import Noco from '../Noco'; -// import NocoCache from '../cache/NocoCache'; import Column from './Column'; import { CacheGetType, CacheScope, MetaTable } from '../utils/globals'; import NocoCache from '../cache/NocoCache'; +import { extractProps } from '../meta/helpers/extractProps'; export default class LookupColumn { fk_relation_column_id: string; @@ -29,11 +29,13 @@ export default class LookupColumn { data: Partial, ncMeta = Noco.ncMeta ) { - await ncMeta.metaInsert2(null, null, MetaTable.COL_LOOKUP, { - fk_column_id: data.fk_column_id, - fk_relation_column_id: data.fk_relation_column_id, - fk_lookup_column_id: data.fk_lookup_column_id, - }); + const insertObj = extractProps(data, [ + 'fk_column_id', + 'fk_relation_column_id', + 'fk_lookup_column_id', + ]); + + await ncMeta.metaInsert2(null, null, MetaTable.COL_LOOKUP, insertObj); await NocoCache.appendToList( CacheScope.COL_LOOKUP, diff --git a/packages/nocodb/src/lib/models/Model.ts b/packages/nocodb/src/lib/models/Model.ts index c22c115d02..5c214c7d1e 100644 --- a/packages/nocodb/src/lib/models/Model.ts +++ b/packages/nocodb/src/lib/models/Model.ts @@ -22,6 +22,7 @@ import View from './View'; import { NcError } from '../meta/helpers/catchError'; import Audit from './Audit'; import { sanitize } from '../db/sql-data-mapper/lib/sql/helpers/sanitize'; +import { extractProps } from '../meta/helpers/extractProps'; export default class Model implements TableType { copy_enabled: boolean; @@ -103,25 +104,38 @@ export default class Model implements TableType { }, ncMeta = Noco.ncMeta ) { + const insertObj = extractProps(model, [ + 'table_name', + 'title', + 'mm', + 'order', + 'type', + 'created_at', + 'updated_at', + 'id', + ]); + + insertObj.mm = !!insertObj.mm; + + if (!insertObj.order) { + insertObj.order = await ncMeta.metaGetNextOrder( + MetaTable.FORM_VIEW_COLUMNS, + { + project_id: projectId, + base_id: baseId, + } + ); + } + + if (!insertObj.type) { + insertObj.type = ModelTypes.TABLE; + } + const { id } = await ncMeta.metaInsert2( projectId, baseId, MetaTable.MODELS, - { - table_name: model.table_name, - title: model.title, - mm: !!model.mm, - order: - model.order || - (await ncMeta.metaGetNextOrder(MetaTable.FORM_VIEW_COLUMNS, { - project_id: projectId, - base_id: baseId, - })), - type: model.type || ModelTypes.TABLE, - created_at: model.created_at, - updated_at: model.updated_at, - id: model.id, - } + insertObj ); await NocoCache.appendToList( @@ -561,14 +575,14 @@ export default class Model implements TableType { ncMeta = Noco.ncMeta ) { const model = await this.getWithInfo({ id: tableId }); - const currentPvCol = model.displayValue; const newPvCol = model.columns.find((c) => c.id === columnId); if (!newPvCol) NcError.badRequest('Column not found'); - if (currentPvCol) { + // drop existing primary column/s + for (const col of model.columns?.filter((c) => c.pv) || []) { // get existing cache - const key = `${CacheScope.COLUMN}:${currentPvCol.id}`; + const key = `${CacheScope.COLUMN}:${col.id}`; const o = await NocoCache.get(key, CacheGetType.TYPE_OBJECT); if (o) { o.pv = false; @@ -583,7 +597,7 @@ export default class Model implements TableType { { pv: false, }, - currentPvCol.id + col.id ); } diff --git a/packages/nocodb/src/lib/models/ModelRoleVisibility.ts b/packages/nocodb/src/lib/models/ModelRoleVisibility.ts index f6a6a1df2f..74f6515315 100644 --- a/packages/nocodb/src/lib/models/ModelRoleVisibility.ts +++ b/packages/nocodb/src/lib/models/ModelRoleVisibility.ts @@ -8,6 +8,7 @@ import { } from '../utils/globals'; import NocoCache from '../cache/NocoCache'; import View from './View'; +import { extractProps } from '../meta/helpers/extractProps'; export default class ModelRoleVisibility implements ModelRoleVisibilityType { id?: string; @@ -134,17 +135,17 @@ export default class ModelRoleVisibility implements ModelRoleVisibilityType { >, ncMeta = Noco.ncMeta ) { - const insertObj = { - role: body.role, - disabled: body.disabled, - fk_view_id: body.fk_view_id, - project_id: body.project_id, - base_id: body.base_id, - created_at: body.created_at, - updated_at: body.updated_at, - }; + const insertObj = extractProps(body, [ + 'role', + 'disabled', + 'fk_view_id', + 'project_id', + 'base_id', + 'created_at', + 'updated_at', + ]); - if (!(body.project_id && body.base_id)) { + if (!(insertObj.project_id && insertObj.base_id)) { const view = await View.get(body.fk_view_id, ncMeta); insertObj.project_id = view.project_id; insertObj.base_id = view.base_id; diff --git a/packages/nocodb/src/lib/models/Plugin.ts b/packages/nocodb/src/lib/models/Plugin.ts index b5f2097568..711feb700e 100644 --- a/packages/nocodb/src/lib/models/Plugin.ts +++ b/packages/nocodb/src/lib/models/Plugin.ts @@ -2,6 +2,7 @@ import { PluginType } from 'nocodb-sdk'; import { CacheGetType, CacheScope, MetaTable } from '../utils/globals'; import Noco from '../Noco'; import NocoCache from '../cache/NocoCache'; +import { extractProps } from '../meta/helpers/extractProps'; export default class Plugin implements PluginType { id?: string; @@ -56,13 +57,12 @@ export default class Plugin implements PluginType { } public static async update(pluginId: string, plugin: Partial) { - const updateObj = { - input: - plugin.input && typeof plugin.input === 'object' - ? JSON.stringify(plugin.input) - : plugin.input, - active: plugin.active, - }; + const updateObj = extractProps(plugin, ['input', 'active']); + + if (updateObj.input && typeof updateObj.input === 'object') { + updateObj.input = JSON.stringify(updateObj.input); + } + // get existing cache const key = `${CacheScope.PLUGIN}:${pluginId}`; let o = await NocoCache.get(key, CacheGetType.TYPE_OBJECT); diff --git a/packages/nocodb/src/lib/models/Project.ts b/packages/nocodb/src/lib/models/Project.ts index cf1cdf5a4d..ec69d51b88 100644 --- a/packages/nocodb/src/lib/models/Project.ts +++ b/packages/nocodb/src/lib/models/Project.ts @@ -36,25 +36,27 @@ export default class Project implements ProjectType { } public static async createProject( - projectBody: ProjectType & { + project: ProjectType & { created_at?; updated_at?; }, ncMeta = Noco.ncMeta ): Promise { + const insertObj = extractProps(project, [ + 'id', + 'title', + 'prefix', + 'description', + 'is_meta', + 'created_at', + 'updated_at', + ]); + const { id: projectId } = await ncMeta.metaInsert2( null, null, MetaTable.PROJECT, - { - id: projectBody?.id, - title: projectBody.title, - prefix: projectBody.prefix, - description: projectBody.description, - is_meta: projectBody.is_meta, - created_at: projectBody.created_at, - updated_at: projectBody.updated_at, - } + insertObj ); await NocoCache.appendToList( @@ -63,7 +65,7 @@ export default class Project implements ProjectType { `${CacheScope.PROJECT}:${projectId}` ); - for (const base of projectBody.bases) { + for (const base of project.bases) { await Base.createBase( { type: base.config?.client, diff --git a/packages/nocodb/src/lib/models/ProjectUser.ts b/packages/nocodb/src/lib/models/ProjectUser.ts index c4c7454a31..d62f5490e8 100644 --- a/packages/nocodb/src/lib/models/ProjectUser.ts +++ b/packages/nocodb/src/lib/models/ProjectUser.ts @@ -8,6 +8,7 @@ import { import Noco from '../Noco'; import NocoCache from '../cache/NocoCache'; import User from './User'; +import { extractProps } from '../meta/helpers/extractProps'; export default class ProjectUser { project_id: string; @@ -22,17 +23,19 @@ export default class ProjectUser { projectUser: Partial, ncMeta = Noco.ncMeta ) { + const insertObj = extractProps(projectUser, [ + 'fk_user_id', + 'project_id', + 'roles', + 'created_at', + 'updated_at', + ]); + const { project_id, fk_user_id } = await ncMeta.metaInsert2( null, null, MetaTable.PROJECT_USERS, - { - fk_user_id: projectUser.fk_user_id, - project_id: projectUser.project_id, - roles: projectUser.roles, - created_at: projectUser.created_at, - updated_at: projectUser.updated_at, - }, + insertObj, true ); diff --git a/packages/nocodb/src/lib/models/QrCodeColumn.ts b/packages/nocodb/src/lib/models/QrCodeColumn.ts index 0dc39f8d2d..9610b69f06 100644 --- a/packages/nocodb/src/lib/models/QrCodeColumn.ts +++ b/packages/nocodb/src/lib/models/QrCodeColumn.ts @@ -12,15 +12,17 @@ export default class QrCodeColumn { } public static async insert( - data: Partial, + qrCode: Partial, ncMeta = Noco.ncMeta ) { - await ncMeta.metaInsert2(null, null, MetaTable.COL_QRCODE, { - fk_column_id: data.fk_column_id, - fk_qr_value_column_id: data.fk_qr_value_column_id, - }); + const insertObj = extractProps(qrCode, [ + 'fk_column_id', + 'fk_qr_value_column_id', + ]); + + await ncMeta.metaInsert2(null, null, MetaTable.COL_QRCODE, insertObj); - return this.read(data.fk_column_id, ncMeta); + return this.read(qrCode.fk_column_id, ncMeta); } public static async read(columnId: string, ncMeta = Noco.ncMeta) { let column = diff --git a/packages/nocodb/src/lib/models/RollupColumn.ts b/packages/nocodb/src/lib/models/RollupColumn.ts index a66512300a..14fc0d3366 100644 --- a/packages/nocodb/src/lib/models/RollupColumn.ts +++ b/packages/nocodb/src/lib/models/RollupColumn.ts @@ -2,6 +2,7 @@ import Noco from '../Noco'; import Column from './Column'; import { CacheGetType, CacheScope, MetaTable } from '../utils/globals'; import NocoCache from '../cache/NocoCache'; +import { extractProps } from '../meta/helpers/extractProps'; export default class RollupColumn { fk_column_id; @@ -20,12 +21,13 @@ export default class RollupColumn { data: Partial, ncMeta = Noco.ncMeta ) { - await ncMeta.metaInsert2(null, null, MetaTable.COL_ROLLUP, { - fk_column_id: data.fk_column_id, - fk_relation_column_id: data.fk_relation_column_id, - fk_rollup_column_id: data.fk_rollup_column_id, - rollup_function: data.rollup_function, - }); + const insertObj = extractProps(data, [ + 'fk_column_id', + 'fk_relation_column_id', + 'fk_rollup_column_id', + 'rollup_function', + ]); + await ncMeta.metaInsert2(null, null, MetaTable.COL_ROLLUP, insertObj); await NocoCache.appendToList( CacheScope.COL_ROLLUP, diff --git a/packages/nocodb/src/lib/models/SelectOption.ts b/packages/nocodb/src/lib/models/SelectOption.ts index ac2af034c9..fa24d06e50 100644 --- a/packages/nocodb/src/lib/models/SelectOption.ts +++ b/packages/nocodb/src/lib/models/SelectOption.ts @@ -1,6 +1,7 @@ import Noco from '../Noco'; import NocoCache from '../cache/NocoCache'; import { CacheGetType, CacheScope, MetaTable } from '../utils/globals'; +import { extractProps } from '../meta/helpers/extractProps'; export default class SelectOption { title: string; @@ -16,11 +17,19 @@ export default class SelectOption { data: Partial, ncMeta = Noco.ncMeta ) { + const insertObj = extractProps(data, [ + 'id', + 'title', + 'fk_column_id', + 'color', + 'order', + ]); + const { id } = await ncMeta.metaInsert2( null, null, MetaTable.COL_SELECT_OPTIONS, - data + insertObj ); await NocoCache.appendToList( diff --git a/packages/nocodb/src/lib/models/Sort.ts b/packages/nocodb/src/lib/models/Sort.ts index 355ca6a725..1d90324f52 100644 --- a/packages/nocodb/src/lib/models/Sort.ts +++ b/packages/nocodb/src/lib/models/Sort.ts @@ -9,6 +9,7 @@ import { } from '../utils/globals'; import NocoCache from '../cache/NocoCache'; import { SortType } from 'nocodb-sdk'; +import { extractProps } from '../meta/helpers/extractProps'; export default class Sort { id: string; @@ -35,11 +36,20 @@ export default class Sort { } public static async insert( - sortObj: Partial & { push_to_top?: boolean }, + sortObj: Partial & { push_to_top?: boolean; order?: number }, ncMeta = Noco.ncMeta ) { + const insertObj = extractProps(sortObj, [ + 'id', + 'fk_view_id', + 'fk_column_id', + 'direction', + 'project_id', + 'base_id', + ]); + // todo: implement a generic function - const order = sortObj.push_to_top + insertObj.order = sortObj.push_to_top ? 1 : (+( await ncMeta @@ -50,16 +60,6 @@ export default class Sort { }) .first() )?.order || 0) + 1; - - const insertObj = { - id: sortObj.id, - fk_view_id: sortObj.fk_view_id, - fk_column_id: sortObj.fk_column_id, - direction: sortObj.direction, - project_id: sortObj.project_id, - base_id: sortObj.base_id, - order, - }; if (!(sortObj.project_id && sortObj.base_id)) { const model = await Column.get({ colId: sortObj.fk_column_id }, ncMeta); insertObj.project_id = model.project_id; diff --git a/packages/nocodb/src/lib/models/SyncLogs.ts b/packages/nocodb/src/lib/models/SyncLogs.ts index 035debc75e..d10e814c56 100644 --- a/packages/nocodb/src/lib/models/SyncLogs.ts +++ b/packages/nocodb/src/lib/models/SyncLogs.ts @@ -1,5 +1,6 @@ import Noco from '../Noco'; import { MetaTable } from '../utils/globals'; +import { extractProps } from '../meta/helpers/extractProps'; export default class SyncLogs { id?: string; @@ -34,13 +35,13 @@ export default class SyncLogs { >, ncMeta = Noco.ncMeta ) { - const insertObj = { - project_id: syncLog?.project_id, - fk_sync_source_id: syncLog?.fk_sync_source_id, - time_taken: syncLog?.time_taken, - status: syncLog?.status, - status_details: syncLog?.status_details, - }; + const insertObj = extractProps(syncLog, [ + 'project_id', + 'fk_sync_source_id', + 'time_taken', + 'status', + 'status_details', + ]); const { id } = await ncMeta.metaInsert2( null, diff --git a/packages/nocodb/src/lib/models/SyncSource.ts b/packages/nocodb/src/lib/models/SyncSource.ts index 4f169fae12..25292a3576 100644 --- a/packages/nocodb/src/lib/models/SyncSource.ts +++ b/packages/nocodb/src/lib/models/SyncSource.ts @@ -73,15 +73,15 @@ export default class SyncSource { >, ncMeta = Noco.ncMeta ) { - const insertObj = { - id: syncSource?.id, - title: syncSource?.title, - type: syncSource?.type, - details: syncSource?.details, - project_id: syncSource?.project_id, - base_id: syncSource?.base_id, - fk_user_id: syncSource?.fk_user_id, - }; + const insertObj = extractProps(syncSource, [ + 'id', + 'title', + 'type', + 'details', + 'project_id', + 'base_id', + 'fk_user_id', + ]); if (insertObj.details && typeof insertObj.details === 'object') { insertObj.details = JSON.stringify(insertObj.details); diff --git a/packages/nocodb/src/lib/models/View.ts b/packages/nocodb/src/lib/models/View.ts index 64a2df528c..b58fe429ac 100644 --- a/packages/nocodb/src/lib/models/View.ts +++ b/packages/nocodb/src/lib/models/View.ts @@ -244,25 +244,29 @@ export default class View implements ViewType { }, ncMeta = Noco.ncMeta ) { + const insertObj = extractProps(view, [ + 'id', + 'title', + 'is_default', + 'type', + 'fk_model_id', + 'project_id', + 'base_id', + 'created_at', + 'updated_at', + 'meta', + ]); + // get order value - const order = await ncMeta.metaGetNextOrder(MetaTable.VIEWS, { + insertObj.order = await ncMeta.metaGetNextOrder(MetaTable.VIEWS, { fk_model_id: view.fk_model_id, }); - const insertObj = { - id: view.id, - title: view.title, - show: true, - is_default: view.is_default, - order, - type: view.type, - fk_model_id: view.fk_model_id, - project_id: view.project_id, - base_id: view.base_id, - created_at: view.created_at, - updated_at: view.updated_at, - meta: view.meta ?? {}, - }; + insertObj.show = true; + + if (!insertObj.meta) { + insertObj.meta = {}; + } insertObj.meta = stringifyMetaProp(insertObj); diff --git a/packages/nocodb/src/lib/utils/common/BaseApiBuilder.ts b/packages/nocodb/src/lib/utils/common/BaseApiBuilder.ts index 210eb61a32..69294bdfc3 100644 --- a/packages/nocodb/src/lib/utils/common/BaseApiBuilder.ts +++ b/packages/nocodb/src/lib/utils/common/BaseApiBuilder.ts @@ -187,7 +187,7 @@ export default abstract class BaseApiBuilder return this.connectionConfig?.meta?.dbAlias; } - public async getSqlClient(): Promise { + public async getSqlClient() { return NcConnectionMgr.getSqlClient({ dbAlias: this.dbAlias, env: this.config.env, diff --git a/packages/nocodb/src/lib/utils/common/NcConnectionMgr.ts b/packages/nocodb/src/lib/utils/common/NcConnectionMgr.ts index 9c9c4c55a0..ca7f4fe53d 100644 --- a/packages/nocodb/src/lib/utils/common/NcConnectionMgr.ts +++ b/packages/nocodb/src/lib/utils/common/NcConnectionMgr.ts @@ -149,7 +149,7 @@ export default class NcConnectionMgr { env: string; config: NcConfig; projectId: string; - }): Promise { + }) { const knex = this.get({ dbAlias, env, diff --git a/packages/nocodb/src/lib/utils/common/NcConnectionMgrv2.ts b/packages/nocodb/src/lib/utils/common/NcConnectionMgrv2.ts index 06386e3391..bb55673cf6 100644 --- a/packages/nocodb/src/lib/utils/common/NcConnectionMgrv2.ts +++ b/packages/nocodb/src/lib/utils/common/NcConnectionMgrv2.ts @@ -149,7 +149,7 @@ export default class NcConnectionMgrv2 { // return config?.envs?.[env]?.db?.find(db => db?.meta?.dbAlias === dbAlias); // } - public static async getSqlClient(base: Base, _knex = null): Promise { + public static async getSqlClient(base: Base, _knex = null) { const knex = _knex || this.get(base); return SqlClientFactory.create({ knex, diff --git a/packages/nocodb/src/lib/version-upgrader/NcUpgrader.ts b/packages/nocodb/src/lib/version-upgrader/NcUpgrader.ts index cd84032692..c125701a4c 100644 --- a/packages/nocodb/src/lib/version-upgrader/NcUpgrader.ts +++ b/packages/nocodb/src/lib/version-upgrader/NcUpgrader.ts @@ -43,8 +43,8 @@ export default class NcUpgrader { { name: '0100002', handler: ncFilterUpgrader }, { name: '0101002', handler: ncAttachmentUpgrader }, { name: '0104002', handler: ncAttachmentUpgrader_0104002 }, - { name: '0104003', handler: ncStickyColumnUpgrader }, { name: '0104004', handler: ncFilterUpgrader_0104004 }, + { name: '0105002', handler: ncStickyColumnUpgrader }, ]; if (!(await ctx.ncMeta.knexConnection?.schema?.hasTable?.('nc_store'))) { return; diff --git a/packages/nocodb/src/lib/version-upgrader/ncAttachmentUpgrader.ts b/packages/nocodb/src/lib/version-upgrader/ncAttachmentUpgrader.ts index a66cae4359..f5c1393b3a 100644 --- a/packages/nocodb/src/lib/version-upgrader/ncAttachmentUpgrader.ts +++ b/packages/nocodb/src/lib/version-upgrader/ncAttachmentUpgrader.ts @@ -6,6 +6,7 @@ import Model from '../models/Model'; import { XKnex } from '../db/sql-data-mapper/index'; import NcConnectionMgrv2 from '../utils/common/NcConnectionMgrv2'; import { BaseType, UITypes } from 'nocodb-sdk'; +import { throwTimeoutError } from './ncUpgradeErrors'; // before 0.103.0, an attachment object was like // [{ @@ -68,6 +69,12 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { : NcConnectionMgrv2.get(base); const models = await base.getModels(ncMeta); + // used in timeout error message + const timeoutErrorInfo = { + projectTitle: project.title, + connection: knex.client.config.connection, + }; + for (const model of models) { try { // if the table is missing in database, skip @@ -170,6 +177,9 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { } catch (e) { // ignore the error related to deleted project if (!isProjectDeleted) { + // throw the custom timeout error message if applicable + throwTimeoutError(e, timeoutErrorInfo); + // throw general error throw e; } } diff --git a/packages/nocodb/src/lib/version-upgrader/ncAttachmentUpgrader_0104002.ts b/packages/nocodb/src/lib/version-upgrader/ncAttachmentUpgrader_0104002.ts index 3531b296c9..cb47f72122 100644 --- a/packages/nocodb/src/lib/version-upgrader/ncAttachmentUpgrader_0104002.ts +++ b/packages/nocodb/src/lib/version-upgrader/ncAttachmentUpgrader_0104002.ts @@ -6,6 +6,7 @@ import Model from '../models/Model'; import { XKnex } from '../db/sql-data-mapper/index'; import NcConnectionMgrv2 from '../utils/common/NcConnectionMgrv2'; import { BaseType, UITypes } from 'nocodb-sdk'; +import { throwTimeoutError } from './ncUpgradeErrors'; // after 0101002 upgrader, the attachment object would become broken when // (1) switching views after updating a singleSelect field @@ -60,6 +61,12 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { : NcConnectionMgrv2.get(base); const models = await base.getModels(ncMeta); + // used in timeout error message + const timeoutErrorInfo = { + projectTitle: project.title, + connection: knex.client.config.connection, + }; + for (const model of models) { try { // if the table is missing in database, skip @@ -151,6 +158,9 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { } catch (e) { // ignore the error related to deleted project if (!isProjectDeleted) { + // throw the custom timeout error message if applicable + throwTimeoutError(e, timeoutErrorInfo); + // throw general error throw e; } } diff --git a/packages/nocodb/src/lib/version-upgrader/ncProjectUpgraderV2_0090000.ts b/packages/nocodb/src/lib/version-upgrader/ncProjectUpgraderV2_0090000.ts index 2f604b18df..4bd94c8574 100644 --- a/packages/nocodb/src/lib/version-upgrader/ncProjectUpgraderV2_0090000.ts +++ b/packages/nocodb/src/lib/version-upgrader/ncProjectUpgraderV2_0090000.ts @@ -1231,7 +1231,7 @@ async function migrateWebhooks(ctx: MigrateCtxV1, ncMeta: any) { env: string; tn: string; type: string; - event: 'After' | 'Before'; + event: 'after' | 'before'; operation: 'delete' | 'update' | 'insert'; async: boolean; payload: string; diff --git a/packages/nocodb/src/lib/version-upgrader/ncStickyColumnUpgrader.ts b/packages/nocodb/src/lib/version-upgrader/ncStickyColumnUpgrader.ts index 67b02ce842..1fa222cd17 100644 --- a/packages/nocodb/src/lib/version-upgrader/ncStickyColumnUpgrader.ts +++ b/packages/nocodb/src/lib/version-upgrader/ncStickyColumnUpgrader.ts @@ -38,6 +38,50 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { view_columns_meta.push(col_meta); } + // if no display value column is set + if (!view_columns_meta.some((column) => column.pv)) { + const pkIndex = view_columns_meta.findIndex((column) => column.pk); + + // if PK is at the end of table + if (pkIndex === view_columns_meta.length - 1) { + if (pkIndex > 0) { + await ncMeta.metaUpdate( + null, + null, + MetaTable.COLUMNS, + { pv: true }, + view_columns_meta[pkIndex - 1].id + ); + } else if (view_columns_meta.length > 0) { + await ncMeta.metaUpdate( + null, + null, + MetaTable.COLUMNS, + { pv: true }, + view_columns_meta[0].id + ); + } + // pk is not at the end of table + } else if (pkIndex > -1) { + await ncMeta.metaUpdate( + null, + null, + MetaTable.COLUMNS, + { pv: true }, + view_columns_meta[pkIndex + 1].id + ); + // no pk at all + } else if (view_columns_meta.length > 0) { + await ncMeta.metaUpdate( + null, + null, + MetaTable.COLUMNS, + { pv: true }, + view_columns_meta[0].id + ); + } + } + const primary_value_column_meta = view_columns_meta.find((col) => col.pv); if (primary_value_column_meta) { diff --git a/packages/nocodb/src/lib/version-upgrader/ncUpgradeErrors.ts b/packages/nocodb/src/lib/version-upgrader/ncUpgradeErrors.ts new file mode 100644 index 0000000000..3b9b7330ab --- /dev/null +++ b/packages/nocodb/src/lib/version-upgrader/ncUpgradeErrors.ts @@ -0,0 +1,27 @@ +export function throwTimeoutError(e, timeoutErrorInfo) { + if ( + [ + 'EHOSTDOWN', + 'ETIMEDOUT', + 'EHOSTUNREACH', + 'ENOTFOUND', + 'ECONNREFUSED', + ].includes(e.code) + ) { + let db = ''; + if (timeoutErrorInfo.connection.filename) { + // for sqlite + db = timeoutErrorInfo.connection.filename; + } else if ( + timeoutErrorInfo.connection.database && + timeoutErrorInfo.connection.host && + timeoutErrorInfo.connection.port + ) { + db = `${timeoutErrorInfo.connection.database} (${timeoutErrorInfo.connection.host}:${timeoutErrorInfo.connection.port})`; + } + throw new Error( + `Failed to connect the database ${db} for Project ${timeoutErrorInfo.projectTitle}. + Please fix the connection issue or remove the project before trying to upgrade.` + ); + } +} diff --git a/scripts/sdk/swagger.json b/scripts/sdk/swagger.json index a2690a160c..796123f9ff 100644 --- a/scripts/sdk/swagger.json +++ b/scripts/sdk/swagger.json @@ -9175,8 +9175,8 @@ "event": { "type": "string", "enum": [ - "After", - "Before" + "after", + "before" ] }, "operation": { diff --git a/tests/playwright/package-lock.json b/tests/playwright/package-lock.json index a335ff146c..ddf6fcfb54 100644 --- a/tests/playwright/package-lock.json +++ b/tests/playwright/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "body-parser": "^1.20.1", "express": "^4.18.2", - "nocodb-sdk": "^0.104.3", + "nocodb-sdk": "file:../../packages/nocodb-sdk", "xlsx": "^0.18.5" }, "devDependencies": { @@ -35,6 +35,28 @@ "promised-sqlite3": "^1.2.0" } }, + "../../packages/nocodb-sdk": { + "version": "0.105.2", + "license": "AGPL-3.0-or-later", + "dependencies": { + "axios": "^0.21.1", + "jsep": "^1.3.6" + }, + "devDependencies": { + "@typescript-eslint/eslint-plugin": "^4.0.1", + "@typescript-eslint/parser": "^4.0.1", + "cspell": "^4.1.0", + "eslint": "^7.8.0", + "eslint-config-prettier": "^6.11.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-functional": "^3.0.2", + "eslint-plugin-import": "^2.22.0", + "eslint-plugin-prettier": "^4.0.0", + "npm-run-all": "^4.1.5", + "prettier": "^2.1.1", + "typescript": "^4.0.2" + } + }, "node_modules/@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -2033,6 +2055,7 @@ "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true, "funding": [ { "type": "individual", @@ -2713,14 +2736,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsep": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.3.8.tgz", - "integrity": "sha512-qofGylTGgYj9gZFsHuyWAN4jr35eJ66qJCK4eKDnldohuUoQFbU3iZn2zjvEbd9wOAhP9Wx5DsAAduTyE1PSWQ==", - "engines": { - "node": ">= 10.16.0" - } - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -3174,21 +3189,8 @@ } }, "node_modules/nocodb-sdk": { - "version": "0.104.3", - "resolved": "https://registry.npmjs.org/nocodb-sdk/-/nocodb-sdk-0.104.3.tgz", - "integrity": "sha512-C6uIeexVz2aMWmabpaut3Y/sI8Myp2cRDyKZIjRXmMjSdV1F8BIRrPWVTLGSgHxe6YECFtl+eLR5ma70eJsqCw==", - "dependencies": { - "axios": "^0.21.1", - "jsep": "^1.3.6" - } - }, - "node_modules/nocodb-sdk/node_modules/axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "dependencies": { - "follow-redirects": "^1.14.0" - } + "resolved": "../../packages/nocodb-sdk", + "link": true }, "node_modules/node-pre-gyp": { "version": "0.11.0", @@ -6456,7 +6458,8 @@ "follow-redirects": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true }, "forwarded": { "version": "0.2.0", @@ -6922,11 +6925,6 @@ "esprima": "^4.0.0" } }, - "jsep": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.3.8.tgz", - "integrity": "sha512-qofGylTGgYj9gZFsHuyWAN4jr35eJ66qJCK4eKDnldohuUoQFbU3iZn2zjvEbd9wOAhP9Wx5DsAAduTyE1PSWQ==" - }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -7278,22 +7276,22 @@ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, "nocodb-sdk": { - "version": "0.104.3", - "resolved": "https://registry.npmjs.org/nocodb-sdk/-/nocodb-sdk-0.104.3.tgz", - "integrity": "sha512-C6uIeexVz2aMWmabpaut3Y/sI8Myp2cRDyKZIjRXmMjSdV1F8BIRrPWVTLGSgHxe6YECFtl+eLR5ma70eJsqCw==", + "version": "file:../../packages/nocodb-sdk", "requires": { + "@typescript-eslint/eslint-plugin": "^4.0.1", + "@typescript-eslint/parser": "^4.0.1", "axios": "^0.21.1", - "jsep": "^1.3.6" - }, - "dependencies": { - "axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "requires": { - "follow-redirects": "^1.14.0" - } - } + "cspell": "^4.1.0", + "eslint": "^7.8.0", + "eslint-config-prettier": "^6.11.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-functional": "^3.0.2", + "eslint-plugin-import": "^2.22.0", + "eslint-plugin-prettier": "^4.0.0", + "jsep": "^1.3.6", + "npm-run-all": "^4.1.5", + "prettier": "^2.1.1", + "typescript": "^4.0.2" } }, "node-pre-gyp": { diff --git a/tests/playwright/package.json b/tests/playwright/package.json index f719fa2767..2fddfa4331 100644 --- a/tests/playwright/package.json +++ b/tests/playwright/package.json @@ -45,7 +45,7 @@ "dependencies": { "body-parser": "^1.20.1", "express": "^4.18.2", - "nocodb-sdk": "^0.104.3", + "nocodb-sdk": "file:../../packages/nocodb-sdk", "xlsx": "^0.18.5" } } diff --git a/tests/playwright/tests/projectOperations.spec.ts b/tests/playwright/tests/projectOperations.spec.ts index 832daad183..19a572288e 100644 --- a/tests/playwright/tests/projectOperations.spec.ts +++ b/tests/playwright/tests/projectOperations.spec.ts @@ -19,15 +19,16 @@ test.describe('Project operations', () => { test('rename, delete', async () => { await dashboard.clickHome(); - await projectPage.createProject({ name: 'project-1' }); + await projectPage.createProject({ name: 'project-firstName', withoutPrefix: true }); await dashboard.clickHome(); await projectPage.renameProject({ - title: 'project-1', - newTitle: 'project-new', + title: 'project-firstName', + newTitle: 'project-rename', + withoutPrefix: true, }); await dashboard.clickHome(); - await projectPage.openProject({ title: 'project-new' }); + await projectPage.openProject({ title: 'project-rename', withoutPrefix: true }); await dashboard.clickHome(); - await projectPage.deleteProject({ title: 'project-new' }); + await projectPage.deleteProject({ title: 'project-rename', withoutPrefix: true }); }); });