diff --git a/lerna.json b/lerna.json index 9c5a6c6bab..16dc73aa30 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.24.2", + "version": "2.25.0", "npmClient": "yarn", "packages": [ "packages/*", diff --git a/packages/backend-core/src/db/couch/DatabaseImpl.ts b/packages/backend-core/src/db/couch/DatabaseImpl.ts index d220d0a8ac..ef351f7d4d 100644 --- a/packages/backend-core/src/db/couch/DatabaseImpl.ts +++ b/packages/backend-core/src/db/couch/DatabaseImpl.ts @@ -3,11 +3,11 @@ import { AllDocsResponse, AnyDocument, Database, - DatabaseOpts, - DatabaseQueryOpts, - DatabasePutOpts, DatabaseCreateIndexOpts, DatabaseDeleteIndexOpts, + DatabaseOpts, + DatabasePutOpts, + DatabaseQueryOpts, Document, isDocument, RowResponse, @@ -17,7 +17,7 @@ import { import { getCouchInfo } from "./connections" import { directCouchUrlCall } from "./utils" import { getPouchDB } from "./pouchDB" -import { WriteStream, ReadStream } from "fs" +import { ReadStream, WriteStream } from "fs" import { newid } from "../../docIds/newid" import { SQLITE_DESIGN_DOC_ID } from "../../constants" import { DDInstrumentedDatabase } from "../instrumentation" @@ -38,6 +38,39 @@ function buildNano(couchInfo: { url: string; cookie: string }) { type DBCall = () => Promise +class CouchDBError extends Error { + status: number + statusCode: number + reason: string + name: string + errid: string + error: string + description: string + + constructor( + message: string, + info: { + status: number | undefined + statusCode: number | undefined + name: string + errid: string + description: string + reason: string + error: string + } + ) { + super(message) + const statusCode = info.status || info.statusCode || 500 + this.status = statusCode + this.statusCode = statusCode + this.reason = info.reason + this.name = info.name + this.errid = info.errid + this.description = info.description + this.error = info.error + } +} + export function DatabaseWithConnection( dbName: string, connection: string, @@ -119,7 +152,7 @@ export class DatabaseImpl implements Database { } catch (err: any) { // Handling race conditions if (err.statusCode !== 412) { - throw err + throw new CouchDBError(err.message, err) } } } @@ -138,10 +171,9 @@ export class DatabaseImpl implements Database { if (err.statusCode === 404 && err.reason === DATABASE_NOT_FOUND) { await this.checkAndCreateDb() return await this.performCall(call) - } else if (err.statusCode) { - err.status = err.statusCode } - throw err + // stripping the error down the props which are safe/useful, drop everything else + throw new CouchDBError(`CouchDB error: ${err.message}`, err) } } @@ -288,7 +320,7 @@ export class DatabaseImpl implements Database { if (err.statusCode === 404) { return } else { - throw { ...err, status: err.statusCode } + throw new CouchDBError(err.message, err) } } } diff --git a/packages/bbui/src/FancyForm/FancyInput.svelte b/packages/bbui/src/FancyForm/FancyInput.svelte index 0c58b9b045..f665fa5724 100644 --- a/packages/bbui/src/FancyForm/FancyInput.svelte +++ b/packages/bbui/src/FancyForm/FancyInput.svelte @@ -11,6 +11,7 @@ export let error = null export let validate = null export let suffix = null + export let validateOn = "change" const dispatch = createEventDispatcher() @@ -24,7 +25,16 @@ const newValue = e.target.value dispatch("change", newValue) value = newValue - if (validate) { + if (validate && (error || validateOn === "change")) { + error = validate(newValue) + } + } + + const onBlur = e => { + focused = false + const newValue = e.target.value + dispatch("blur", newValue) + if (validate && validateOn === "blur") { error = validate(newValue) } } @@ -61,7 +71,7 @@ type={type || "text"} on:input={onChange} on:focus={() => (focused = true)} - on:blur={() => (focused = false)} + on:blur={onBlur} class:placeholder bind:this={ref} /> diff --git a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte index 81d5545c40..8f91796f6c 100644 --- a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte +++ b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte @@ -12,6 +12,7 @@ OptionSelectDnD, Layout, AbsTooltip, + ProgressCircle, } from "@budibase/bbui" import { SWITCHABLE_TYPES, ValidColumnNameRegex } from "@budibase/shared-core" import { createEventDispatcher, getContext, onMount } from "svelte" @@ -245,11 +246,11 @@ } async function saveColumn() { - savingColumn = true if (errors?.length) { return } + savingColumn = true let saveColumn = cloneDeep(editableColumn) delete saveColumn.fieldId @@ -289,6 +290,8 @@ } } catch (err) { notifications.error(`Error saving column: ${err.message}`) + } finally { + savingColumn = false } } @@ -739,7 +742,20 @@ {/if} - + diff --git a/packages/pro b/packages/pro index 479879246a..ff397e5454 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 479879246aac5dd3073cc695945c62c41fae5b0e +Subproject commit ff397e5454ad3361b25efdf14746c36dcbd3f409 diff --git a/packages/server/src/api/routes/tests/search.spec.ts b/packages/server/src/api/routes/tests/search.spec.ts index d036da646e..7a0e78eb1c 100644 --- a/packages/server/src/api/routes/tests/search.spec.ts +++ b/packages/server/src/api/routes/tests/search.spec.ts @@ -44,7 +44,7 @@ describe.each([ const snippets = [ { name: "WeeksAgo", - code: "return function (weeks) {\n const currentTime = new Date();\n currentTime.setDate(currentTime.getDate()-(7 * (weeks || 1)));\n return currentTime.toISOString();\n}", + code: `return function (weeks) {\n const currentTime = new Date(${Date.now()});\n currentTime.setDate(currentTime.getDate()-(7 * (weeks || 1)));\n return currentTime.toISOString();\n}`, }, ] diff --git a/packages/server/src/automations/tests/executeQuery.spec.ts b/packages/server/src/automations/tests/executeQuery.spec.ts index 996e44af79..5a0688276d 100644 --- a/packages/server/src/automations/tests/executeQuery.spec.ts +++ b/packages/server/src/automations/tests/executeQuery.spec.ts @@ -88,7 +88,7 @@ describe.each( let res = await setup.runStep(setup.actions.EXECUTE_QUERY.stepId, { query: { queryId: "wrong_id" }, }) - expect(res.response).toEqual("Error: missing") + expect(res.response).toEqual("Error: CouchDB error: missing") expect(res.success).toEqual(false) }) }) diff --git a/packages/server/src/integrations/googlesheets.ts b/packages/server/src/integrations/googlesheets.ts index 7215c337d7..889adfc544 100644 --- a/packages/server/src/integrations/googlesheets.ts +++ b/packages/server/src/integrations/googlesheets.ts @@ -371,9 +371,11 @@ class GoogleSheetsIntegration implements DatasourcePlus { } buildRowObject(headers: string[], values: string[], rowNumber: number) { - const rowObject: { rowNumber: number; [key: string]: any } = { rowNumber } + const rowObject: { rowNumber: number } & Row = { + rowNumber, + _id: rowNumber.toString(), + } for (let i = 0; i < headers.length; i++) { - rowObject._id = rowNumber rowObject[headers[i]] = values[i] } return rowObject @@ -430,14 +432,6 @@ class GoogleSheetsIntegration implements DatasourcePlus { } } - // clear out deleted columns - for (let key of sheet.headerValues) { - if (!Object.keys(table.schema).includes(key)) { - const idx = updatedHeaderValues.indexOf(key) - updatedHeaderValues.splice(idx, 1) - } - } - try { await sheet.setHeaderRow(updatedHeaderValues) } catch (err) { @@ -458,7 +452,7 @@ class GoogleSheetsIntegration implements DatasourcePlus { } } - async create(query: { sheet: string; row: any }) { + async create(query: { sheet: string; row: Row }) { try { await this.connect() const sheet = this.client.sheetsByTitle[query.sheet] @@ -474,7 +468,7 @@ class GoogleSheetsIntegration implements DatasourcePlus { } } - async createBulk(query: { sheet: string; rows: any[] }) { + async createBulk(query: { sheet: string; rows: Row[] }) { try { await this.connect() const sheet = this.client.sheetsByTitle[query.sheet] diff --git a/packages/server/src/integrations/tests/googlesheets.spec.ts b/packages/server/src/integrations/tests/googlesheets.spec.ts index c6e073d602..97ac35787d 100644 --- a/packages/server/src/integrations/tests/googlesheets.spec.ts +++ b/packages/server/src/integrations/tests/googlesheets.spec.ts @@ -129,10 +129,11 @@ describe("Google Sheets Integration", () => { }) expect(sheet.loadHeaderRow).toHaveBeenCalledTimes(1) expect(sheet.setHeaderRow).toHaveBeenCalledTimes(1) - expect(sheet.setHeaderRow).toHaveBeenCalledWith(["name"]) - - // No undefined are sent - expect((sheet.setHeaderRow as any).mock.calls[0][0]).toHaveLength(1) + expect(sheet.setHeaderRow).toHaveBeenCalledWith([ + "name", + "description", + "location", + ]) }) })