From 23d10e1949fa092c88ac30423c44a5e2b4bf6c77 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 22 Feb 2021 15:49:57 +0000 Subject: [PATCH 01/18] Fixing issue - this will replace any bindings when copying and pasting a stack of components with 'Invalid binding'. --- packages/builder/src/builderStore/dataBinding.js | 15 +++++++++++++++ .../builder/src/builderStore/store/frontend.js | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/packages/builder/src/builderStore/dataBinding.js b/packages/builder/src/builderStore/dataBinding.js index b2eb30c55a..858bfa8801 100644 --- a/packages/builder/src/builderStore/dataBinding.js +++ b/packages/builder/src/builderStore/dataBinding.js @@ -7,6 +7,7 @@ import { TableNames } from "../constants" // Regex to match all instances of template strings const CAPTURE_VAR_INSIDE_TEMPLATE = /{{([^}]+)}}/g +const CAPTURE_HBS_TEMPLATE = /{{[\S\s]*?}}/g /** * Gets all bindable data context fields and instance fields. @@ -273,6 +274,20 @@ const buildFormSchema = component => { return schema } +/** + * Recurses the input object to remove any instances of bindings. + */ +export function removeBindings(obj) { + for (let [key, value] of Object.entries(obj)) { + if (typeof value === "object") { + obj[key] = removeBindings(value) + } else if (typeof value === "string") { + obj[key] = value.replace(CAPTURE_HBS_TEMPLATE, "Invalid binding") + } + } + return obj +} + /** * utility function for the readableToRuntimeBinding and runtimeToReadableBinding. */ diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index 27427c6ef0..51ed83266a 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -15,6 +15,7 @@ import { FrontendTypes } from "constants" import analytics from "analytics" import { findComponentType, findComponentParent } from "../storeUtils" import { uuid } from "../uuid" +import { removeBindings } from "../dataBinding" const INITIAL_FRONTEND_STATE = { apps: [], @@ -408,6 +409,9 @@ export const getFrontendStore = () => { return state } + // immediately need to remove bindings, currently these aren't valid when pasted + state.componentToPaste = removeBindings(state.componentToPaste) + // Clone the component to paste // Retain the same ID if cutting as things may be referencing this component const cut = state.componentToPaste.isCut From 820fe9c9a59dcf7ebfec854ac560ed155a321ed4 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 22 Feb 2021 15:53:49 +0000 Subject: [PATCH 02/18] Adding prettier ignore statement as it kept re-formatting the spacing in query viewer file. --- .../builder/src/components/integration/QueryViewer.svelte | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/builder/src/components/integration/QueryViewer.svelte b/packages/builder/src/components/integration/QueryViewer.svelte index fe8f7a7687..14123a1a9d 100644 --- a/packages/builder/src/components/integration/QueryViewer.svelte +++ b/packages/builder/src/components/integration/QueryViewer.svelte @@ -204,7 +204,9 @@ {#if data} {#if tab === 'JSON'} -
+              
+                
                 {#if !data[0]}
                   
                   Please run your query to fetch some data.

From 64cfc02fa282dd73467694a65026c2bb5a0c713c Mon Sep 17 00:00:00 2001
From: mike12345567 
Date: Mon, 22 Feb 2021 16:10:29 +0000
Subject: [PATCH 03/18] Adding fix in for views including internal views which
 shouldn't be added to view calculation.

---
 .../server/src/api/controllers/deploy/quota.js | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/packages/server/src/api/controllers/deploy/quota.js b/packages/server/src/api/controllers/deploy/quota.js
index 4e4c869670..130ceaa3b9 100644
--- a/packages/server/src/api/controllers/deploy/quota.js
+++ b/packages/server/src/api/controllers/deploy/quota.js
@@ -1,5 +1,12 @@
 const PouchDB = require("../../../db")
-const { DocumentTypes, SEPARATOR, UNICODE_MAX } = require("../../../db/utils")
+const {
+  DocumentTypes,
+  SEPARATOR,
+  UNICODE_MAX,
+  ViewNames,
+} = require("../../../db/utils")
+
+const EXCLUDED_VIEWS = [ViewNames.USERS, ViewNames.LINK, ViewNames.ROUTING]
 
 exports.getAppQuota = async function(appId) {
   const db = new PouchDB(appId)
@@ -19,9 +26,16 @@ exports.getAppQuota = async function(appId) {
 
   const designDoc = await db.get("_design/database")
 
+  let views = 0
+  for (let viewName of Object.keys(designDoc.views)) {
+    if (EXCLUDED_VIEWS.indexOf(viewName) === -1) {
+      views++
+    }
+  }
+
   return {
     rows: existingRows,
     users: existingUsers,
-    views: Object.keys(designDoc.views).length,
+    views: views,
   }
 }

From ed2672fca3ee1f6f038afdfb236829ab3e5c6b6f Mon Sep 17 00:00:00 2001
From: mike12345567 
Date: Mon, 22 Feb 2021 16:13:11 +0000
Subject: [PATCH 04/18] Quick change to make sure as long as internal views are
 denoted in the db constant they'll be handled.

---
 packages/server/src/api/controllers/deploy/quota.js | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/packages/server/src/api/controllers/deploy/quota.js b/packages/server/src/api/controllers/deploy/quota.js
index 130ceaa3b9..5e8880c7a9 100644
--- a/packages/server/src/api/controllers/deploy/quota.js
+++ b/packages/server/src/api/controllers/deploy/quota.js
@@ -6,8 +6,6 @@ const {
   ViewNames,
 } = require("../../../db/utils")
 
-const EXCLUDED_VIEWS = [ViewNames.USERS, ViewNames.LINK, ViewNames.ROUTING]
-
 exports.getAppQuota = async function(appId) {
   const db = new PouchDB(appId)
 
@@ -28,7 +26,7 @@ exports.getAppQuota = async function(appId) {
 
   let views = 0
   for (let viewName of Object.keys(designDoc.views)) {
-    if (EXCLUDED_VIEWS.indexOf(viewName) === -1) {
+    if (Object.values(ViewNames).indexOf(viewName) === -1) {
       views++
     }
   }

From bc5e88bceb994779c4c0c6f95d7a7dfd61048607 Mon Sep 17 00:00:00 2001
From: Andrew Kingston 
Date: Tue, 23 Feb 2021 10:02:21 +0000
Subject: [PATCH 05/18] Make heading respect white space and reduce default
 margin

---
 .../standard-components/src/Heading.svelte    | 25 +++++++++++++------
 1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/packages/standard-components/src/Heading.svelte b/packages/standard-components/src/Heading.svelte
index 66775dc666..bf38ecf06e 100644
--- a/packages/standard-components/src/Heading.svelte
+++ b/packages/standard-components/src/Heading.svelte
@@ -4,21 +4,32 @@
   const { styleable } = getContext("sdk")
   const component = getContext("component")
 
-  export let className = ""
   export let type
   export let text = ""
 
 
 {#if type === 'h1'}
-  

{text}

+

{text}

{:else if type === 'h2'} -

{text}

+

{text}

{:else if type === 'h3'} -

{text}

+

{text}

{:else if type === 'h4'} -

{text}

+

{text}

{:else if type === 'h5'} -
{text}
+
{text}
{:else if type === 'h6'} -
{text}
+
{text}
{/if} + + From dcaacab477ad586d8eef2f2f84c0da7b75bf6ee2 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 23 Feb 2021 10:03:52 +0000 Subject: [PATCH 06/18] Revert heading margin change to use browser default --- packages/standard-components/src/Heading.svelte | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/standard-components/src/Heading.svelte b/packages/standard-components/src/Heading.svelte index bf38ecf06e..f06ac86afd 100644 --- a/packages/standard-components/src/Heading.svelte +++ b/packages/standard-components/src/Heading.svelte @@ -29,7 +29,6 @@ h4, h5, h6 { - margin: 0.5em 0; white-space: pre-wrap; } From d3e4921f297abdf7e3c84a3aec994e7fc8240210 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 23 Feb 2021 10:04:07 +0000 Subject: [PATCH 07/18] Make paragraph respect whitespace --- packages/standard-components/src/Text.svelte | 31 ++------------------ 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/packages/standard-components/src/Text.svelte b/packages/standard-components/src/Text.svelte index 887bdec29d..ab62352694 100644 --- a/packages/standard-components/src/Text.svelte +++ b/packages/standard-components/src/Text.svelte @@ -5,38 +5,13 @@ const component = getContext("component") export let text = "" - export let className = "" - export let type = "" - - const isTag = tag => type === tag -{#if isTag('none')} - {text} -{:else if isTag('bold')} - {text} -{:else if isTag('strong')} - {text} -{:else if isTag('italic')} - {text} -{:else if isTag('emphasis')} - {text} -{:else if isTag('mark')} - {text} -{:else if isTag('small')} - {text} -{:else if isTag('del')} - {text} -{:else if isTag('ins')} - {text} -{:else if isTag('sub')} - {text} -{:else if isTag('sup')} - {text} -{:else}{text}{/if} +

{text}

From 3c3677a88ee160b8d29a6b211c9b7fc35e40e861 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Tue, 23 Feb 2021 10:06:55 +0000 Subject: [PATCH 08/18] allow empty params --- packages/server/src/api/routes/query.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/api/routes/query.js b/packages/server/src/api/routes/query.js index 4266cf6bdc..55223e4e9e 100644 --- a/packages/server/src/api/routes/query.js +++ b/packages/server/src/api/routes/query.js @@ -27,7 +27,7 @@ function generateQueryValidation() { readable: Joi.boolean(), parameters: Joi.array().items(Joi.object({ name: Joi.string(), - default: Joi.string() + default: Joi.string().allow(""), })), queryVerb: Joi.string().allow().required(), schema: Joi.object({}).required().unknown(true) From 56bbaba44e5213d36df08c2cd1d18eeba310859f Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 23 Feb 2021 10:14:54 +0000 Subject: [PATCH 09/18] Update vertical card to preserve white space and fix crashing when a URL isn't entered --- packages/standard-components/src/Card.svelte | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/standard-components/src/Card.svelte b/packages/standard-components/src/Card.svelte index 33be4185f7..85f30c5a09 100644 --- a/packages/standard-components/src/Card.svelte +++ b/packages/standard-components/src/Card.svelte @@ -40,7 +40,7 @@ + href={linkUrl || '/'}> {linkText} @@ -71,6 +71,7 @@ font-size: 1.25rem; font-weight: 700; margin: 0; + white-space: pre-wrap; } .text { @@ -78,6 +79,7 @@ margin: 0; font-weight: 400; line-height: 1.5rem; + white-space: pre-wrap; } a { @@ -85,6 +87,7 @@ text-decoration: none; color: var(--linkColor); font-weight: 600; + white-space: pre-wrap; } a:hover { From d5a37c535e3dec35eaad4b4d87a61aba8003ca72 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 23 Feb 2021 10:15:16 +0000 Subject: [PATCH 10/18] Update horizontal card to preserve white space and fix crashing when a URL isn't entered --- packages/standard-components/src/CardHorizontal.svelte | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/standard-components/src/CardHorizontal.svelte b/packages/standard-components/src/CardHorizontal.svelte index 5d7596e296..523d796cf5 100644 --- a/packages/standard-components/src/CardHorizontal.svelte +++ b/packages/standard-components/src/CardHorizontal.svelte @@ -40,7 +40,7 @@

{subtext}

{linkText} + href={linkUrl || '/'}>{linkText} @@ -71,6 +71,7 @@ font-size: 1rem; font-weight: 700; margin: 0; + white-space: pre-wrap; } .text { @@ -78,6 +79,7 @@ margin: 0.5rem 0 0 0; font-weight: 400; line-height: 1.25rem; + white-space: pre-wrap; } footer { @@ -91,6 +93,7 @@ margin: 0; font-weight: 400; color: #757575; + white-space: pre-wrap; } a { @@ -99,7 +102,7 @@ color: var(--linkColor); font-weight: 600; font-size: 0.85rem; - margin: 0; + white-space: pre-wrap; } a:hover { From 8ed2be55945c5cc1c76282a029ec316db4415513 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 23 Feb 2021 10:15:40 +0000 Subject: [PATCH 11/18] Update card stat to preserve white space --- packages/standard-components/src/CardStat.svelte | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/standard-components/src/CardStat.svelte b/packages/standard-components/src/CardStat.svelte index e5e40ad862..86291db915 100644 --- a/packages/standard-components/src/CardStat.svelte +++ b/packages/standard-components/src/CardStat.svelte @@ -20,7 +20,6 @@ .container { min-width: 260px; width: max-content; - max-height: 170px; border: 1px solid var(--grey-3); border-radius: 0.3rem; color: var(--blue); @@ -31,6 +30,7 @@ color: #9e9e9e; font-weight: 500; margin: 1rem 1.5rem 0.5rem 1.5rem; + white-space: pre-wrap; } .value { @@ -38,6 +38,7 @@ font-weight: 500; margin: 0 1.5rem 1.5rem 1.5rem; color: inherit; + white-space: pre-wrap; } .label { @@ -45,5 +46,6 @@ font-weight: 400; color: #9e9e9e; margin: 1rem 1.5rem; + white-space: pre-wrap; } From aaa40f4638fe21f4ff48308d064cde9ede08c945 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 23 Feb 2021 10:15:51 +0000 Subject: [PATCH 12/18] Update stacked list to preserve white space --- packages/standard-components/src/StackedList.svelte | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/standard-components/src/StackedList.svelte b/packages/standard-components/src/StackedList.svelte index b06ce53ebe..3cf70b2ec1 100644 --- a/packages/standard-components/src/StackedList.svelte +++ b/packages/standard-components/src/StackedList.svelte @@ -50,6 +50,7 @@ .subheading { opacity: 0.6; + white-space: pre-wrap; } .content { @@ -60,6 +61,7 @@ .heading { font-weight: 600; + white-space: pre-wrap; } .image-block { From ab136e248afc905dc789d1cdbfc1d024ccbc307b Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 23 Feb 2021 10:26:37 +0000 Subject: [PATCH 13/18] Only performing the change on copies, allowing cuts through. --- packages/builder/src/builderStore/store/frontend.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index 51ed83266a..7edc378900 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -409,12 +409,16 @@ export const getFrontendStore = () => { return state } + // defines if this is a copy or a cut + const cut = state.componentToPaste.isCut + // immediately need to remove bindings, currently these aren't valid when pasted - state.componentToPaste = removeBindings(state.componentToPaste) + if (!cut) { + state.componentToPaste = removeBindings(state.componentToPaste) + } // Clone the component to paste // Retain the same ID if cutting as things may be referencing this component - const cut = state.componentToPaste.isCut delete state.componentToPaste.isCut let componentToPaste = cloneDeep(state.componentToPaste) if (cut) { From 009bf3755692af0085149b126e3f857b942844e7 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 23 Feb 2021 10:33:26 +0000 Subject: [PATCH 14/18] Show error when trying to create user with a duplicate email address --- .../DataTable/modals/CreateEditUser.svelte | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/builder/src/components/backend/DataTable/modals/CreateEditUser.svelte b/packages/builder/src/components/backend/DataTable/modals/CreateEditUser.svelte index 5753b7d5bb..6467b8e953 100644 --- a/packages/builder/src/components/backend/DataTable/modals/CreateEditUser.svelte +++ b/packages/builder/src/components/backend/DataTable/modals/CreateEditUser.svelte @@ -34,11 +34,26 @@ } const saveRow = async () => { + errors = [] + + // Do some basic front end validation first + if (!row.email) { + errors = [...errors, { message: "Email is required" }] + } + if (!row.password) { + errors = [...errors, { message: "Password is required" }] + } + if (!row.roleId) { + errors = [...errors, { message: "Role is required" }] + } + if (errors.length) { + return false + } + const rowResponse = await backendApi.saveRow( { ...row, tableId: table._id }, table._id ) - if (rowResponse.errors) { if (Array.isArray(rowResponse.errors)) { errors = rowResponse.errors.map(error => ({ message: error })) @@ -48,6 +63,9 @@ .flat() } return false + } else if (rowResponse.status === 400 && rowResponse.message) { + errors = [{ message: rowResponse.message }] + return false } notifier.success("User saved successfully.") From 50f9663622091d01a43d013d44424738b279d3f3 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Tue, 23 Feb 2021 10:41:11 +0000 Subject: [PATCH 15/18] ensure error is thrown on client validation failure --- packages/builder/src/builderStore/store/backend.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/builder/src/builderStore/store/backend.js b/packages/builder/src/builderStore/store/backend.js index 6731aea51c..0a5b9f0461 100644 --- a/packages/builder/src/builderStore/store/backend.js +++ b/packages/builder/src/builderStore/store/backend.js @@ -135,6 +135,9 @@ export const getBackendUiStore = () => { } query.datasourceId = datasourceId const response = await api.post(`/api/queries`, query) + if (response.status !== 200) { + throw new Error("Failed saving query.") + } const json = await response.json() store.update(state => { const currentIdx = state.queries.findIndex( From 19566d9b7d7f6517075cae8f1749e546d0693ab9 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 23 Feb 2021 14:07:19 +0000 Subject: [PATCH 16/18] Add new automation trigger for updating rows --- packages/server/src/api/controllers/row.js | 1 - packages/server/src/automations/triggers.js | 55 +++++++++++++++++++-- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/packages/server/src/api/controllers/row.js b/packages/server/src/api/controllers/row.js index 43d831dc60..54f4e4508e 100644 --- a/packages/server/src/api/controllers/row.js +++ b/packages/server/src/api/controllers/row.js @@ -111,7 +111,6 @@ exports.patch = async function(ctx) { } row._rev = response.rev row.type = "row" - ctx.eventEmitter && ctx.eventEmitter.emitRow(`row:update`, appId, row, table) ctx.body = row ctx.status = 200 diff --git a/packages/server/src/automations/triggers.js b/packages/server/src/automations/triggers.js index e4c91e5610..fcdb8a7e83 100644 --- a/packages/server/src/automations/triggers.js +++ b/packages/server/src/automations/triggers.js @@ -13,11 +13,11 @@ const FAKE_DATETIME = "1970-01-01T00:00:00.000Z" const BUILTIN_DEFINITIONS = { ROW_SAVED: { - name: "Row Saved", + name: "Row Created", event: "row:save", icon: "ri-save-line", tagline: "Row is added to {{inputs.enriched.table.name}}", - description: "Fired when a row is saved to your database", + description: "Fired when a row is added to your database", stepId: "ROW_SAVED", inputs: {}, schema: { @@ -36,7 +36,47 @@ const BUILTIN_DEFINITIONS = { row: { type: "object", customType: "row", - description: "The new row that was saved", + description: "The new row that was created", + }, + id: { + type: "string", + description: "Row ID - can be used for updating", + }, + revision: { + type: "string", + description: "Revision of row", + }, + }, + required: ["row", "id"], + }, + }, + type: "TRIGGER", + }, + ROW_UPDATED: { + name: "Row Updated", + event: "row:update", + icon: "ri-save-line", + tagline: "Row is updated in {{inputs.enriched.table.name}}", + description: "Fired when a row is updated in your database", + stepId: "ROW_UPDATED", + inputs: {}, + schema: { + inputs: { + properties: { + tableId: { + type: "string", + customType: "table", + title: "Table", + }, + }, + required: ["tableId"], + }, + outputs: { + properties: { + row: { + type: "object", + customType: "row", + description: "The row that was updated", }, id: { type: "string", @@ -79,7 +119,7 @@ const BUILTIN_DEFINITIONS = { description: "The row that was deleted", }, }, - required: ["row", "id"], + required: ["row"], }, }, type: "TRIGGER", @@ -191,6 +231,13 @@ emitter.on("row:save", async function(event) { await queueRelevantRowAutomations(event, "row:save") }) +emitter.on("row:update", async function(event) { + if (!event || !event.row || !event.row.tableId) { + return + } + await queueRelevantRowAutomations(event, "row:update") +}) + emitter.on("row:delete", async function(event) { if (!event || !event.row || !event.row.tableId) { return From c47ef73a4a97948608312d5d8b15bd7fa2867ae7 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 23 Feb 2021 14:16:44 +0000 Subject: [PATCH 17/18] Update icon for row updated trigger --- packages/server/src/automations/triggers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/automations/triggers.js b/packages/server/src/automations/triggers.js index fcdb8a7e83..73ce9edeed 100644 --- a/packages/server/src/automations/triggers.js +++ b/packages/server/src/automations/triggers.js @@ -55,7 +55,7 @@ const BUILTIN_DEFINITIONS = { ROW_UPDATED: { name: "Row Updated", event: "row:update", - icon: "ri-save-line", + icon: "ri-refresh-line", tagline: "Row is updated in {{inputs.enriched.table.name}}", description: "Fired when a row is updated in your database", stepId: "ROW_UPDATED", From 2f78afac6d8d33264a7167aac083693777219199 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 23 Feb 2021 14:28:05 +0000 Subject: [PATCH 18/18] Fix cypress test --- .../integration/createAutomation.spec.js | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/builder/cypress/integration/createAutomation.spec.js b/packages/builder/cypress/integration/createAutomation.spec.js index 92d1f907bd..efc185be7c 100644 --- a/packages/builder/cypress/integration/createAutomation.spec.js +++ b/packages/builder/cypress/integration/createAutomation.spec.js @@ -17,23 +17,33 @@ context("Create a automation", () => { cy.get("[data-cy=new-automation]").click() cy.get(".modal").within(() => { cy.get("input").type("Add Row") - cy.get(".buttons").contains("Create").click() + cy.get(".buttons") + .contains("Create") + .click() }) // Add trigger cy.contains("Trigger").click() - cy.contains("Row Saved").click() + cy.contains("Row Created").click() cy.get(".setup").within(() => { - cy.get("select").first().select("dog") + cy.get("select") + .first() + .select("dog") }) // Create action cy.contains("Action").click() cy.contains("Create Row").click() cy.get(".setup").within(() => { - cy.get("select").first().select("dog") - cy.get("input").first().type("goodboy") - cy.get("input").eq(1).type("11") + cy.get("select") + .first() + .select("dog") + cy.get("input") + .first() + .type("goodboy") + cy.get("input") + .eq(1) + .type("11") }) // Save