From 33e2ee427d5a6e7384906c16aacf24e827ad4a63 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 12 Nov 2020 12:24:45 +0000 Subject: [PATCH] Replace all manual API interaction with SDK --- packages/component-sdk/src/api/api.js | 15 ++- packages/component-sdk/src/api/attachments.js | 12 ++ packages/component-sdk/src/api/datasources.js | 43 +------ packages/component-sdk/src/api/index.js | 5 + .../component-sdk/src/api/relationships.js | 4 +- packages/component-sdk/src/api/rows.js | 56 +++++++++ packages/component-sdk/src/api/tables.js | 6 +- packages/component-sdk/src/api/views.js | 12 +- packages/component-sdk/src/store/auth.js | 23 ++-- packages/component-sdk/src/store/config.js | 2 +- .../standard-components/src/DataList.svelte | 82 ------------- .../standard-components/src/DataSearch.svelte | 15 --- .../standard-components/src/IconOld.svelte | 9 -- .../src/LinkedRowSelector.svelte | 20 ++- packages/standard-components/src/List.svelte | 4 +- packages/standard-components/src/Login.svelte | 16 +-- packages/standard-components/src/Nav.svelte | 116 ------------------ .../standard-components/src/Navigation.svelte | 12 +- .../standard-components/src/NewRow.svelte | 9 +- .../standard-components/src/RowDetail.svelte | 59 +++------ packages/standard-components/src/Table.svelte | 77 ------------ .../standard-components/src/TableBody.svelte | 10 -- .../standard-components/src/TableHead.svelte | 10 -- .../src/attachments/Dropzone.svelte | 12 +- .../src/charts/BarChart.svelte | 13 +- .../src/charts/CandleStickChart.svelte | 6 +- .../src/charts/LineChart.svelte | 6 +- .../src/charts/PieChart.svelte | 6 +- .../src/grid/Component.svelte | 22 ++-- .../Relationship/RelationshipDisplay.svelte | 17 +-- .../src/grid/Relationship/tableCache.js | 20 --- packages/standard-components/src/index.js | 2 - 32 files changed, 188 insertions(+), 533 deletions(-) create mode 100644 packages/component-sdk/src/api/attachments.js delete mode 100644 packages/standard-components/src/DataList.svelte delete mode 100644 packages/standard-components/src/DataSearch.svelte delete mode 100644 packages/standard-components/src/IconOld.svelte delete mode 100644 packages/standard-components/src/Nav.svelte delete mode 100644 packages/standard-components/src/Table.svelte delete mode 100644 packages/standard-components/src/TableBody.svelte delete mode 100644 packages/standard-components/src/TableHead.svelte delete mode 100644 packages/standard-components/src/grid/Relationship/tableCache.js diff --git a/packages/component-sdk/src/api/api.js b/packages/component-sdk/src/api/api.js index e7cc5261e0..6cc643872a 100644 --- a/packages/component-sdk/src/api/api.js +++ b/packages/component-sdk/src/api/api.js @@ -11,7 +11,7 @@ let cache = {} * Makes a fully formatted URL based on the SDK configuration. */ const makeFullURL = path => { - const { proto, domain, port } = get(configStore).config + const { proto, domain, port } = get(configStore) let url = `/${path}`.replace("//", "/") return domain ? `${proto}://${domain}:${port}${url}` : url } @@ -28,15 +28,17 @@ const handleError = error => { * Performs an API call to the server. * App ID header is always correctly set. */ -const makeApiCall = async ({ method, url, body }) => { +const makeApiCall = async ({ method, url, body, json = true }) => { try { + const requestBody = json ? JSON.stringify(body) : body const response = await fetch(url, { method, headers: { + Accept: "application/json", "Content-Type": "application/json", "x-budibase-app-id": getAppId(window.document.cookie), }, - body: body && JSON.stringify(body), + body: requestBody, credentials: "same-origin", }) switch (response.status) { @@ -79,10 +81,11 @@ const makeCachedApiCall = async params => { /** * Constructs an API call function for a particular HTTP method. */ -const requestApiCall = method => async ({ url, body, cache = false }) => { +const requestApiCall = method => async params => { + const { url, cache = false } = params const fullURL = makeFullURL(url) - const params = { method, url: fullURL, body } - return await (cache ? makeCachedApiCall : makeApiCall)(params) + const enrichedParams = { ...params, method, url: fullURL } + return await (cache ? makeCachedApiCall : makeApiCall)(enrichedParams) } export default { diff --git a/packages/component-sdk/src/api/attachments.js b/packages/component-sdk/src/api/attachments.js new file mode 100644 index 0000000000..68bc7df415 --- /dev/null +++ b/packages/component-sdk/src/api/attachments.js @@ -0,0 +1,12 @@ +import api from "./api" + +/** + * Uploads an attachment to the server. + */ +export const uploadAttachment = async data => { + return await api.post({ + url: "/api/attachments/upload", + body: data, + json: false, + }) +} diff --git a/packages/component-sdk/src/api/datasources.js b/packages/component-sdk/src/api/datasources.js index acea8ab640..4c614b0085 100644 --- a/packages/component-sdk/src/api/datasources.js +++ b/packages/component-sdk/src/api/datasources.js @@ -1,20 +1,21 @@ -import { fetchTableData, fetchTableDefinition } from "./tables" +import { fetchTableData } from "./tables" import { fetchViewData } from "./views" import { fetchRelationshipData } from "./relationships" +import { enrichRows } from "./rows" /** * Fetches all rows for a particular Budibase data source. */ export const fetchDatasource = async datasource => { - if (!datasource || !datasource.name) { + if (!datasource || !datasource.type) { return [] } // Fetch all rows in data source - const { type, name, tableId } = datasource + const { type, tableId } = datasource let rows = [] if (type === "table") { - rows = await fetchTableData(name) + rows = await fetchTableData(tableId) } else if (type === "view") { rows = await fetchViewData(datasource) } else if (type === "link") { @@ -22,37 +23,5 @@ export const fetchDatasource = async datasource => { } // Enrich rows - return await enrichDatasourceRows(rows, tableId) -} - -/** - * Enriches data source rows which contain certain field types so that they can - * be properly displayed. - */ -const enrichDatasourceRows = async (rows, tableId) => { - if (rows && rows.length && tableId) { - // Fetch table schema so we can check column types - const tableDefinition = await fetchTableDefinition(tableId) - const schema = tableDefinition && tableDefinition.schema - if (schema) { - const keys = Object.keys(schema) - rows.forEach(row => { - for (let key of keys) { - const type = schema[key].type - if (type === "link") { - // Enrich row with the count of any relationship fields - row[`${key}_count`] = Array.isArray(row[key]) ? row[key].length : 0 - } else if (type === "attachment") { - // Enrich row with the first image URL for any attachment fields - let url = null - if (Array.isArray(row[key]) && row[key][0] != null) { - url = row[key][0].url - } - row[`${key}_first`] = url - } - } - }) - } - } - return rows + return await enrichRows(rows, tableId) } diff --git a/packages/component-sdk/src/api/index.js b/packages/component-sdk/src/api/index.js index 56ef9b06ad..711479fb83 100644 --- a/packages/component-sdk/src/api/index.js +++ b/packages/component-sdk/src/api/index.js @@ -1,2 +1,7 @@ export * from "./rows" export * from "./auth" +export * from "./datasources" +export * from "./tables" +export * from "./attachments" +export * from "./views" +export * from "./relationships" diff --git a/packages/component-sdk/src/api/relationships.js b/packages/component-sdk/src/api/relationships.js index a4d09f1250..d988220f14 100644 --- a/packages/component-sdk/src/api/relationships.js +++ b/packages/component-sdk/src/api/relationships.js @@ -1,4 +1,5 @@ import api from "./api" +import { enrichRows } from "./rows" /** * Fetches related rows for a certain field of a certain row. @@ -8,5 +9,6 @@ export const fetchRelationshipData = async ({ tableId, rowId, fieldName }) => { return [] } const response = await api.get({ url: `/api/${tableId}/${rowId}/enrich` }) - return response[fieldName] || [] + const rows = response[fieldName] || [] + return await enrichRows(rows, tableId) } diff --git a/packages/component-sdk/src/api/rows.js b/packages/component-sdk/src/api/rows.js index 3267bfda3e..60d83bbee0 100644 --- a/packages/component-sdk/src/api/rows.js +++ b/packages/component-sdk/src/api/rows.js @@ -1,4 +1,15 @@ import api from "./api" +import { fetchTableDefinition } from "./tables" + +/** + * Fetches data about a certain row in a table. + */ +export const fetchRow = async ({ tableId, rowId }) => { + const row = await api.get({ + url: `/api/${tableId}/rows/${rowId}`, + }) + return await enrichRows([row], tableId) +} /** * Creates a row in a table. @@ -31,6 +42,19 @@ export const deleteRow = async ({ tableId, rowId, revId }) => { }) } +/** + * Deletes many rows from a table. + */ +export const deleteRows = async ({ tableId, rows }) => { + return await api.post({ + url: `/api/${tableId}/rows`, + body: { + rows, + type: "delete", + }, + }) +} + /** * Sanitises and parses column types when saving and updating rows. */ @@ -68,3 +92,35 @@ const makeRowRequestBody = (parameters, state) => { return body } + +/** + * Enriches rows which contain certain field types so that they can + * be properly displayed. + */ +export const enrichRows = async (rows, tableId) => { + if (rows && rows.length && tableId) { + // Fetch table schema so we can check column types + const tableDefinition = await fetchTableDefinition(tableId) + const schema = tableDefinition && tableDefinition.schema + if (schema) { + const keys = Object.keys(schema) + rows.forEach(row => { + for (let key of keys) { + const type = schema[key].type + if (type === "link") { + // Enrich row with the count of any relationship fields + row[`${key}_count`] = Array.isArray(row[key]) ? row[key].length : 0 + } else if (type === "attachment") { + // Enrich row with the first image URL for any attachment fields + let url = null + if (Array.isArray(row[key]) && row[key][0] != null) { + url = row[key][0].url + } + row[`${key}_first`] = url + } + } + }) + } + } + return rows +} diff --git a/packages/component-sdk/src/api/tables.js b/packages/component-sdk/src/api/tables.js index f8259186d0..7ad5633b07 100644 --- a/packages/component-sdk/src/api/tables.js +++ b/packages/component-sdk/src/api/tables.js @@ -1,4 +1,5 @@ import api from "./api" +import { enrichRows } from "./rows" /** * Fetches a table definition. @@ -11,6 +12,7 @@ export const fetchTableDefinition = async tableId => { /** * Fetches all rows from a table. */ -export const fetchTableData = async name => { - return await api.get({ url: `/api/views/${name}` }) +export const fetchTableData = async tableId => { + const rows = await api.get({ url: `/api/${tableId}/rows` }) + return await enrichRows(rows, tableId) } diff --git a/packages/component-sdk/src/api/views.js b/packages/component-sdk/src/api/views.js index 4f7acd2d8f..7c1386d721 100644 --- a/packages/component-sdk/src/api/views.js +++ b/packages/component-sdk/src/api/views.js @@ -1,9 +1,16 @@ import api from "./api" +import { enrichRows } from "./rows" /** * Fetches all rows in a view. */ -export const fetchViewData = async ({ name, field, groupBy, calculation }) => { +export const fetchViewData = async ({ + name, + field, + groupBy, + calculation, + tableId, +}) => { const params = new URLSearchParams() if (calculation) { @@ -18,5 +25,6 @@ export const fetchViewData = async ({ name, field, groupBy, calculation }) => { ? `/api/views/${name}?${params}` : `/api/views/${name}` - return await api.get({ url: QUERY_VIEW_URL }) + const rows = await api.get({ url: QUERY_VIEW_URL }) + return await enrichRows(rows, tableId) } diff --git a/packages/component-sdk/src/store/auth.js b/packages/component-sdk/src/store/auth.js index 05f7709b4a..4d69530efa 100644 --- a/packages/component-sdk/src/store/auth.js +++ b/packages/component-sdk/src/store/auth.js @@ -1,12 +1,11 @@ import { localStorageStore } from "../../../builder/src/builderStore/store/localStorage" import * as api from "../api" +import { getAppId } from "../utils" -const initialState = { - user: null, -} +const initialState = "" export const createAuthStore = () => { - const store = localStorageStore("bb-app-auth", initialState) + const store = localStorageStore("budibase:token", initialState) /** * Logs a user in. @@ -14,18 +13,24 @@ export const createAuthStore = () => { const logIn = async ({ username, password }) => { const user = await api.logIn({ username, password }) if (!user.error) { - store.update(state => { - state.user = user - return state - }) + store.set(user.token) } + return !user.error } /** * Logs a user out. */ const logOut = () => { - store.update(() => initialState) + store.set(initialState) + + // Expire any cookies + const appId = getAppId(window.document.cookie) + if (appId) { + for (let environment of ["local", "cloud"]) { + window.document.cookie = `budibase:${appId}:${environment}=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;` + } + } } store.actions = { diff --git a/packages/component-sdk/src/store/config.js b/packages/component-sdk/src/store/config.js index dbf9918ae3..b6978d6f77 100644 --- a/packages/component-sdk/src/store/config.js +++ b/packages/component-sdk/src/store/config.js @@ -26,7 +26,7 @@ export const createConfigStore = () => { * Rests the SDK configuration */ const reset = () => { - store.update(() => initialState) + store.set(initialState) } /** diff --git a/packages/standard-components/src/DataList.svelte b/packages/standard-components/src/DataList.svelte deleted file mode 100644 index 343ea886ad..0000000000 --- a/packages/standard-components/src/DataList.svelte +++ /dev/null @@ -1,82 +0,0 @@ - - -
- {#each data as data} -
-
    - {#each Object.keys(data) as key} -
  • - {key}: - {data[key]} -
  • - {/each} -
-
- {/each} -
- - diff --git a/packages/standard-components/src/DataSearch.svelte b/packages/standard-components/src/DataSearch.svelte deleted file mode 100644 index 1521dae418..0000000000 --- a/packages/standard-components/src/DataSearch.svelte +++ /dev/null @@ -1,15 +0,0 @@ - - -
- - -
diff --git a/packages/standard-components/src/IconOld.svelte b/packages/standard-components/src/IconOld.svelte deleted file mode 100644 index f220d3c8f9..0000000000 --- a/packages/standard-components/src/IconOld.svelte +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/packages/standard-components/src/LinkedRowSelector.svelte b/packages/standard-components/src/LinkedRowSelector.svelte index cd9c6fc264..a0e74dca97 100644 --- a/packages/standard-components/src/LinkedRowSelector.svelte +++ b/packages/standard-components/src/LinkedRowSelector.svelte @@ -1,6 +1,6 @@ diff --git a/packages/standard-components/src/Nav.svelte b/packages/standard-components/src/Nav.svelte deleted file mode 100644 index 7619a440b4..0000000000 --- a/packages/standard-components/src/Nav.svelte +++ /dev/null @@ -1,116 +0,0 @@ - - -
- {#if !hideNavBar} - - {/if} - {#each _children as navItem, index} -
- {/each} -
- - diff --git a/packages/standard-components/src/Navigation.svelte b/packages/standard-components/src/Navigation.svelte index dda860414d..97d4ca0b8c 100644 --- a/packages/standard-components/src/Navigation.svelte +++ b/packages/standard-components/src/Navigation.svelte @@ -1,4 +1,6 @@ diff --git a/packages/standard-components/src/NewRow.svelte b/packages/standard-components/src/NewRow.svelte index e7446f9bdc..dd43a3ee47 100644 --- a/packages/standard-components/src/NewRow.svelte +++ b/packages/standard-components/src/NewRow.svelte @@ -1,5 +1,6 @@ - - - - - {#each columns as col} - - {/each} - - - - {#if data} - {#each data as row} - - {#each columns as col, index} - - {/each} - - {/each} - {/if} - -
{col.title}
{cellValue(index, row)}
- - diff --git a/packages/standard-components/src/TableBody.svelte b/packages/standard-components/src/TableBody.svelte deleted file mode 100644 index ca92ac255c..0000000000 --- a/packages/standard-components/src/TableBody.svelte +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/packages/standard-components/src/TableHead.svelte b/packages/standard-components/src/TableHead.svelte deleted file mode 100644 index ae739aa306..0000000000 --- a/packages/standard-components/src/TableHead.svelte +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/packages/standard-components/src/attachments/Dropzone.svelte b/packages/standard-components/src/attachments/Dropzone.svelte index 62bb57b0f8..f30860accf 100644 --- a/packages/standard-components/src/attachments/Dropzone.svelte +++ b/packages/standard-components/src/attachments/Dropzone.svelte @@ -1,5 +1,6 @@ diff --git a/packages/standard-components/src/charts/BarChart.svelte b/packages/standard-components/src/charts/BarChart.svelte index 9fdc649dfa..09d2e04908 100644 --- a/packages/standard-components/src/charts/BarChart.svelte +++ b/packages/standard-components/src/charts/BarChart.svelte @@ -1,16 +1,9 @@ diff --git a/packages/standard-components/src/grid/Relationship/tableCache.js b/packages/standard-components/src/grid/Relationship/tableCache.js deleted file mode 100644 index 850bdd212a..0000000000 --- a/packages/standard-components/src/grid/Relationship/tableCache.js +++ /dev/null @@ -1,20 +0,0 @@ -import api from "../../api" - -let cache = {} - -async function fetchTable(id) { - const FETCH_TABLE_URL = `/api/tables/${id}` - const response = await api.get(FETCH_TABLE_URL) - return await response.json() -} - -export async function getTable(tableId) { - if (!tableId) { - return null - } - if (!cache[tableId]) { - cache[tableId] = fetchTable(tableId) - cache[tableId] = await cache[tableId] - } - return await cache[tableId] -} diff --git a/packages/standard-components/src/index.js b/packages/standard-components/src/index.js index 30748aa2bf..0bd46f12d9 100644 --- a/packages/standard-components/src/index.js +++ b/packages/standard-components/src/index.js @@ -13,9 +13,7 @@ export { default as Navigation } from "./Navigation.svelte" export { default as datagrid } from "./grid/Component.svelte" export { default as dataform } from "./DataForm.svelte" export { default as dataformwide } from "./DataFormWide.svelte" -export { default as datalist } from "./DataList.svelte" export { default as list } from "./List.svelte" -export { default as datasearch } from "./DataSearch.svelte" export { default as embed } from "./Embed.svelte" export { default as stackedlist } from "./StackedList.svelte" export { default as card } from "./Card.svelte"