diff --git a/packages/bbui/package.json b/packages/bbui/package.json index b0192739be..47a1fe6c3d 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -66,6 +66,7 @@ "@spectrum-css/tabs": "^3.0.1", "@spectrum-css/textfield": "^3.0.1", "@spectrum-css/toast": "^3.0.1", + "@spectrum-css/treeview": "^3.0.2", "@spectrum-css/typography": "^3.0.1", "@spectrum-css/underlay": "^2.0.9", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/bbui/src/Menu/Item.svelte b/packages/bbui/src/Menu/Item.svelte index 58b031fe78..23116a25a0 100644 --- a/packages/bbui/src/Menu/Item.svelte +++ b/packages/bbui/src/Menu/Item.svelte @@ -3,7 +3,7 @@ export let disabled = undefined; -
  • + + {#if $$slots.default} + + {/if} + {#if icon} + + {/if} + {title} + + {#if $$slots.default} + + {/if} +
  • \ No newline at end of file diff --git a/packages/bbui/src/TreeView/Tree.svelte b/packages/bbui/src/TreeView/Tree.svelte new file mode 100644 index 0000000000..5a4e254732 --- /dev/null +++ b/packages/bbui/src/TreeView/Tree.svelte @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/packages/bbui/src/index.js b/packages/bbui/src/index.js index 73fc8699a5..57cf237abb 100644 --- a/packages/bbui/src/index.js +++ b/packages/bbui/src/index.js @@ -42,6 +42,8 @@ export { default as Context } from "./context" export { default as Table } from "./Table/Table.svelte" export { default as Tabs } from "./Tabs/Tabs.svelte" export { default as Tab } from "./Tabs/Tab.svelte" +export { default as TreeView } from "./TreeView/Tree.svelte" +export { default as TreeItem } from "./TreeView/Item.svelte" export { default as Divider } from "./Divider/Divider.svelte" export { default as Search } from "./Form/Search.svelte" diff --git a/packages/bbui/yarn.lock b/packages/bbui/yarn.lock index c03cb4b1f5..69691be906 100644 --- a/packages/bbui/yarn.lock +++ b/packages/bbui/yarn.lock @@ -211,6 +211,11 @@ resolved "https://registry.yarnpkg.com/@spectrum-css/toast/-/toast-3.0.2.tgz#8e27cce799b1b1d0054a88b135dddf7fbf1bdc78" integrity sha512-sJp8DRsU2iSF67hlOQHFdRkbJHncspoOywHEsqcjh2KFl8gRY12rQL0ORG6J2THUt0LVBWSy48iwph9s4rkwsA== +"@spectrum-css/treeview@^3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/treeview/-/treeview-3.0.2.tgz#d54d8f17290babb1c885f5d9355e225421beb0d2" + integrity sha512-foO7UBJv1JMFaKgDPVt8jBghZSVbqhXR8TaGaxHSnMubv7ygmKkc1AITrWC2STILCn84ju2vchOohMZfW6sYwg== + "@spectrum-css/typography@^3.0.1": version "3.0.2" resolved "https://registry.yarnpkg.com/@spectrum-css/typography/-/typography-3.0.2.tgz#ea3ca0a60e18064527819d48c8c4364cab4fcd38" diff --git a/packages/builder/src/builderStore/store/backend.js b/packages/builder/src/builderStore/store/backend.js deleted file mode 100644 index 5d0e722650..0000000000 --- a/packages/builder/src/builderStore/store/backend.js +++ /dev/null @@ -1,362 +0,0 @@ -import { writable, get } from "svelte/store" -import { cloneDeep } from "lodash/fp" -import api from "../api" - -const INITIAL_BACKEND_UI_STATE = { - tables: [], - views: [], - users: [], - roles: [], - datasources: [], - queries: [], - integrations: {}, - selectedDatabase: {}, - selectedTable: {}, - draftTable: {}, -} - -export const getBackendUiStore = () => { - const store = writable({ ...INITIAL_BACKEND_UI_STATE }) - - store.actions = { - reset: () => store.set({ ...INITIAL_BACKEND_UI_STATE }), - database: { - select: async db => { - const tablesResponse = await api.get(`/api/tables`) - const tables = await tablesResponse.json() - const datasourcesResponse = await api.get(`/api/datasources`) - const datasources = await datasourcesResponse.json() - const queriesResponse = await api.get(`/api/queries`) - const queries = await queriesResponse.json() - const integrationsResponse = await api.get("/api/integrations") - const integrations = await integrationsResponse.json() - const permissionLevels = await store.actions.permissions.fetchLevels() - - store.update(state => { - state.selectedDatabase = db - state.tables = tables - state.datasources = datasources - state.queries = queries - state.integrations = integrations - state.permissionLevels = permissionLevels - return state - }) - }, - }, - rows: { - save: () => - store.update(state => { - state.selectedView = state.selectedView - return state - }), - delete: () => - store.update(state => { - state.selectedView = state.selectedView - return state - }), - select: row => - store.update(state => { - state.selectedRow = row - return state - }), - }, - datasources: { - fetch: async () => { - const response = await api.get(`/api/datasources`) - const json = await response.json() - store.update(state => { - state.datasources = json - return state - }) - return json - }, - select: async datasourceId => { - store.update(state => { - state.selectedDatasourceId = datasourceId - state.selectedQueryId = null - return state - }) - }, - save: async datasource => { - const response = await api.post("/api/datasources", datasource) - const json = await response.json() - store.update(state => { - const currentIdx = state.datasources.findIndex( - ds => ds._id === json._id - ) - - if (currentIdx >= 0) { - state.datasources.splice(currentIdx, 1, json) - } else { - state.datasources.push(json) - } - - state.datasources = state.datasources - state.selectedDatasourceId = json._id - return state - }) - return json - }, - delete: async datasource => { - await api.delete( - `/api/datasources/${datasource._id}/${datasource._rev}` - ) - store.update(state => { - state.datasources = state.datasources.filter( - existing => existing._id !== datasource._id - ) - if (datasource._id === state.selectedDatasourceId) { - state.selectedDatasourceId = null - } - return state - }) - }, - }, - queries: { - fetch: async () => { - const response = await api.get(`/api/queries`) - const json = await response.json() - store.update(state => { - state.queries = json - return state - }) - return json - }, - save: async (datasourceId, query) => { - const integrations = get(store).integrations - const dataSource = get(store).datasources.filter( - ds => ds._id === datasourceId - ) - // check if readable attribute is found - if (dataSource.length !== 0) { - const integration = integrations[dataSource[0].source] - const readable = integration.query[query.queryVerb].readable - if (readable) { - query.readable = readable - } - } - 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( - query => query._id === json._id - ) - - if (currentIdx >= 0) { - state.queries.splice(currentIdx, 1, json) - } else { - state.queries.push(json) - } - - state.queries = state.queries - state.selectedQueryId = json._id - return state - }) - return json - }, - select: query => - store.update(state => { - state.selectedDatasourceId = query.datasourceId - state.selectedQueryId = query._id - return state - }), - delete: async query => { - await api.delete(`/api/queries/${query._id}/${query._rev}`) - store.update(state => { - state.queries = state.queries.filter( - existing => existing._id !== query._id - ) - if (state.selectedQueryId === query._id) { - state.selectedQueryId = null - } - - return state - }) - }, - }, - tables: { - fetch: async () => { - const tablesResponse = await api.get(`/api/tables`) - const tables = await tablesResponse.json() - store.update(state => { - state.tables = tables - return state - }) - }, - select: table => - store.update(state => { - state.selectedTable = table - state.draftTable = cloneDeep(table) - state.selectedView = { name: `all_${table._id}` } - return state - }), - save: async table => { - const updatedTable = cloneDeep(table) - const oldTable = get(store).tables.filter(t => t._id === table._id)[0] - - const fieldNames = [] - // update any renamed schema keys to reflect their names - for (let key of Object.keys(updatedTable.schema)) { - // if field name has been seen before remove it - if (fieldNames.indexOf(key.toLowerCase()) !== -1) { - delete updatedTable.schema[key] - continue - } - const field = updatedTable.schema[key] - const oldField = oldTable?.schema[key] - // if the type has changed then revert back to the old field - if (oldField != null && oldField.type !== field.type) { - updatedTable.schema[key] = oldField - } - // field has been renamed - if (field.name && field.name !== key) { - updatedTable.schema[field.name] = field - updatedTable._rename = { old: key, updated: field.name } - delete updatedTable.schema[key] - } - // finally record this field has been used - fieldNames.push(key.toLowerCase()) - } - - const SAVE_TABLE_URL = `/api/tables` - const response = await api.post(SAVE_TABLE_URL, updatedTable) - const savedTable = await response.json() - await store.actions.tables.fetch() - store.actions.tables.select(savedTable) - return savedTable - }, - delete: async table => { - await api.delete(`/api/tables/${table._id}/${table._rev}`) - store.update(state => { - state.tables = state.tables.filter( - existing => existing._id !== table._id - ) - if (table._id === state.selectedTable._id) { - state.selectedTable = {} - } - return state - }) - }, - saveField: ({ originalName, field, primaryDisplay = false, indexes }) => { - store.update(state => { - // delete the original if renaming - // need to handle if the column had no name, empty string - if (originalName || originalName === "") { - delete state.draftTable.schema[originalName] - state.draftTable._rename = { - old: originalName, - updated: field.name, - } - } - - // Optionally set display column - if (primaryDisplay) { - state.draftTable.primaryDisplay = field.name - } - - if (indexes) { - state.draftTable.indexes = indexes - } - - state.draftTable.schema[field.name] = cloneDeep(field) - store.actions.tables.save(state.draftTable) - return state - }) - }, - deleteField: field => { - store.update(state => { - delete state.draftTable.schema[field.name] - store.actions.tables.save(state.draftTable) - return state - }) - }, - }, - views: { - select: view => - store.update(state => { - state.selectedView = view - state.selectedTable = {} - return state - }), - delete: async view => { - await api.delete(`/api/views/${view}`) - await store.actions.tables.fetch() - }, - save: async view => { - const response = await api.post(`/api/views`, view) - const json = await response.json() - - const viewMeta = { - name: view.name, - ...json, - } - - store.update(state => { - const viewTable = state.tables.find( - table => table._id === view.tableId - ) - - if (view.originalName) delete viewTable.views[view.originalName] - viewTable.views[view.name] = viewMeta - - state.tables = state.tables - state.selectedView = viewMeta - return state - }) - }, - }, - users: { - create: user => - store.update(state => { - state.users.push(user) - state.users = state.users - return state - }), - }, - roles: { - fetch: async () => { - const response = await api.get("/api/roles") - const roles = await response.json() - store.update(state => { - state.roles = roles - return state - }) - }, - delete: async role => { - const response = await api.delete(`/api/roles/${role._id}/${role._rev}`) - await store.actions.roles.fetch() - return response - }, - save: async role => { - const response = await api.post("/api/roles", role) - await store.actions.roles.fetch() - return response - }, - }, - permissions: { - fetchLevels: async () => { - const response = await api.get("/api/permission/levels") - const json = await response.json() - return json - }, - forResource: async resourceId => { - const response = await api.get(`/api/permission/${resourceId}`) - const json = await response.json() - return json - }, - save: async ({ role, resource, level }) => { - const response = await api.post( - `/api/permission/${role}/${resource}/${level}` - ) - const json = await response.json() - return json - }, - }, - } - - return store -}