diff --git a/README.md b/README.md index 5dfca4057e..bbac6c92a2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

- NocoDB
+
NocoDB

The Open Source Airtable Alternative

@@ -263,6 +263,7 @@ Access Dashboard using : [http://localhost:8080/dashboard](http://localhost:8080 - [Contributing](#contributing) - [Why are we building this?](#why-are-we-building-this) - [Our Mission](#our-mission) +- [License](#license) - [Contributors](#contributors) # Features @@ -323,6 +324,11 @@ Most internet businesses equip themselves with either spreadsheet or a database # Our Mission Our mission is to provide the most powerful no-code interface for databases which is open source to every single internet business in the world. This would not only democratise access to a powerful computing tool but also bring forth a billion+ people who will have radical tinkering-and-building abilities on internet. +# License +

+This project is licensed under AGPLv3.

+
+ # Contributors [//]: contributor-faces diff --git a/packages/nc-gui/assets/style.scss b/packages/nc-gui/assets/style.scss index f1d7e48405..c01000b6af 100644 --- a/packages/nc-gui/assets/style.scss +++ b/packages/nc-gui/assets/style.scss @@ -100,7 +100,7 @@ a { } .animated-bg-gradient { - background: linear-gradient(122deg, #6f3381, #81c7d4, #fedfe1, #9ee59e); + background: linear-gradient(122deg, #6f3381, #ec4899, #fedfe1, #4351e8); background-size: 800% 800%; -webkit-animation: gradient 4s ease infinite; @@ -168,6 +168,28 @@ a { transform: translate(-100%, 0); } +.slide-right-enter-active, +.slide-right-leave-active { + transition: all 400ms ease; +} + +.slide-right-enter-from, +.slide-right-leave-to { + transform: translate(100%, 0%); + opacity: 0; +} + +.slide-left-enter-active, +.slide-left-leave-active { + transition: all 400ms ease; +} + +.slide-left-enter-from, +.slide-left-leave-to { + transform: translate(-100%, 0%); + opacity: 0; +} + .glow-enter-active, .glow-leave-active { @apply transition-all duration-300 ease-in-out; diff --git a/packages/nc-gui/components/dashboard/TreeView.vue b/packages/nc-gui/components/dashboard/TreeView.vue index d8a0c5ae63..6bba577e05 100644 --- a/packages/nc-gui/components/dashboard/TreeView.vue +++ b/packages/nc-gui/components/dashboard/TreeView.vue @@ -14,6 +14,7 @@ import { useProject, useTable, useTabs, + useToggle, useUIPermission, watchEffect, } from '#imports' @@ -33,6 +34,8 @@ const { deleteTable } = useTable() const { isUIAllowed } = useUIPermission() +const [searchActive, toggleSearchActive] = useToggle() + const isLocked = inject('TreeViewIsLockedInj') let key = $ref(0) @@ -126,8 +129,6 @@ const contextMenuTarget = reactive<{ type?: 'table' | 'main'; value?: any }>({}) const setMenuContext = (type: 'table' | 'main', value?: any) => { contextMenuTarget.type = type contextMenuTarget.value = value - - // $e('c:table:create:navdraw:right-click') } const reloadTables = async () => { @@ -215,12 +216,26 @@ function openTableCreateDialog() {
-
- - {{ $t('objects.tables') }} - - - +
+ + + + + {{ $t('objects.tables') }} + + + + + + + + +
diff --git a/packages/nc-gui/components/general/NocoIcon.vue b/packages/nc-gui/components/general/NocoIcon.vue index b7d54dd9e9..8b2ae0a1bd 100644 --- a/packages/nc-gui/components/general/NocoIcon.vue +++ b/packages/nc-gui/components/general/NocoIcon.vue @@ -2,13 +2,21 @@ interface Props { width?: number height?: number + animate?: boolean } -const { width = 90, height = 90 } = defineProps() +const { width = 90, height = 90, animate = false } = defineProps() diff --git a/packages/nc-gui/pages/[projectType]/[projectId]/index.vue b/packages/nc-gui/pages/[projectType]/[projectId]/index.vue index a2781409d7..e92b11b5d0 100644 --- a/packages/nc-gui/pages/[projectType]/[projectId]/index.vue +++ b/packages/nc-gui/pages/[projectType]/[projectId]/index.vue @@ -186,7 +186,7 @@ onBeforeUnmount(reset) >
- +

{{ $t('title.resetPassword') }}

diff --git a/packages/nc-gui/pages/index/index/[projectId].vue b/packages/nc-gui/pages/index/index/[projectId].vue index d8d529348a..d57bfb1d7f 100644 --- a/packages/nc-gui/pages/index/index/[projectId].vue +++ b/packages/nc-gui/pages/index/index/[projectId].vue @@ -68,7 +68,7 @@ onMounted(async () => {
- +
{
- +
{
- +
- +

{{ $t('general.signIn') }}

diff --git a/packages/nc-gui/pages/signup/[[token]].vue b/packages/nc-gui/pages/signup/[[token]].vue index 52e6905ca4..918482b20e 100644 --- a/packages/nc-gui/pages/signup/[[token]].vue +++ b/packages/nc-gui/pages/signup/[[token]].vue @@ -85,10 +85,7 @@ function resetError() {
- +

{{ $t('general.signUp') }} diff --git a/scripts/cypress/integration/common/00_pre_configurations.js b/scripts/cypress/integration/common/00_pre_configurations.js index baff649a0d..a600f7e275 100644 --- a/scripts/cypress/integration/common/00_pre_configurations.js +++ b/scripts/cypress/integration/common/00_pre_configurations.js @@ -243,12 +243,7 @@ export const genTest = (apiType, dbType) => { // wait for tab to be rendered completely cy.wait(2000); - - cy.getSettled("button.ant-tabs-tab-remove") - .should("be.visible") - .click(); - cy.get("button.ant-tabs-tab-remove").should("not.exist"); - cy.wait(2000); + cy.closeTableTab(); // first instance of updating local storage information cy.saveLocalStorage(); diff --git a/scripts/cypress/integration/common/1b_table_column_operations.js b/scripts/cypress/integration/common/1b_table_column_operations.js index f1d53f0895..e01b1a97a4 100644 --- a/scripts/cypress/integration/common/1b_table_column_operations.js +++ b/scripts/cypress/integration/common/1b_table_column_operations.js @@ -75,9 +75,7 @@ export const genTest = (apiType, dbType) => { .find(".nc-column-edit") .click(); - // fix me! wait till the modal rendering (input highlight) is completed - // focus shifts back to the input field to select text after the dropdown is rendered - cy.wait(500); + cy.inputHighlightRenderWait(); // change column type and verify // cy.get(".nc-column-type-input").last().click(); diff --git a/scripts/cypress/integration/common/3c_lookup_column.js b/scripts/cypress/integration/common/3c_lookup_column.js index 7980380009..6f76e89c6f 100644 --- a/scripts/cypress/integration/common/3c_lookup_column.js +++ b/scripts/cypress/integration/common/3c_lookup_column.js @@ -11,18 +11,7 @@ export const genTest = (apiType, dbType) => { cy.get("label").contains(label).parents(".ant-row").click(); }; - // Run once before test- create project (rest/graphql) - // // before(() => { - // cy.fileHook(); - // mainPage.tabReset(); - // // open a table to work on views - // // - // - // // // close team & auth tab - // // cy.get('button.ant-tabs-tab-remove').should('exist').click(); - // - // cy.openTableTab("City", 25); // }); beforeEach(() => { @@ -60,9 +49,7 @@ export const genTest = (apiType, dbType) => { .contains("Lookup") .click(); - // fix me! wait till the modal rendering (input highlight) is completed - // focus shifts back to the input field to select text after the dropdown is rendered - cy.wait(500); + cy.inputHighlightRenderWait(); // Configure Child table & column names fetchParentFromLabel("Child table"); diff --git a/scripts/cypress/integration/common/3d_rollup_column.js b/scripts/cypress/integration/common/3d_rollup_column.js index 30d35e5ce9..28af98540d 100644 --- a/scripts/cypress/integration/common/3d_rollup_column.js +++ b/scripts/cypress/integration/common/3d_rollup_column.js @@ -11,17 +11,7 @@ export const genTest = (apiType, dbType) => { cy.get("label").contains(label).parents(".ant-row").click(); }; - // Run once before test- create project (rest/graphql) - // // before(() => { - // cy.fileHook(); - // mainPage.tabReset(); - // - // // // close team & auth tab - // // cy.get('button.ant-tabs-tab-remove').should('exist').click(); - // // open a table to work on views - // // - // cy.openTableTab("Country", 25); // }); beforeEach(() => { @@ -64,9 +54,7 @@ export const genTest = (apiType, dbType) => { .contains("Rollup") .click(); - // fix me! wait till the modal rendering (input highlight) is completed - // focus shifts back to the input field to select text after the dropdown is rendered - cy.wait(500); + cy.inputHighlightRenderWait(); // Configure Child table & column names fetchParentFromLabel("Child table"); diff --git a/scripts/cypress/integration/common/3e_duration_column.js b/scripts/cypress/integration/common/3e_duration_column.js index ce7691d5ca..8824b1eaf0 100644 --- a/scripts/cypress/integration/common/3e_duration_column.js +++ b/scripts/cypress/integration/common/3e_duration_column.js @@ -57,9 +57,7 @@ export const genTest = (apiType, dbType) => { .contains("Duration") .click(); - // fix me! wait till the modal rendering (input highlight) is completed - // focus shifts back to the input field to select text after the dropdown is rendered - cy.wait(500); + cy.inputHighlightRenderWait(); // Configure Duration format fetchParentFromLabel("Duration Format"); @@ -101,9 +99,7 @@ export const genTest = (apiType, dbType) => { .clear() .type(newName); - // fix me! wait till the modal rendering (input highlight) is completed - // focus shifts back to the input field to select text after the dropdown is rendered - cy.wait(500); + cy.inputHighlightRenderWait(); // Configure Duration format fetchParentFromLabel("Duration Format"); diff --git a/scripts/cypress/integration/common/3f_link_to_another_record.js b/scripts/cypress/integration/common/3f_link_to_another_record.js index 8e072ee185..7414773786 100644 --- a/scripts/cypress/integration/common/3f_link_to_another_record.js +++ b/scripts/cypress/integration/common/3f_link_to_another_record.js @@ -6,7 +6,7 @@ export const genTest = (apiType, dbType) => { if (!isTestSuiteActive(apiType, dbType)) return; // tbd: this needs a proper fix - let waitTime = 2000; + let waitTime = 0; let clear; describe(`${apiType.toUpperCase()} api - Link to another record`, () => { @@ -185,7 +185,6 @@ export const genTest = (apiType, dbType) => { // Click on `Add new row` button cy.get(".nc-add-new-row-btn:visible").should("exist"); cy.get(".nc-add-new-row-btn").click(); - cy.wait(waitTime); // Title cy.get(".nc-expand-col-Title") @@ -205,32 +204,26 @@ export const genTest = (apiType, dbType) => { .find(".nc-action-icon") .should("exist") .click({ force: true }); - cy.wait(waitTime); cy.wait("@waitForCardLoad"); cy.getActiveModal(".nc-modal-link-record") .find(".ant-card") .should("exist") .eq(0) .click(); - cy.wait(waitTime); // MM cy.get(".nc-expand-col-Sheet1.List").find(".ant-btn-primary").click(); - cy.wait(waitTime); cy.wait("@waitForCardLoad"); cy.getActiveModal(".nc-modal-link-record") .find(".ant-card") .should("exist") .eq(0) .click(); - cy.wait(waitTime); // HM cy.get(".nc-expand-col-Link2-1hm").find(".ant-btn-primary").click(); - cy.wait(waitTime); cy.wait("@waitForCardLoad"); cy.getActiveModal().find(".ant-card").should("exist").eq(0).click(); - cy.wait(waitTime); // Save row cy.getActiveDrawer(".nc-drawer-expanded-form") @@ -256,13 +249,11 @@ export const genTest = (apiType, dbType) => { .getCell("Sheet1", 2) .find(".nc-action-icon") .click({ force: true }); - cy.wait(waitTime); cy.getActiveModal(".nc-modal-link-record") .find(".ant-card") .should("exist") .eq(1) .click(); - cy.wait(waitTime); // MM mainPage @@ -270,13 +261,11 @@ export const genTest = (apiType, dbType) => { .find(".nc-action-icon") .last() .click({ force: true }); - cy.wait(waitTime); cy.getActiveModal(".nc-modal-link-record") .find(".ant-card") .should("exist") .eq(1) .click(); - cy.wait(waitTime); // HM mainPage @@ -284,13 +273,11 @@ export const genTest = (apiType, dbType) => { .find(".nc-action-icon") .last() .click({ force: true }); - cy.wait(waitTime); cy.getActiveModal(".nc-modal-link-record") .find(".ant-card") .should("exist") .eq(1) .click(); - cy.wait(waitTime); }); // Existing row, expand record @@ -300,49 +287,37 @@ export const genTest = (apiType, dbType) => { addRow(3, "2c"); - cy.wait(waitTime); cy.get(".nc-row-expand").eq(2).click({ force: true }); - cy.wait(waitTime); // wait for page render to complete cy.get('button:contains("Save row"):visible').should("exist"); // BT - cy.wait(waitTime); cy.get(".nc-expand-col-Sheet1") .find(".nc-action-icon") .should("exist") .click({ force: true }); - cy.wait(waitTime); - // cy.wait("@waitForCardLoad"); cy.getActiveModal(".nc-modal-link-record") .find(".ant-card") .should("exist") .eq(2) .click(); - cy.wait(waitTime); // MM cy.get(".nc-expand-col-Sheet1.List").find(".ant-btn-primary").click(); - cy.wait(waitTime); - // cy.wait("@waitForCardLoad"); cy.getActiveModal(".nc-modal-link-record") .find(".ant-card") .should("exist") .eq(2) .click(); - cy.wait(waitTime); // HM cy.get(".nc-expand-col-Link2-1hm").find(".ant-btn-primary").click(); - cy.wait(waitTime); - // cy.wait("@waitForCardLoad"); cy.getActiveModal(".nc-modal-link-record") .find(".ant-card") .should("exist") .eq(2) .click(); - cy.wait(waitTime); cy.getActiveDrawer(".nc-drawer-expanded-form") .find("button") diff --git a/scripts/cypress/integration/common/5a_user_role.js b/scripts/cypress/integration/common/5a_user_role.js index 85d0a48b8f..336fc0a28a 100644 --- a/scripts/cypress/integration/common/5a_user_role.js +++ b/scripts/cypress/integration/common/5a_user_role.js @@ -145,14 +145,7 @@ export const genTest = (apiType, dbType) => { } if (roleType === "creator") { - // kludge: wait for page load to finish - // close team & auth tab - // cy.wait(500); - // cy.get("button.ant-tabs-tab-remove").should("exist").click(); - cy.getSettled("button.ant-tabs-tab-remove") - .should("be.visible") - .click(); - cy.wait(2000); + cy.closeTableTab(); } cy.saveLocalStorage(); diff --git a/scripts/cypress/integration/common/9a_QuickTest.js b/scripts/cypress/integration/common/9a_QuickTest.js index 6487b4c297..97af0e9666 100644 --- a/scripts/cypress/integration/common/9a_QuickTest.js +++ b/scripts/cypress/integration/common/9a_QuickTest.js @@ -113,9 +113,7 @@ export const genTest = (apiType, dbType, testMode) => { // kludge: wait for page load to finish cy.wait(2000); - // close team & auth tab - cy.get("button.ant-tabs-tab-remove").should("exist").click(); - cy.wait(2000); + cy.closeTableTab(); } else { cy.restoreLocalStorage(); } diff --git a/scripts/cypress/support/commands.js b/scripts/cypress/support/commands.js index 2c32a5d676..a1734a933a 100644 --- a/scripts/cypress/support/commands.js +++ b/scripts/cypress/support/commands.js @@ -189,17 +189,24 @@ Cypress.Commands.add("openTableTab", (tn, rc) => { Cypress.Commands.add("closeTableTab", (tn) => { cy.task("log", `[closeTableTab] ${tn}`); - cy.get(".ant-tabs-tab-btn") - .contains(tn) - .should("exist") - .parent() - .parent() - .parent() - .find("button") - .click(); + if (tn) { + // request to close specific tab + cy.get(".ant-tabs-tab-btn") + .contains(tn) + .should("exist") + .parent() + .parent() + .parent() + .find("button") + .click(); + } else { + // lone tab active; close it + cy.getSettled("button.ant-tabs-tab-remove").should("be.visible").click(); + cy.get("button.ant-tabs-tab-remove").should("not.exist"); + } // subsequent tab open commands will fail if tab is not closed completely - cy.wait(2000) + cy.wait(2000); }); Cypress.Commands.add("openOrCreateGqlProject", (_args) => { @@ -403,6 +410,12 @@ Cypress.Commands.add("toastWait", (msg) => { ); }); +Cypress.Commands.add("inputHighlightRenderWait", (selector) => { + // fix me! wait till the modal rendering (input highlight) is completed + // focus shifts back to the input field to select text after the dropdown is rendered + cy.wait(500); +}); + // vn: view name // rc: expected row count. validate row count if rc!=0 Cypress.Commands.add("openViewsTab", (vn, rc) => { diff --git a/scripts/cypress/support/page_objects/mainPage.js b/scripts/cypress/support/page_objects/mainPage.js index 0d0eef2833..ab4f9f0692 100644 --- a/scripts/cypress/support/page_objects/mainPage.js +++ b/scripts/cypress/support/page_objects/mainPage.js @@ -615,17 +615,7 @@ export class _mainPage { }); } - tabReset() { - // temporary disable (kludge) - // mainPage.toolBarTopLeft(mainPage.HOME).click({ force: true }); - // cy.get(".project-row").should("exist").click({ force: true }); - // projectsPage.waitHomePageLoad(); - // option-2 - // cy.openTableTab("Country", 0); - // cy.get(".mdi-close").click({ multiple: true }); - // cy.get("button.ant-tabs-tab-remove").click({ multiple: true }); - // cy.get('.ant-tabs-tab-remove').should('not.exist') - } + tabReset() {} toggleRightSidebar() { cy.get(".nc-toggle-right-navbar").should("exist").click(); diff --git a/scripts/cypress/support/page_objects/navigation.js b/scripts/cypress/support/page_objects/navigation.js index 0437237500..938350a238 100644 --- a/scripts/cypress/support/page_objects/navigation.js +++ b/scripts/cypress/support/page_objects/navigation.js @@ -70,16 +70,6 @@ export class _loginPage { loginAndOpenProject(apiType, dbType) { loginPage.signIn(roles.owner.credentials); projectsPage.openConfiguredProject(apiType, dbType); - // if (dbType === "mysql") { - // projectsPage.openProject(staticProjects.externalREST.basic.name); - // } else if (dbType === "xcdb") { - // projectsPage.openProject(staticProjects.sampleREST.basic.name); - // } else if (dbType === "postgres") { - // projectsPage.openProject(staticProjects.pgExternalREST.basic.name); - // } - // - // // close team & auth tab - // cy.get('button.ant-tabs-tab-remove').should('exist').click(); } } @@ -108,9 +98,7 @@ export class _projectsPage { cy.wait("@waitForPageLoad"); // close team & auth tab - cy.getSettled("button.ant-tabs-tab-remove").should("be.visible").click(); - cy.get("button.ant-tabs-tab-remove").should("not.exist"); - cy.wait(2000); + cy.closeTableTab(); } // Open existing project @@ -151,9 +139,7 @@ export class _projectsPage { cy.get(".nc-metadb-project-name").should("exist"); cy.contains("button", "Create").should("exist"); - // fix me! wait till the modal rendering (input highlight) is completed - // focus shifts back to the input field to select text after the dropdown is rendered - cy.wait(1000); + cy.inputHighlightRenderWait(); // feed project name cy.get(".nc-metadb-project-name", { timeout: 20000 }) @@ -183,9 +169,7 @@ export class _projectsPage { cy.get(".nc-extdb-proj-name").should("exist"); cy.get(".nc-extdb-btn-test-connection").should("exist"); - // fix me! wait till the modal rendering (input highlight) is completed - // focus shifts back to the input field to select text after the dropdown is rendered - cy.wait(1000); + cy.inputHighlightRenderWait(); cy.get(".nc-extdb-proj-name").clear().type(projectName);