Merge pull request #6286 from Budibase/cheeks-fixes

App list updates + small stuff
This commit is contained in:
Andrew Kingston 2022-06-20 10:18:13 +01:00 committed by GitHub
commit 7bca02c28e
11 changed files with 444 additions and 611 deletions

View File

@ -14,6 +14,7 @@
export let active = false export let active = false
export let tooltip = undefined export let tooltip = undefined
export let dataCy export let dataCy
export let newStyles = false
let showTooltip = false let showTooltip = false
</script> </script>
@ -25,6 +26,7 @@
class:spectrum-Button--warning={warning} class:spectrum-Button--warning={warning}
class:spectrum-Button--overBackground={overBackground} class:spectrum-Button--overBackground={overBackground}
class:spectrum-Button--quiet={quiet} class:spectrum-Button--quiet={quiet}
class:new-styles={newStyles}
class:active class:active
class="spectrum-Button spectrum-Button--size{size.toUpperCase()}" class="spectrum-Button spectrum-Button--size{size.toUpperCase()}"
{disabled} {disabled}
@ -93,4 +95,20 @@
padding-left: var(--spacing-m); padding-left: var(--spacing-m);
line-height: 0; line-height: 0;
} }
.spectrum-Button--primary.new-styles {
background: var(--spectrum-global-color-gray-800);
border-color: transparent;
color: var(--spectrum-global-color-gray-50);
}
.spectrum-Button--primary.new-styles:hover {
background: var(--spectrum-global-color-gray-900);
}
.spectrum-Button--secondary.new-styles {
background: var(--spectrum-global-color-gray-200);
border-color: transparent;
color: var(--spectrum-global-color-gray-900);
}
.spectrum-Button--secondary.new-styles:hover {
background: var(--spectrum-global-color-gray-300);
}
</style> </style>

View File

@ -112,4 +112,8 @@
.spectrum-Textfield { .spectrum-Textfield {
width: 100%; width: 100%;
} }
input:disabled {
color: var(--spectrum-global-color-gray-600) !important;
-webkit-text-fill-color: var(--spectrum-global-color-gray-600) !important;
}
</style> </style>

View File

@ -1,7 +1,7 @@
import filterTests from "../support/filterTests" import filterTests from "../support/filterTests"
import clientPackage from "@budibase/client/package.json" import clientPackage from "@budibase/client/package.json"
filterTests(['all'], () => { filterTests(["all"], () => {
context("Application Overview screen", () => { context("Application Overview screen", () => {
before(() => { before(() => {
cy.login() cy.login()
@ -10,31 +10,19 @@ filterTests(['all'], () => {
it("Should be accessible from the applications list", () => { it("Should be accessible from the applications list", () => {
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable .title")
.eq(0)
.invoke("attr", "data-cy")
.then($dataCy => {
const dataCy = $dataCy
cy.get(".appTable .app-row-actions button")
.contains("Manage")
.click({ force: true })
cy.get(".appTable .title").eq(0) cy.location().should(loc => {
.invoke('attr', 'data-cy') expect(loc.pathname).to.eq("/builder/portal/overview/" + dataCy)
.then(($dataCy) => {
const dataCy = $dataCy;
cy.get(".appTable .name").eq(0).click()
cy.location().should((loc) => {
expect(loc.pathname).to.eq('/builder/portal/overview/' + dataCy)
}) })
}) })
cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable .title").eq(0)
.invoke('attr', 'data-cy')
.then(($dataCy) => {
const dataCy = $dataCy;
cy.get(".appTable .app-row-actions button").contains("View").click({force: true})
cy.location().should((loc) => {
expect(loc.pathname).to.eq('/builder/portal/overview/' + dataCy)
})
})
}) })
// Find a more suitable place for this. // Find a more suitable place for this.
@ -43,24 +31,28 @@ filterTests(['all'], () => {
cy.get(".appTable .lock-status").eq(0).contains("Locked by you").click() cy.get(".appTable .lock-status").eq(0).contains("Locked by you").click()
cy.unlockApp({ owned : true }) cy.unlockApp({ owned: true })
cy.get(".appTable").should("exist") cy.get(".appTable").should("exist")
cy.get(".lock-status").should('not.be.visible') cy.get(".lock-status").should("not.be.visible")
}) })
it("Should allow unlocking in the app overview screen", () => { it("Should allow unlocking in the app overview screen", () => {
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable .app-row-actions button").contains("Edit").eq(0).click({force: true}) cy.get(".appTable .app-row-actions button")
.contains("Edit")
.eq(0)
.click({ force: true })
cy.wait(1000) cy.wait(1000)
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable .app-row-actions button")
cy.get(".appTable .name").eq(0).click() .contains("Manage")
.eq(0)
.click({ force: true })
cy.get(".lock-status").eq(0).contains("Locked by you").click() cy.get(".lock-status").eq(0).contains("Locked by you").click()
cy.unlockApp({ owned : true }) cy.unlockApp({ owned: true })
cy.get(".lock-status").should("not.be.visible") cy.get(".lock-status").should("not.be.visible")
}) })
@ -68,107 +60,149 @@ filterTests(['all'], () => {
it("Should reflect the deploy state of an app that hasn't been published.", () => { it("Should reflect the deploy state of an app that hasn't been published.", () => {
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable .name").eq(0).click() cy.get(".appTable .app-row-actions button")
.contains("Manage")
cy.get(".header-right button.spectrum-Button[data-cy='view-app']").should("be.disabled") .eq(0)
.click({ force: true })
cy.get(".header-right button.spectrum-Button[data-cy='view-app']").should(
"be.disabled"
)
cy.get(".spectrum-Tabs-item.is-selected").contains("Overview") cy.get(".spectrum-Tabs-item.is-selected").contains("Overview")
cy.get(".overview-tab").should("be.visible") cy.get(".overview-tab").should("be.visible")
cy.get(".overview-tab [data-cy='app-status']").within(() => { cy.get(".overview-tab [data-cy='app-status']").within(() => {
cy.get(".status-display").contains("Unpublished") cy.get(".status-display").contains("Unpublished")
cy.get(".status-display .icon svg[aria-label='GlobeStrike']").should("exist") cy.get(".status-display .icon svg[aria-label='GlobeStrike']").should(
"exist"
)
cy.get(".status-text").contains("-") cy.get(".status-text").contains("-")
}) })
}) })
it("Should reflect the app deployment state", () => { it("Should reflect the app deployment state", () => {
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable .app-row-actions button").contains("Edit").eq(0).click({force: true}) cy.get(".appTable .app-row-actions button")
.contains("Edit")
.eq(0)
.click({ force: true })
cy.get(".toprightnav button.spectrum-Button").contains("Publish").click({ force : true }) cy.get(".toprightnav button.spectrum-Button")
cy.get(".spectrum-Modal [data-cy='deploy-app-modal']").should("be.visible") .contains("Publish")
.click({ force: true })
cy.get(".spectrum-Modal [data-cy='deploy-app-modal']")
.should("be.visible")
.within(() => { .within(() => {
cy.get(".spectrum-Button").contains("Publish").click({ force : true }) cy.get(".spectrum-Button").contains("Publish").click({ force: true })
cy.wait(1000) cy.wait(1000)
}); })
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable .name").eq(0).click() cy.get(".appTable .app-row-actions button")
.contains("Manage")
cy.get(".header-right button.spectrum-Button[data-cy='view-app']").should("not.be.disabled") .eq(0)
.click({ force: true })
cy.get(".header-right button.spectrum-Button[data-cy='view-app']").should(
"not.be.disabled"
)
cy.get(".overview-tab [data-cy='app-status']").within(() => { cy.get(".overview-tab [data-cy='app-status']").within(() => {
cy.get(".status-display").contains("Published") cy.get(".status-display").contains("Published")
cy.get(".status-display .icon svg[aria-label='GlobeCheck']").should("exist") cy.get(".status-display .icon svg[aria-label='GlobeCheck']").should(
"exist"
)
cy.get(".status-text").contains("Last published a few seconds ago") cy.get(".status-text").contains("Last published a few seconds ago")
}) })
}) })
it("Should reflect an application that has been unpublished", () => { it("Should reflect an application that has been unpublished", () => {
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable .app-row-actions button").contains("Edit").eq(0).click({force: true}) cy.get(".appTable .app-row-actions button")
.contains("Edit")
cy.get(".deployment-top-nav svg[aria-label='Globe']") .eq(0)
.click({ force: true }) .click({ force: true })
cy.get("[data-cy='publish-popover-menu']").should("be.visible") cy.get(".deployment-top-nav svg[aria-label='Globe']").click({
cy.get("[data-cy='publish-popover-menu'] [data-cy='publish-popover-action']") force: true,
.click({ force : true }) })
cy.get("[data-cy='unpublish-modal']").should("be.visible") cy.get("[data-cy='publish-popover-menu']").should("be.visible")
cy.get(
"[data-cy='publish-popover-menu'] [data-cy='publish-popover-action']"
).click({ force: true })
cy.get("[data-cy='unpublish-modal']")
.should("be.visible")
.within(() => { .within(() => {
cy.get(".confirm-wrap button").click({ force: true } cy.get(".confirm-wrap button").click({ force: true })
)}) })
cy.wait(1000) cy.wait(1000)
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable .name").eq(0).click() cy.get(".appTable .app-row-actions button")
.contains("Manage")
.eq(0)
.click({ force: true })
cy.get(".overview-tab [data-cy='app-status']").within(() => { cy.get(".overview-tab [data-cy='app-status']").within(() => {
cy.get(".status-display").contains("Unpublished") cy.get(".status-display").contains("Unpublished")
cy.get(".status-display .icon svg[aria-label='GlobeStrike']").should("exist") cy.get(".status-display .icon svg[aria-label='GlobeStrike']").should(
"exist"
)
cy.get(".status-text").contains("Last published a few seconds ago") cy.get(".status-text").contains("Last published a few seconds ago")
}) })
}) })
it("Should allow the editing of the application icon and colour", () => { it("Should allow the editing of the application icon and colour", () => {
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable", { timeout: 2000}) cy.get(".appTable .app-row-actions button")
.within(() => { .contains("Manage")
cy.get(".app-row-actions-icon").eq(0).click() .eq(0)
.click({ force: true })
cy.wait(1000)
cy.get(".app-overview-actions-icon").within(() => {
cy.get(".spectrum-Icon").click({ force: true })
}) })
cy.get(".spectrum-Menu").contains("Edit icon").click() cy.get(".spectrum-Menu").contains("Edit icon").click()
// Select random icon // Select random icon
cy.get(".grid").within(() => { cy.get(".grid").within(() => {
cy.get(".icon-item").eq(Math.floor(Math.random() * 23) + 1).click() cy.get(".icon-item")
.eq(Math.floor(Math.random() * 23) + 1)
.click()
}) })
// Select random colour // Select random colour
cy.get(".fill").click() cy.get(".fill").click()
cy.get(".colors").within(() => { cy.get(".colors").within(() => {
cy.get(".color").eq(Math.floor(Math.random() * 33) + 1).click() cy.get(".color")
.eq(Math.floor(Math.random() * 33) + 1)
.click()
}) })
cy.intercept('**/applications/**').as('iconChange') cy.intercept("**/applications/**").as("iconChange")
cy.get(".spectrum-Button").contains("Save").click({ force: true }) cy.get(".spectrum-Button").contains("Save").click({ force: true })
cy.wait("@iconChange") cy.wait("@iconChange")
cy.get("@iconChange").its('response.statusCode') cy.get("@iconChange").its("response.statusCode").should("eq", 200)
.should('eq', 200)
// Confirm icon has changed from default // Confirm icon has changed from default
// Confirm colour has been applied // Confirm colour has been applied
cy.get(".appTable", { timeout: 2000}) cy.get(".appTable", { timeout: 2000 }).within(() => {
.within(() => { cy.get("[aria-label]")
cy.get('[aria-label]').eq(0).children() .eq(0)
.should('have.attr', 'xlink:href').and('not.contain', '#spectrum-icon-18-Apps') .children()
cy.get(".title").children().children() .should("have.attr", "xlink:href")
.should('have.attr', 'style').and('contains', 'color') .and("not.contain", "#spectrum-icon-18-Apps")
cy.get(".title")
.children()
.children()
.should("have.attr", "style")
.and("contains", "color")
}) })
}) })
it("Should reflect the last time the application was edited", () => { it("Should reflect the last time the application was edited", () => {
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable .name").eq(0).click() cy.get(".appTable .app-row-actions button")
.contains("Manage")
cy.get(".header-right button").contains("Edit").click({ force: true }); .eq(0)
.click({ force: true })
cy.get(".header-right button").contains("Edit").click({ force: true })
cy.navigateToFrontend() cy.navigateToFrontend()
@ -177,41 +211,51 @@ filterTests(['all'], () => {
}) })
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable .name").eq(0).click() cy.get(".appTable .app-row-actions button")
.contains("Manage")
.eq(0)
.click({ force: true })
cy.get(".overview-tab [data-cy='edited-by']").within(() => { cy.get(".overview-tab [data-cy='edited-by']").within(() => {
cy.get(".editor-name").contains("You") cy.get(".editor-name").contains("You")
cy.get(".last-edit-text").contains("Last edited a few seconds ago") cy.get(".last-edit-text").contains("Last edited a few seconds ago")
}) })
}); })
it("Should reflect application version is up-to-date", () => { it("Should reflect application version is up-to-date", () => {
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable .name").eq(0).click() cy.get(".appTable .app-row-actions button")
.contains("Manage")
.eq(0)
.click({ force: true })
cy.get(".overview-tab [data-cy='app-version']").within(() => { cy.get(".overview-tab [data-cy='app-version']").within(() => {
cy.get(".version-status").contains("You're running the latest!") cy.get(".version-status").contains("You're running the latest!")
}) })
}); })
it("Should navigate to the settings tab when clicking the App Version card header", () => { it("Should navigate to the settings tab when clicking the App Version card header", () => {
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable .name").eq(0).click() cy.get(".appTable .app-row-actions button")
.contains("Manage")
.eq(0)
.click({ force: true })
cy.get(".spectrum-Tabs-item.is-selected").contains("Overview") cy.get(".spectrum-Tabs-item.is-selected").contains("Overview")
cy.get(".overview-tab").should("be.visible") cy.get(".overview-tab").should("be.visible")
cy.get(".overview-tab [data-cy='app-version'] .dash-card-header").click({ force : true }) cy.get(".overview-tab [data-cy='app-version'] .dash-card-header").click({
force: true,
})
cy.get(".spectrum-Tabs-item.is-selected").contains("Settings") cy.get(".spectrum-Tabs-item.is-selected").contains("Settings")
cy.get(".settings-tab").should("be.visible") cy.get(".settings-tab").should("be.visible")
cy.get(".overview-tab").should("not.exist") cy.get(".overview-tab").should("not.exist")
})
});
it("Should allow the upgrading of an application, if available.", () => { it("Should allow the upgrading of an application, if available.", () => {
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable .name").eq(0).click() cy.get(".appTable .app-row-actions button")
.contains("Manage")
.eq(0)
.click({ force: true })
cy.wait(500) cy.wait(500)
cy.location().then(loc => { cy.location().then(loc => {
@ -219,8 +263,7 @@ filterTests(['all'], () => {
const appId = params[params.length - 1] const appId = params[params.length - 1]
cy.log(appId) cy.log(appId)
//Downgrade the app for the test //Downgrade the app for the test
cy.alterAppVersion(appId, "0.0.1-alpha.0") cy.alterAppVersion(appId, "0.0.1-alpha.0").then(() => {
.then(()=>{
cy.reload() cy.reload()
cy.wait(1000) cy.wait(1000)
cy.log("Current deployment version: " + clientPackage.version) cy.log("Current deployment version: " + clientPackage.version)
@ -228,65 +271,90 @@ filterTests(['all'], () => {
cy.get(".version-status a").contains("Update").click() cy.get(".version-status a").contains("Update").click()
cy.get(".spectrum-Tabs-item.is-selected").contains("Settings") cy.get(".spectrum-Tabs-item.is-selected").contains("Settings")
cy.get(".version-section .page-action button").contains("Update").click({ force: true }) cy.get(".version-section .page-action button")
.contains("Update")
.click({ force: true })
cy.intercept('POST', '**/applications/**/client/update').as('updateVersion') cy.intercept("POST", "**/applications/**/client/update").as(
cy.get(".spectrum-Modal.is-open button").contains("Update").click({ force: true }) "updateVersion"
)
cy.get(".spectrum-Modal.is-open button")
.contains("Update")
.click({ force: true })
cy.wait("@updateVersion") cy.wait("@updateVersion")
.its('response.statusCode').should('eq', 200) .its("response.statusCode")
.should("eq", 200)
.then(() => { .then(() => {
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable .name").eq(0).click() cy.get(".appTable .app-row-actions button")
.contains("Manage")
cy.get(".spectrum-Tabs-item").contains("Overview").click({ force: true }) .eq(0)
.click({ force: true })
cy.get(".spectrum-Tabs-item")
.contains("Overview")
.click({ force: true })
cy.get(".overview-tab [data-cy='app-version']").within(() => { cy.get(".overview-tab [data-cy='app-version']").within(() => {
cy.get(".spectrum-Heading").contains(clientPackage.version) cy.get(".spectrum-Heading").contains(clientPackage.version)
cy.get(".version-status").contains("You're running the latest!") cy.get(".version-status").contains("You're running the latest!")
}) })
}) })
}) })
}); })
}) })
it("Should allow editing of the app details.", () => { it("Should allow editing of the app details.", () => {
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable .name").eq(0).click() cy.get(".appTable .app-row-actions button")
.contains("Manage")
.eq(0)
.click({ force: true })
cy.get(".spectrum-Tabs-item").contains("Settings").click() cy.get(".spectrum-Tabs-item").contains("Settings").click()
cy.get(".spectrum-Tabs-item.is-selected").contains("Settings") cy.get(".spectrum-Tabs-item.is-selected").contains("Settings")
cy.get(".settings-tab").should("be.visible") cy.get(".settings-tab").should("be.visible")
cy.get(".details-section .page-action button").contains("Edit").click({ force: true }) cy.get(".details-section .page-action button")
.contains("Edit")
.click({ force: true })
cy.updateAppName("sample name") cy.updateAppName("sample name")
//publish and check its disabled //publish and check its disabled
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable .app-row-actions button").contains("Edit").eq(0).click({force: true}) cy.get(".appTable .app-row-actions button")
.contains("Edit")
.eq(0)
.click({ force: true })
cy.get(".toprightnav button.spectrum-Button").contains("Publish").click({ force : true }) cy.get(".toprightnav button.spectrum-Button")
cy.get(".spectrum-Modal [data-cy='deploy-app-modal']").should("be.visible") .contains("Publish")
.click({ force: true })
cy.get(".spectrum-Modal [data-cy='deploy-app-modal']")
.should("be.visible")
.within(() => { .within(() => {
cy.get(".spectrum-Button").contains("Publish").click({ force : true }) cy.get(".spectrum-Button").contains("Publish").click({ force: true })
cy.wait(1000) cy.wait(1000)
}); })
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.wait(1000) cy.wait(1000)
cy.get(".appTable .name").eq(0).click() cy.get(".appTable .app-row-actions button")
.contains("Manage")
.eq(0)
.click({ force: true })
cy.get(".spectrum-Tabs-item").contains("Settings").click() cy.get(".spectrum-Tabs-item").contains("Settings").click()
cy.get(".spectrum-Tabs-item.is-selected").contains("Settings") cy.get(".spectrum-Tabs-item.is-selected").contains("Settings")
cy.get(".details-section .page-action .spectrum-Button").scrollIntoView() cy.get(".details-section .page-action .spectrum-Button").scrollIntoView()
cy.wait(1000) cy.wait(1000)
cy.get(".details-section .page-action .spectrum-Button").should("be.disabled") cy.get(".details-section .page-action .spectrum-Button").should(
"be.disabled"
)
}) })
xit("Should allow copying of the published application Id", () => { xit("Should allow copying of the published application Id", () => {
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable .app-row-actions").eq(0) cy.get(".appTable .app-row-actions")
.eq(0)
.within(() => { .within(() => {
cy.get(".spectrum-Button").contains("Edit").click({ force: true }) cy.get(".spectrum-Button").contains("Edit").click({ force: true })
}) })
@ -294,47 +362,70 @@ filterTests(['all'], () => {
cy.publishApp("sample-name") cy.publishApp("sample-name")
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable .name").eq(0).click() cy.get(".appTable .app-row-actions button")
.contains("Manage")
.eq(0)
.click({ force: true })
cy.get(".app-overview-actions-icon > .icon").click({ force: true })
cy.get(".app-overview-actions-icon > .icon").click({ force : true }) cy.get("[data-cy='app-overview-menu-popover']")
.eq(0)
cy.get("[data-cy='app-overview-menu-popover']").eq(0).within(() => { .within(() => {
cy.get(".spectrum-Menu-item").contains("Copy App ID").click({ force: true }) cy.get(".spectrum-Menu-item")
.contains("Copy App ID")
.click({ force: true })
}) })
cy.get(".spectrum-Toast-content").contains("App ID copied to clipboard.").should("be.visible") cy.get(".spectrum-Toast-content")
.contains("App ID copied to clipboard.")
.should("be.visible")
}) })
it("Should allow unpublishing of the application", () => { it("Should allow unpublishing of the application", () => {
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable .name").eq(0).click() cy.get(".appTable .app-row-actions button")
.contains("Manage")
.eq(0)
.click({ force: true })
cy.get(".app-overview-actions-icon > .icon").click({ force: true })
cy.get(".app-overview-actions-icon > .icon").click({ force : true }) cy.get("[data-cy='app-overview-menu-popover']")
.eq(0)
cy.get("[data-cy='app-overview-menu-popover']").eq(0).within(() => { .within(() => {
cy.get(".spectrum-Menu-item").contains("Unpublish").click({ force: true }) cy.get(".spectrum-Menu-item")
.contains("Unpublish")
.click({ force: true })
cy.wait(500) cy.wait(500)
}) })
cy.get("[data-cy='unpublish-modal']").should("be.visible") cy.get("[data-cy='unpublish-modal']")
.should("be.visible")
.within(() => { .within(() => {
cy.get(".confirm-wrap button").click({ force: true } cy.get(".confirm-wrap button").click({ force: true })
)}) })
cy.get(".overview-tab [data-cy='app-status']").within(() => { cy.get(".overview-tab [data-cy='app-status']").within(() => {
cy.get(".status-display").contains("Unpublished") cy.get(".status-display").contains("Unpublished")
cy.get(".status-display .icon svg[aria-label='GlobeStrike']").should("exist") cy.get(".status-display .icon svg[aria-label='GlobeStrike']").should(
"exist"
)
}) })
}) })
it("Should allow deleting of the application", () => { it("Should allow deleting of the application", () => {
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(".appTable .name").eq(0).click() cy.get(".appTable .app-row-actions button")
.contains("Manage")
.eq(0)
.click({ force: true })
cy.get(".app-overview-actions-icon > .icon").click({ force: true })
cy.get(".app-overview-actions-icon > .icon").click({ force : true }) cy.get("[data-cy='app-overview-menu-popover']")
.eq(0)
cy.get("[data-cy='app-overview-menu-popover']").eq(0).within(() => { .within(() => {
cy.get(".spectrum-Menu-item").contains("Delete").click({ force: true }) cy.get(".spectrum-Menu-item")
.contains("Delete")
.click({ force: true })
cy.wait(500) cy.wait(500)
}) })
@ -344,8 +435,8 @@ filterTests(['all'], () => {
cy.get(".spectrum-Button--warning").click() cy.get(".spectrum-Button--warning").click()
}) })
cy.location().should((loc) => { cy.location().should(loc => {
expect(loc.pathname).to.eq('/builder/portal/apps') expect(loc.pathname).to.eq("/builder/portal/apps")
}) })
cy.get(".appTable").should("not.exist") cy.get(".appTable").should("not.exist")
@ -356,6 +447,5 @@ filterTests(['all'], () => {
after(() => { after(() => {
cy.deleteAllApps() cy.deleteAllApps()
}) })
}) })
}) })

View File

@ -1,7 +1,7 @@
import filterTests from "../support/filterTests" import filterTests from "../support/filterTests"
const interact = require('../support/interact') const interact = require("../support/interact")
filterTests(['all'], () => { filterTests(["all"], () => {
context("Create Components", () => { context("Create Components", () => {
let headlineId let headlineId
@ -19,15 +19,13 @@ filterTests(['all'], () => {
//Use the tree to delete a selected component //Use the tree to delete a selected component
const deleteSelectedComponent = () => { const deleteSelectedComponent = () => {
cy.get(".nav-items-container .nav-item.selected .actions > div > .icon").click({ cy.get(
".nav-items-container .nav-item.selected .actions > div > .icon"
).click({
force: true, force: true,
}) })
cy.get(".spectrum-Popover.is-open li") cy.get(".spectrum-Popover.is-open li").contains("Delete").click()
.contains("Delete") cy.get(".spectrum-Modal button").contains("Delete Component").click({
.click()
cy.get(".spectrum-Modal button")
.contains("Delete Component")
.click({
force: true, force: true,
}) })
} }
@ -47,16 +45,16 @@ filterTests(['all'], () => {
it("should change the text of the headline", () => { it("should change the text of the headline", () => {
const text = "Lorem ipsum dolor sit amet." const text = "Lorem ipsum dolor sit amet."
cy.get("[data-cy=setting-text] input") cy.get("[data-cy=setting-text] input").type(text).blur()
.type(text)
.blur()
cy.getComponent(headlineId).should("have.text", text) cy.getComponent(headlineId).should("have.text", text)
}) })
it("should change the size of the headline", () => { it("should change the size of the headline", () => {
cy.get("[data-cy=setting-size]").scrollIntoView().click() cy.get("[data-cy=setting-size]").scrollIntoView().click()
cy.get("[data-cy=setting-size]").within(() => { cy.get("[data-cy=setting-size]").within(() => {
cy.get(".spectrum-Form-item li.spectrum-Menu-item").contains("3XL").click() cy.get(".spectrum-Form-item li.spectrum-Menu-item")
.contains("3XL")
.click()
}) })
cy.getComponent(headlineId).within(() => { cy.getComponent(headlineId).within(() => {
@ -66,12 +64,8 @@ filterTests(['all'], () => {
it("should create a form and reset to match schema", () => { it("should create a form and reset to match schema", () => {
cy.addComponent("Form", "Form").then(() => { cy.addComponent("Form", "Form").then(() => {
cy.get("[data-cy=setting-dataSource]") cy.get("[data-cy=setting-dataSource]").contains("Custom").click()
.contains("Custom") cy.get(interact.DROPDOWN).contains("dog").click()
.click()
cy.get(interact.DROPDOWN)
.contains("dog")
.click()
cy.wait(500) cy.wait(500)
cy.addComponent("Form", "Field Group").then(fieldGroupId => { cy.addComponent("Form", "Field Group").then(fieldGroupId => {
cy.contains("Update form fields").click() cy.contains("Update form fields").click()
@ -85,9 +79,7 @@ filterTests(['all'], () => {
cy.contains("breed").should("exist") cy.contains("breed").should("exist")
// cy.contains("image").should("exist") // cy.contains("image").should("exist")
}) })
cy.getComponent(fieldGroupId) cy.getComponent(fieldGroupId).find("input").should("have.length", 2)
.find("input")
.should("have.length", 2)
cy.getComponent(fieldGroupId) cy.getComponent(fieldGroupId)
.find(interact.SPECTRUM_PICKER) .find(interact.SPECTRUM_PICKER)
.should("have.length", 1) .should("have.length", 1)
@ -97,191 +89,102 @@ filterTests(['all'], () => {
it("deletes a component", () => { it("deletes a component", () => {
cy.addComponent("Elements", "Paragraph").then(componentId => { cy.addComponent("Elements", "Paragraph").then(componentId => {
cy.get("[data-cy=setting-_instanceName] input") cy.get("[data-cy=setting-_instanceName] input").type(componentId).blur()
.type(componentId) cy.get(
.blur() ".nav-items-container .nav-item.selected .actions > div > .icon"
cy.get(".nav-items-container .nav-item.selected .actions > div > .icon").click({ ).click({
force: true, force: true,
}) })
cy.get(".spectrum-Popover.is-open li") cy.get(".spectrum-Popover.is-open li").contains("Delete").click()
.contains("Delete") cy.get(".spectrum-Modal button").contains("Delete Component").click({
.click()
cy.get(".spectrum-Modal button")
.contains("Delete Component")
.click({
force: true, force: true,
}) })
cy.getComponent(componentId).should("not.exist") cy.getComponent(componentId).should("not.exist")
}) })
}) })
it("should set focus to the field setting when fields are added to a form", () => {
cy.addComponent("Form", "Form").then((formId) => {
//For deletion
cy.get("[data-cy=setting-_instanceName] input")
.clear()
.type(formId)
.blur()
const componentTypeLabels = ["Text Field", "Number Field", "Password Field",
"Options Picker", "Checkbox", "Long Form Field", "Date Picker", "Attachment",
"JSON Field", "Multi-select Picker", "Relationship Picker"]
const refocusTest = (componentId) => {
cy.getComponent(componentId)
.find(".showMe").should("exist").click({ force: true })
cy.get("[data-cy=setting-field] .spectrum-InputGroup")
.should("have.class", "is-focused")
}
const testFieldFocusOnCreate = (componentLabel) => {
cy.log("Adding: " + componentLabel)
return cy.addComponent("Form", componentLabel).then((componentId) => {
refocusTest(componentId)
cy.get("[data-cy=setting-field] .spectrum-InputGroup")
.should("have.class", "is-focused")
})
}
cy.wait(1000)
cy.wrap(componentTypeLabels).each((label) => {
return testFieldFocusOnCreate(label)
}).then(()=>{
cy.get(".nav-items-container .nav-item").contains(formId).click({ force: true })
deleteSelectedComponent()
})
})
})
it("should clear the iframe place holder when a form field has been set", () => { it("should clear the iframe place holder when a form field has been set", () => {
cy.addComponent("Form", "Form").then((formId) => { cy.addComponent("Form", "Form").then(formId => {
//For deletion //For deletion
cy.get("[data-cy=setting-_instanceName] input") cy.get("[data-cy=setting-_instanceName] input")
.clear() .clear()
.type(formId) .type(formId)
.blur() .blur()
cy.get("[data-cy=setting-dataSource]").contains("Custom").click()
cy.get("[data-cy=setting-dataSource]") cy.get(".dropdown").contains("dog").click()
.contains("Custom")
.click()
cy.get(".dropdown")
.contains("dog")
.click()
const fieldTypeToColumnName = { const fieldTypeToColumnName = {
"Text Field" : "name", "Text Field": "name",
"Number Field": "age", "Number Field": "age",
"Options Picker": "breed" "Options Picker": "breed",
} }
const componentTypeLabels = Object.keys(fieldTypeToColumnName) const componentTypeLabels = Object.keys(fieldTypeToColumnName)
const testFieldFocusOnCreate = (componentLabel) => { const testFieldFocusOnCreate = componentLabel => {
cy.log("Adding: " + componentLabel) cy.log("Adding: " + componentLabel)
return cy.addComponent("Form", componentLabel).then((componentId) => { return cy.addComponent("Form", componentLabel).then(componentId => {
cy.getComponent(componentId) cy.getComponent(componentId)
.find(".placeholder_wrap").should("exist") .find(".component-placeholder")
.should("exist")
cy.get("[data-cy=setting-field] .spectrum-InputGroup")
.should("have.class", "is-focused")
cy.get("[data-cy=setting-field] button.spectrum-Picker").click() cy.get("[data-cy=setting-field] button.spectrum-Picker").click()
//Click the first appropriate field. They are filtered by type //Click the first appropriate field. They are filtered by type
cy.get("[data-cy=setting-field] .spectrum-Popover.is-open li.spectrum-Menu-item") cy.get(
.contains(fieldTypeToColumnName[componentLabel]).click() "[data-cy=setting-field] .spectrum-Popover.is-open li.spectrum-Menu-item"
)
.contains(fieldTypeToColumnName[componentLabel])
.click()
cy.wait(500) cy.wait(500)
cy.getComponent(componentId) cy.getComponent(componentId)
.find(".placeholder_wrap").should("not.exist") .find(".component-placeholder")
.should("not.exist")
}) })
} }
cy.wait(500) cy.wait(500)
cy.wrap(componentTypeLabels).each((label) => { cy.wrap(componentTypeLabels)
.each(label => {
return testFieldFocusOnCreate(label) return testFieldFocusOnCreate(label)
}).then(()=>{ })
cy.get(".nav-items-container .nav-item").contains(formId).click({ force: true }) .then(() => {
cy.get(".nav-items-container .nav-item")
.contains(formId)
.click({ force: true })
deleteSelectedComponent() deleteSelectedComponent()
}) })
}) })
}) })
it("should focus a charts settings on data provider if not nested in provider ", () => {
cy.addComponent("Layout", "Container").then((containerId) => {
//For deletion
cy.get("[data-cy=setting-_instanceName] input")
.clear()
.type(containerId)
.blur()
const chartTypeLabels = ["Bar Chart", "Line Chart", "Area Chart", "Pie Chart",
"Donut Chart", "Candlestick Chart"]
const refocusTest = (componentId) => {
cy.getComponent(componentId)
.find(".showMe").should("exist").click({ force: true })
cy.get("[data-cy=dataProvider-prop-control] .spectrum-Picker")
.should("have.class", "is-focused")
}
const testFocusOnCreate = (chartLabel) => {
cy.log("Adding: " + chartLabel)
cy.addComponent("Chart", chartLabel).then((componentId) => {
refocusTest(componentId)
cy.get("[data-cy=dataProvider-prop-control] .spectrum-Picker")
.should("have.class", "is-focused")
})
}
cy.wait(1000)
cy.wrap(chartTypeLabels).each((label) => {
return testFocusOnCreate(label)
})
.then(()=>{
cy.get(".nav-items-container .nav-item").contains(containerId).click({ force: true })
deleteSelectedComponent()
})
})
})
it("should populate the provider for charts with a data provider in its path", () => { it("should populate the provider for charts with a data provider in its path", () => {
cy.addComponent("Data", "Data Provider").then((providerId) => { cy.addComponent("Data", "Data Provider").then(providerId => {
//For deletion //For deletion
cy.get("[data-cy=setting-_instanceName] input") cy.get("[data-cy=setting-_instanceName] input")
.clear() .clear()
.type(providerId) .type(providerId)
.blur() .blur()
cy.get("[data-cy=setting-dataSource]") cy.get("[data-cy=setting-dataSource]")
.contains("Choose an option") .contains("Choose an option")
.click() .click()
cy.get(`[data-cy=dataSource-popover-${providerId}] ul li`) cy.get(`[data-cy=dataSource-popover-${providerId}] ul li`)
.contains("dog") .contains("dog")
.click() .click()
const chartTypeLabels = ["Bar Chart", "Line Chart", "Area Chart", "Pie Chart", const chartTypeLabels = [
"Donut Chart", "Candlestick Chart"] "Bar Chart",
"Line Chart",
"Area Chart",
"Pie Chart",
"Donut Chart",
"Candlestick Chart",
]
const testFocusOnCreate = (chartLabel) => { const testFocusOnCreate = chartLabel => {
cy.log("Adding: " + chartLabel) cy.log("Adding: " + chartLabel)
cy.addComponent("Chart", chartLabel).then((componentId) => { cy.addComponent("Chart", chartLabel).then(componentId => {
cy.get(
cy.get("[data-cy=dataProvider-prop-control] .spectrum-Picker") "[data-cy=dataProvider-prop-control] .spectrum-Picker"
.should("not.have.class", "is-focused") ).should("not.have.class", "is-focused")
// Pre populated. // Pre populated.
cy.get("[data-cy=dataProvider-prop-control] .spectrum-Picker-label") cy.get("[data-cy=dataProvider-prop-control] .spectrum-Picker-label")
@ -289,114 +192,86 @@ filterTests(['all'], () => {
.should("exist") .should("exist")
}) })
} }
cy.wait(1000) cy.wait(1000)
cy.wrap(chartTypeLabels).each((label) => { cy.wrap(chartTypeLabels)
.each(label => {
return testFocusOnCreate(label) return testFocusOnCreate(label)
}) })
.then(()=>{ .then(() => {
cy.get(".nav-items-container .nav-item").contains(providerId).click({ force: true }) cy.get(".nav-items-container .nav-item")
.contains(providerId)
.click({ force: true })
deleteSelectedComponent() deleteSelectedComponent()
}) })
}) })
}) })
it("should replace the placeholder when a url is set on an image", () => { it("should replace the placeholder when a url is set on an image", () => {
cy.addComponent("Elements", "Image").then((imageId) => { cy.addComponent("Elements", "Image").then(imageId => {
cy.get("[data-cy=url-prop-control] .spectrum-InputGroup")
.should("have.class", "is-focused")
cy.get("[data-cy=setting-_instanceName] input") cy.get("[data-cy=setting-_instanceName] input")
.clear() .clear()
.type(imageId) .type(imageId)
.blur() .blur()
//return $("New Data Provider.Rows")[0]["Attachment"][0]["url"] //return $("New Data Provider.Rows")[0]["Attachment"][0]["url"]
//No minio, so just enter something local that will not reslove //No minio, so just enter something local that will not reslove
cy.get("[data-cy=url-prop-control] input[type=text]") cy.get("[data-cy=url-prop-control] input[type=text]")
.type("cypress/fixtures/ghost.png") .type("cypress/fixtures/ghost.png")
.blur() .blur()
cy.getComponent(imageId) cy.getComponent(imageId)
.find(".placeholder_wrap").should("not.exist") .find(".component-placeholder")
.should("not.exist")
cy.getComponent(imageId) cy.getComponent(imageId).find(`img[alt=${imageId}]`).should("exist")
.find(`img[alt=${imageId}]`).should("exist")
cy.get(".nav-items-container .nav-item") cy.get(".nav-items-container .nav-item")
.contains(imageId) .contains(imageId)
.click({ force: true }) .click({ force: true })
deleteSelectedComponent() deleteSelectedComponent()
}) })
}) })
it("should add a markdown component.", () => { it("should add a markdown component.", () => {
cy.addComponent("Elements", "Markdown Viewer").then((markdownId) => { cy.addComponent("Elements", "Markdown Viewer").then(markdownId => {
cy.get("[data-cy=value-prop-control] .spectrum-InputGroup")
.should("have.class", "is-focused")
cy.get("[data-cy=setting-_instanceName] input") cy.get("[data-cy=setting-_instanceName] input")
.clear() .clear()
.type(markdownId) .type(markdownId)
.blur() .blur()
cy.get(
cy.get("[data-cy=value-prop-control] input[type=text].spectrum-Textfield-input") "[data-cy=value-prop-control] input[type=text].spectrum-Textfield-input"
.type("# Hi").blur() )
.type("# Hi")
.blur()
cy.getComponent(markdownId) cy.getComponent(markdownId)
.find(".placeholder_wrap").should("not.exist") .find(".component-placeholder")
.should("not.exist")
cy.getComponent(markdownId) cy.getComponent(markdownId)
.find(".editor-preview-full h1").contains("Hi") .find(".editor-preview-full h1")
.contains("Hi")
cy.get(".nav-items-container .nav-item") cy.get(".nav-items-container .nav-item")
.contains(markdownId) .contains(markdownId)
.click({ force: true }) .click({ force: true })
deleteSelectedComponent() deleteSelectedComponent()
}) })
}) })
it("should direct the user when adding an Icon component.", () => { it("should direct the user when adding an Icon component.", () => {
cy.addComponent("Elements", "Icon").then((iconId) => { cy.addComponent("Elements", "Icon").then(iconId => {
cy.getComponent(iconId).find(".component-placeholder").should("exist")
cy.get("[data-cy=icon-prop-control] .spectrum-ActionButton")
.should("have.class", "is-focused")
cy.getComponent(iconId)
.find(".placeholder_wrap").should("exist")
cy.get("[data-cy=setting-_instanceName] input") cy.get("[data-cy=setting-_instanceName] input")
.clear() .clear()
.type(iconId) .type(iconId)
.blur() .blur()
cy.get("[data-cy=icon-prop-control] .spectrum-ActionButton").click() cy.get("[data-cy=icon-prop-control] .spectrum-ActionButton").click()
cy.get("[data-cy=icon-popover].spectrum-Popover.is-open").within(() => { cy.get("[data-cy=icon-popover].spectrum-Popover.is-open").within(() => {
cy.get(".search-input input") cy.get(".search-input input").type("save").blur()
.type("save")
.blur()
cy.get(".search-input button").click({ force: true }) cy.get(".search-input button").click({ force: true })
cy.get(".icon-area .icon-container").eq(0).click({ force: true }) cy.get(".icon-area .icon-container").eq(0).click({ force: true })
}) })
cy.getComponent(iconId) cy.getComponent(iconId)
.find(".placeholder_wrap").should("not.exist") .find(".component-placeholder")
.should("not.exist")
cy.getComponent(iconId) cy.getComponent(iconId).find("i.ri-save-fill").should("exist")
.find("i.ri-save-fill").should("exist")
cy.get(".nav-items-container .nav-item") cy.get(".nav-items-container .nav-item")
.contains(iconId) .contains(iconId)
.click({ force: true }) .click({ force: true })
deleteSelectedComponent() deleteSelectedComponent()
}) })
}) })

View File

@ -1,7 +1,7 @@
import filterTests from "../support/filterTests" import filterTests from "../support/filterTests"
const interact = require('../support/interact') const interact = require("../support/interact")
filterTests(['all'], () => { filterTests(["all"], () => {
context("Rename an App", () => { context("Rename an App", () => {
beforeEach(() => { beforeEach(() => {
cy.login() cy.login()
@ -32,11 +32,14 @@ filterTests(['all'], () => {
const appRename = "Cypress Renamed" const appRename = "Cypress Renamed"
// Publish the app // Publish the app
cy.get(interact.TOP_RIGHT_NAV) cy.get(interact.TOP_RIGHT_NAV)
cy.get(interact.SPECTRUM_BUTTON).contains("Publish").click({ force: true }) cy.get(interact.SPECTRUM_BUTTON)
cy.get(interact.SPECTRUM_DIALOG_GRID) .contains("Publish")
.within(() => { .click({ force: true })
cy.get(interact.SPECTRUM_DIALOG_GRID).within(() => {
// Click publish again within the modal // Click publish again within the modal
cy.get(interact.SPECTRUM_BUTTON).contains("Publish").click({ force: true }) cy.get(interact.SPECTRUM_BUTTON)
.contains("Publish")
.click({ force: true })
}) })
// Rename app, Search for app, Confirm name was changed // Rename app, Search for app, Confirm name was changed
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
@ -64,13 +67,19 @@ filterTests(['all'], () => {
const appName = "Cypress Tests" const appName = "Cypress Tests"
cy.visit(`${Cypress.config().baseUrl}/builder`) cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.wait(500) cy.wait(500)
cy.get(interact.SPECTRUM_BUTTON).contains("Create app").click({ force: true }) cy.get(interact.SPECTRUM_BUTTON)
.contains("Create app")
.click({ force: true })
cy.contains(/Start from scratch/).click() cy.contains(/Start from scratch/).click()
cy.get(interact.SPECTRUM_MODAL) cy.get(interact.SPECTRUM_MODAL).within(() => {
.within(() => {
cy.get("input").eq(0).type(appName) cy.get("input").eq(0).type(appName)
cy.get(interact.SPECTRUM_BUTTON_GROUP).contains("Create app").click({ force: true }) cy.get(interact.SPECTRUM_BUTTON_GROUP)
cy.get(interact.ERROR).should("have.text", "Another app with the same name already exists") .contains("Create app")
.click({ force: true })
cy.get(interact.ERROR).should(
"have.text",
"Another app with the same name already exists"
)
}) })
}) })
@ -89,7 +98,10 @@ filterTests(['all'], () => {
cy.reload() cy.reload()
cy.wait(1000) cy.wait(1000)
renameApp(numberName, specialCharName) renameApp(numberName, specialCharName)
cy.get(interact.ERROR).should("have.text", "App name must be letters, numbers and spaces only") cy.get(interact.ERROR).should(
"have.text",
"App name must be letters, numbers and spaces only"
)
// Set app name back to Cypress Tests // Set app name back to Cypress Tests
cy.reload() cy.reload()
cy.wait(1000) cy.wait(1000)
@ -98,24 +110,19 @@ filterTests(['all'], () => {
const renameApp = (originalName, changedName, published, noName) => { const renameApp = (originalName, changedName, published, noName) => {
cy.searchForApplication(originalName) cy.searchForApplication(originalName)
cy.get(interact.APP_TABLE) cy.get(interact.APP_TABLE).within(() => {
.within(() => { cy.get(".app-row-actions button")
cy.get(interact.AREA_LABEL_MORE).eq(0).click() .contains("Manage")
.eq(0)
.click({ force: true })
}) })
// Check for when an app is published cy.get(".spectrum-Tabs-item").contains("Settings").click()
if (published == true) { cy.get(".spectrum-Tabs-item.is-selected").contains("Settings")
// Should not have Edit as option, will unpublish app cy.get(".settings-tab").should("be.visible")
cy.should("not.have.value", "Edit") cy.get(".details-section .page-action button")
cy.get(interact.SPECTRUM_MENU).contains("Unpublish").click() .contains("Edit")
cy.get(interact.SPECTRUM_DIALOG_GRID).contains("Unpublish app").click() .click({ force: true })
cy.get(".appTable > :nth-child(5) > :nth-child(2) > .spectrum-Icon").click()
}
cy.get(interact.APP_ROW_ACTION_MENU_POPOVER).eq(0).within(() => {
cy.get(interact.SPECTRUM_MENU_ITEMM).contains("Edit").click({ force: true })
})
cy.updateAppName(changedName, noName) cy.updateAppName(changedName, noName)
} }
}) })
}) })

View File

@ -144,20 +144,27 @@ Cypress.Commands.add("deleteApp", name => {
return return
} }
// Go to app overview
const appIdParsed = appId.split("_").pop() const appIdParsed = appId.split("_").pop()
const actionEleId = `[data-cy=row_actions_${appIdParsed}]` const actionEleId = `[data-cy=row_actions_${appIdParsed}]`
cy.get(actionEleId).within(() => { cy.get(actionEleId).within(() => {
cy.get(".spectrum-Icon").eq(0).click({ force: true }) cy.contains("Manage").click({ force: true })
})
cy.wait(1000)
// Unpublish first if needed
cy.get(`[data-cy="app-status"]`).then($status => {
if ($status.text().includes("Last published")) {
cy.contains("Unpublish").click()
cy.get(".spectrum-Modal").within(() => {
cy.contains("Unpublish app").click()
}) })
cy.get(".spectrum-Menu").then($menu => {
if ($menu.text().includes("Unpublish")) {
cy.get(".spectrum-Menu").contains("Unpublish").click()
cy.get(".spectrum-Dialog-grid").contains("Unpublish app").click()
} }
}) })
cy.get(actionEleId).within(() => { // Delete app
cy.get(".spectrum-Icon").eq(0).click({ force: true }) cy.get(".app-overview-actions-icon").within(() => {
cy.get(".spectrum-Icon").click({ force: true })
}) })
cy.get(".spectrum-Menu").contains("Delete").click() cy.get(".spectrum-Menu").contains("Delete").click()
cy.get(".spectrum-Dialog-grid").within(() => { cy.get(".spectrum-Dialog-grid").within(() => {
@ -180,17 +187,7 @@ Cypress.Commands.add("deleteAllApps", () => {
.its("body") .its("body")
.then(val => { .then(val => {
for (let i = 0; i < val.length; i++) { for (let i = 0; i < val.length; i++) {
const appIdParsed = val[i].appId.split("_").pop() cy.deleteApp(val[i].name)
const actionEleId = `[data-cy=row_actions_${appIdParsed}]`
cy.get(actionEleId).within(() => {
cy.get(".spectrum-Icon").eq(0).click({ force: true })
})
cy.get(".spectrum-Menu").contains("Delete").click()
cy.get(".spectrum-Dialog-grid").within(() => {
cy.get("input").type(val[i].name)
cy.get(".spectrum-Button--warning").click()
})
cy.reload() cy.reload()
} }
}) })

View File

@ -87,7 +87,7 @@
{#if lockedByYou && getExpiryDuration(app) > 0} {#if lockedByYou && getExpiryDuration(app) > 0}
<span class="lock-expiry-body"> <span class="lock-expiry-body">
{processStringSync( {processStringSync(
"This lock will expire in {{ duration time 'millisecond' }} from now", "This lock will expire in {{ duration time 'millisecond' }} from now.",
{ {
time: getExpiryDuration(app), time: getExpiryDuration(app),
} }
@ -141,4 +141,8 @@
gap: var(--spacing-s); gap: var(--spacing-s);
max-width: 175px; max-width: 175px;
} }
.lock-status-text {
font-weight: 400;
color: var(--spectrum-global-color-gray-800);
}
</style> </style>

View File

@ -1,18 +1,11 @@
<script> <script>
import { Heading, Button, Icon, ActionMenu, MenuItem } from "@budibase/bbui" import { Heading, Button, Icon } from "@budibase/bbui"
import AppLockModal from "../common/AppLockModal.svelte" import AppLockModal from "../common/AppLockModal.svelte"
import { processStringSync } from "@budibase/string-templates" import { processStringSync } from "@budibase/string-templates"
export let app export let app
export let exportApp
export let editApp export let editApp
export let updateApp
export let deleteApp
export let unpublishApp
export let appOverview export let appOverview
export let releaseLock
export let editIcon
export let copyAppId
</script> </script>
<div class="title" data-cy={`${app.devId}`}> <div class="title" data-cy={`${app.devId}`}>
@ -20,7 +13,7 @@
<div class="app-icon" style="color: {app.icon?.color || ''}"> <div class="app-icon" style="color: {app.icon?.color || ''}">
<Icon size="XL" name={app.icon?.name || "Apps"} /> <Icon size="XL" name={app.icon?.name || "Apps"} />
</div> </div>
<div class="name" data-cy="app-name-link" on:click={() => appOverview(app)}> <div class="name" data-cy="app-name-link" on:click={() => editApp(app)}>
<Heading size="XS"> <Heading size="XS">
{app.name} {app.name}
</Heading> </Heading>
@ -37,7 +30,7 @@
{/if} {/if}
</div> </div>
<div class="desktop"> <div class="desktop">
<AppLockModal {app} buttonSize="S" /> <AppLockModal {app} buttonSize="M" />
</div> </div>
<div class="desktop"> <div class="desktop">
<div class="app-status"> <div class="app-status">
@ -52,47 +45,27 @@
</div> </div>
<div data-cy={`row_actions_${app.appId}`}> <div data-cy={`row_actions_${app.appId}`}>
<div class="app-row-actions"> <div class="app-row-actions">
<Button size="S" secondary newStyles on:click={() => appOverview(app)}>
Manage
</Button>
<Button <Button
size="S" size="S"
secondary primary
quiet newStyles
disabled={app.lockedOther} disabled={app.lockedOther}
on:click={() => editApp(app)} on:click={() => editApp(app)}
>Edit >
Edit
</Button> </Button>
<Button size="S" cta on:click={() => appOverview(app)}>View</Button>
</div> </div>
<ActionMenu align="right" dataCy="app-row-actions-menu-popover">
<span slot="control" class="app-row-actions-icon">
<Icon hoverable name="More" />
</span>
{#if app.lockedYou}
<MenuItem on:click={() => releaseLock(app)} icon="LockOpen">
Release lock
</MenuItem>
{/if}
<MenuItem on:click={() => exportApp(app)} icon="Download">Export</MenuItem>
{#if app.deployed}
<MenuItem on:click={() => unpublishApp(app)} icon="GlobeRemove">
Unpublish
</MenuItem>
<MenuItem on:click={() => copyAppId(app)} icon="Copy">
Copy App ID
</MenuItem>
{/if}
{#if !app.deployed}
<MenuItem on:click={() => updateApp(app)} icon="Edit">Edit</MenuItem>
<MenuItem on:click={() => deleteApp(app)} icon="Delete">Delete</MenuItem>
{/if}
<MenuItem on:click={() => editIcon(app)} icon="Brush">Edit icon</MenuItem>
</ActionMenu>
</div> </div>
<style> <style>
.app-row-actions { .app-row-actions {
grid-gap: var(--spacing-s); grid-gap: var(--spacing-s);
display: grid; display: flex;
grid-template-columns: 75px 75px; flex-direction: row;
justify-content: flex-end;
} }
.app-status { .app-status {
display: grid; display: grid;

View File

@ -3,20 +3,17 @@
Heading, Heading,
Layout, Layout,
Button, Button,
Input,
Select, Select,
Modal, Modal,
Page, Page,
notifications, notifications,
Body, Body,
Search, Search,
Helpers,
} from "@budibase/bbui" } from "@budibase/bbui"
import TemplateDisplay from "components/common/TemplateDisplay.svelte" import TemplateDisplay from "components/common/TemplateDisplay.svelte"
import Spinner from "components/common/Spinner.svelte" import Spinner from "components/common/Spinner.svelte"
import CreateAppModal from "components/start/CreateAppModal.svelte" import CreateAppModal from "components/start/CreateAppModal.svelte"
import UpdateAppModal from "components/start/UpdateAppModal.svelte" import UpdateAppModal from "components/start/UpdateAppModal.svelte"
import ChooseIconModal from "components/start/ChooseIconModal.svelte"
import ExportAppModal from "components/start/ExportAppModal.svelte" import ExportAppModal from "components/start/ExportAppModal.svelte"
import { store, automationStore } from "builderStore" import { store, automationStore } from "builderStore"
@ -25,10 +22,8 @@
import { apps, auth, admin, templates } from "stores/portal" import { apps, auth, admin, templates } from "stores/portal"
import download from "downloadjs" import download from "downloadjs"
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import AppRow from "components/start/AppRow.svelte" import AppRow from "components/start/AppRow.svelte"
import { AppStatus } from "constants" import { AppStatus } from "constants"
import analytics, { Events, EventSource } from "analytics"
import Logo from "assets/bb-space-man.svg" import Logo from "assets/bb-space-man.svg"
let sortBy = "name" let sortBy = "name"
@ -36,15 +31,11 @@
let selectedApp let selectedApp
let creationModal let creationModal
let updatingModal let updatingModal
let deletionModal
let unpublishModal
let exportModal let exportModal
let iconModal
let creatingApp = false let creatingApp = false
let loaded = $apps?.length || $templates?.length let loaded = $apps?.length || $templates?.length
let searchTerm = "" let searchTerm = ""
let cloud = $admin.cloud let cloud = $admin.cloud
let appName = ""
let creatingFromTemplate = false let creatingFromTemplate = false
const resolveWelcomeMessage = (auth, apps) => { const resolveWelcomeMessage = (auth, apps) => {
@ -164,18 +155,6 @@
creatingApp = false creatingApp = false
} }
const viewApp = app => {
analytics.captureEvent(Events.APP_VIEW_PUBLISHED, {
appId: app.appId,
eventSource: EventSource.PORTAL,
})
if (app.url) {
window.open(`/app${app.url}`)
} else {
window.open(`/${app.prodId}`)
}
}
const appOverview = app => { const appOverview = app => {
$goto(`../overview/${app.devId}`) $goto(`../overview/${app.devId}`)
} }
@ -190,76 +169,6 @@
$goto(`../../app/${app.devId}`) $goto(`../../app/${app.devId}`)
} }
const editIcon = app => {
selectedApp = app
iconModal.show()
}
const exportApp = app => {
exportModal.show()
selectedApp = app
}
const unpublishApp = app => {
selectedApp = app
unpublishModal.show()
}
const confirmUnpublishApp = async () => {
if (!selectedApp) {
return
}
try {
await API.unpublishApp(selectedApp.prodId)
await apps.load()
notifications.success("App unpublished successfully")
} catch (err) {
notifications.error("Error unpublishing app")
}
}
const deleteApp = app => {
selectedApp = app
deletionModal.show()
}
const confirmDeleteApp = async () => {
if (!selectedApp) {
return
}
try {
await API.deleteApp(selectedApp?.devId)
await apps.load()
// Get checklist, just in case that was the last app
await admin.init()
notifications.success("App deleted successfully")
} catch (err) {
notifications.error("Error deleting app")
}
selectedApp = null
appName = null
}
const updateApp = async app => {
selectedApp = app
updatingModal.show()
}
const releaseLock = async app => {
try {
await API.releaseAppLock(app.devId)
await apps.load()
notifications.success("Lock released successfully")
} catch (err) {
notifications.error("Error releasing lock")
}
}
const copyAppId = async app => {
await Helpers.copyToClipboard(app.prodId)
notifications.success("App ID copied to clipboard.")
}
function createAppFromTemplateUrl(templateKey) { function createAppFromTemplateUrl(templateKey) {
// validate the template key just to make sure // validate the template key just to make sure
const templateParts = templateKey.split("/") const templateParts = templateKey.split("/")
@ -407,19 +316,7 @@
<div class="appTable" class:unlocked> <div class="appTable" class:unlocked>
{#each filteredApps as app (app.appId)} {#each filteredApps as app (app.appId)}
<AppRow <AppRow {app} {editApp} {appOverview} />
{copyAppId}
{releaseLock}
{editIcon}
{app}
{unpublishApp}
{viewApp}
{editApp}
{exportApp}
{deleteApp}
{updateApp}
{appOverview}
/>
{/each} {/each}
</div> </div>
</Layout> </Layout>
@ -453,35 +350,6 @@
<ExportAppModal app={selectedApp} /> <ExportAppModal app={selectedApp} />
</Modal> </Modal>
<ConfirmDialog
bind:this={deletionModal}
title="Confirm deletion"
okText="Delete app"
onOk={confirmDeleteApp}
onCancel={() => (appName = null)}
disabled={appName !== selectedApp?.name}
>
Are you sure you want to delete the app <b>{selectedApp?.name}</b>?
<p>Please enter the app name below to confirm.</p>
<Input
bind:value={appName}
data-cy="delete-app-confirmation"
placeholder={selectedApp?.name}
/>
</ConfirmDialog>
<ConfirmDialog
bind:this={unpublishModal}
title="Confirm unpublish"
okText="Unpublish app"
onOk={confirmUnpublishApp}
dataCy={"unpublish-modal"}
>
Are you sure you want to unpublish the app <b>{selectedApp?.name}</b>?
</ConfirmDialog>
<ChooseIconModal app={selectedApp} bind:this={iconModal} />
<style> <style>
.appTable { .appTable {
border-top: var(--border-light); border-top: var(--border-light);
@ -538,12 +406,9 @@
height: 70px; height: 70px;
display: grid; display: grid;
align-items: center; align-items: center;
grid-gap: var(--spacing-xl);
grid-template-columns: auto 1fr;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
padding: 0 var(--spacing-s);
} }
.appTable :global(> div) { .appTable :global(> div) {
border-bottom: var(--border-light); border-bottom: var(--border-light);

View File

@ -51,7 +51,7 @@
bind:value={$email} bind:value={$email}
error={$touched && $error} error={$touched && $error}
/> />
<Input disabled label="Password" value={password} /> <Input readonly label="Password" value={password} />
<div> <div>
<div class="toggle"> <div class="toggle">
<Label size="L">Development access</Label> <Label size="L">Development access</Label>

View File

@ -97,7 +97,7 @@ exports.externalTrigger = async function (
// values are likely to be submitted as strings, so we shall convert to correct type // values are likely to be submitted as strings, so we shall convert to correct type
const coercedFields = {} const coercedFields = {}
const fields = automation.definition.trigger.inputs.fields const fields = automation.definition.trigger.inputs.fields
for (let key of Object.keys(fields)) { for (let key of Object.keys(fields || {})) {
coercedFields[key] = coerce(params.fields[key], fields[key]) coercedFields[key] = coerce(params.fields[key], fields[key])
} }
params.fields = coercedFields params.fields = coercedFields