diff --git a/packages/builder/src/components/integration/AccessLevelSelect.svelte b/packages/builder/src/components/integration/AccessLevelSelect.svelte new file mode 100644 index 0000000000..bcb2f1208d --- /dev/null +++ b/packages/builder/src/components/integration/AccessLevelSelect.svelte @@ -0,0 +1,37 @@ + + +{#if label} + +{/if} + updateRole(e.detail)} - options={$roles} - getOptionLabel={x => x.name} - getOptionValue={x => x._id} - /> + {#if integrationInfo?.extra && query.queryVerb} import { store, automationStore } from "builderStore" - import { roles } from "stores/backend" + import { roles, flags } from "stores/backend" import { Icon, ActionGroup, Tabs, Tab, notifications } from "@budibase/bbui" import DeployModal from "components/deploy/DeployModal.svelte" import RevertModal from "components/deploy/RevertModal.svelte" @@ -49,6 +49,7 @@ } await automationStore.actions.fetch() await roles.fetch() + await flags.fetch() return pkg } else { throw new Error(pkg) diff --git a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/[query]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/[query]/_layout.svelte index a01bc5fb8c..403e12a78c 100644 --- a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/[query]/_layout.svelte +++ b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/[query]/_layout.svelte @@ -4,17 +4,19 @@ import { IntegrationTypes } from "constants/backend" import { goto } from "@roxi/routify" + let datasourceId if ($params.query) { const query = $queries.list.find(q => q._id === $params.query) if (query) { queries.select(query) + datasourceId = query.datasourceId } } const datasource = $datasources.list.find( - ds => ds._id === $datasources.selected + ds => ds._id === $datasources.selected || ds._id === datasourceId ) if (datasource?.source === IntegrationTypes.REST) { - $goto("../rest") + $goto(`../rest/${$params.query}`) } diff --git a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/rest/[query]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/rest/[query]/_layout.svelte new file mode 100644 index 0000000000..6d802df2e9 --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/rest/[query]/_layout.svelte @@ -0,0 +1,13 @@ + + + diff --git a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/rest/index.svelte b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/rest/[query]/index.svelte similarity index 87% rename from packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/rest/index.svelte rename to packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/rest/[query]/index.svelte index d469053c89..1b9ac22498 100644 --- a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/rest/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/rest/[query]/index.svelte @@ -1,6 +1,6 @@ - - diff --git a/packages/builder/src/stores/backend/flags.js b/packages/builder/src/stores/backend/flags.js new file mode 100644 index 0000000000..7e5adcd00f --- /dev/null +++ b/packages/builder/src/stores/backend/flags.js @@ -0,0 +1,37 @@ +import { writable } from "svelte/store" +import api from "builderStore/api" + +export function createFlagsStore() { + const { subscribe, set } = writable({}) + + return { + subscribe, + fetch: async () => { + const { doc, response } = await getFlags() + set(doc) + return response + }, + updateFlag: async (flag, value) => { + const response = await api.post("/api/users/flags", { + flag, + value, + }) + if (response.status === 200) { + const { doc } = await getFlags() + set(doc) + } + return response + }, + } +} + +async function getFlags() { + const response = await api.get("/api/users/flags") + let doc = {} + if (response.status === 200) { + doc = await response.json() + } + return { doc, response } +} + +export const flags = createFlagsStore() diff --git a/packages/builder/src/stores/backend/index.js b/packages/builder/src/stores/backend/index.js index e020baaf4b..bbbc7be57e 100644 --- a/packages/builder/src/stores/backend/index.js +++ b/packages/builder/src/stores/backend/index.js @@ -7,3 +7,4 @@ export { roles } from "./roles" export { datasources } from "./datasources" export { integrations } from "./integrations" export { queries } from "./queries" +export { flags } from "./flags" diff --git a/packages/server/src/api/controllers/user.js b/packages/server/src/api/controllers/user.js index 95e9a9969d..902f6ce7e5 100644 --- a/packages/server/src/api/controllers/user.js +++ b/packages/server/src/api/controllers/user.js @@ -2,6 +2,7 @@ const CouchDB = require("../../db") const { generateUserMetadataID, getUserMetadataParams, + generateUserFlagID, } = require("../../db/utils") const { InternalTables } = require("../../db/utils") const { getGlobalUsers, getRawGlobalUser } = require("../../utilities/global") @@ -195,3 +196,35 @@ exports.destroyMetadata = async function (ctx) { exports.findMetadata = async function (ctx) { ctx.body = await getFullUser(ctx, ctx.params.id) } + +exports.setFlag = async function (ctx) { + const userId = ctx.user._id + const { flag, value } = ctx.request.body + if (!flag) { + ctx.throw(400, "Must supply a 'flag' field in request body.") + } + const flagDocId = generateUserFlagID(userId) + const db = new CouchDB(ctx.appId) + let doc + try { + doc = await db.get(flagDocId) + } catch (err) { + doc = { _id: flagDocId } + } + doc[flag] = value || true + await db.put(doc) + ctx.body = { message: "Flag set successfully" } +} + +exports.getFlags = async function (ctx) { + const userId = ctx.user._id + const docId = generateUserFlagID(userId) + const db = new CouchDB(ctx.appId) + let doc + try { + doc = await db.get(docId) + } catch (err) { + doc = { _id: docId } + } + ctx.body = doc +} diff --git a/packages/server/src/api/routes/query.js b/packages/server/src/api/routes/query.js index 3fca0c1e0f..2d77522033 100644 --- a/packages/server/src/api/routes/query.js +++ b/packages/server/src/api/routes/query.js @@ -33,6 +33,7 @@ function generateQueryValidation() { extra: Joi.object().optional(), schema: Joi.object({}).required().unknown(true), transformer: Joi.string().optional(), + flags: Joi.object().optional(), })) } diff --git a/packages/server/src/api/routes/user.js b/packages/server/src/api/routes/user.js index a3043b5af1..9acd599b71 100644 --- a/packages/server/src/api/routes/user.js +++ b/packages/server/src/api/routes/user.js @@ -39,5 +39,15 @@ router authorized(PermissionTypes.USER, PermissionLevels.WRITE), controller.syncUser ) + .post( + "/api/users/flags", + authorized(PermissionTypes.USER, PermissionLevels.WRITE), + controller.setFlag + ) + .get( + "/api/users/flags", + authorized(PermissionTypes.USER, PermissionLevels.READ), + controller.getFlags + ) module.exports = router diff --git a/packages/server/src/db/utils.js b/packages/server/src/db/utils.js index 17b19bba49..2d9ef87c87 100644 --- a/packages/server/src/db/utils.js +++ b/packages/server/src/db/utils.js @@ -40,6 +40,7 @@ const DocumentTypes = { DEPLOYMENTS: "deployments", METADATA: "metadata", MEM_VIEW: "view", + USER_FLAG: "flag", } const ViewNames = { @@ -339,6 +340,14 @@ exports.getQueryParams = (datasourceId = null, otherProps = {}) => { ) } +/** + * Generates a new flag document ID. + * @returns {string} The ID of the flag document that was generated. + */ +exports.generateUserFlagID = userId => { + return `${DocumentTypes.USER_FLAG}${SEPARATOR}${userId}` +} + exports.generateMetadataID = (type, entityId) => { return `${DocumentTypes.METADATA}${SEPARATOR}${type}${SEPARATOR}${entityId}` }