diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000000..3112dfa8e7 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,18 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 60 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 7 +# Issues with these labels will never be considered stale +exemptLabels: + - pinned + - security + - roadmap +# Label to use when marking an issue as stale +staleLabel: stale +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: false diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 87fe57ebf8..eb878d2b54 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,12 +28,17 @@ jobs: - run: yarn lint - run: yarn bootstrap - run: yarn build + env: + POSTHOG_TOKEN: ${{ secrets.POSTHOG_TOKEN }} + POSTHOG_URL: ${{ secrets.POSTHOG_URL }} + SENTRY_DSN: ${{ secrets.SENTRY_DSN }} - run: yarn test - name: Prepare for app notarization (macOS) if: startsWith(matrix.os, 'macos') # Import Apple API key for app notarization on macOS run: | + xattr -cr * mkdir -p ~/private_keys/ echo '${{ secrets.api_key }}' > ~/private_keys/AuthKey_${{ secrets.api_key_id }}.p8 diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..53fbb0d221 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "editor.formatOnSave": true, + "eslint.format.enable": true, + "editor.codeActionsOnSave": { + "source.fixAll": true + }, + "[svelte]": { + "editor.defaultFormatter": "JamesBirtles.svelte-vscode" + }, + "editor.defaultFormatter": "esbenp.prettier-vscode" +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9d473198b9..c5cf27a8f2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,15 +27,15 @@ A client represents a single budibase customer. Each budibase client will have 1 ### App -A client can have one or more budibase applications. Think of a budibase application as a tree. Budibase applications have one definition of what the front end will look like, +A client can have one or more budibase applications. Budibase applications would be things like "Developer Inventory Management" or "Goat Herder CRM". Think of a budibase application as a tree. ### Database An App can have one or more databases. Keeping with our [dendrology](https://en.wikipedia.org/wiki/Dendrology) analogy - think of an database as a branch on the tree. Databases are used to keep data separate for different instances of your app. For example, if you had a CRM app, you may create a database for your US office, and a database for your Australian office. Databases allow us to support [multitenancy](https://www.gartner.com/en/information-technology/glossary/multitenancy) in budibase applications. -### Model +### Table -Models in budibase are almost akin to tables in relational databases. A model may be a "Car" or an "Employee". They are the main building blocks for the creation and management of backend data in budibase. +Tables in budibase are almost akin to tables in relational databases. A table may be a "Car" or an "Employee". They are the main building blocks for the creation and management of backend data in budibase. ### View @@ -95,7 +95,7 @@ then `cd ` into your local copy. ### 4. Initialising Budibase and Creating a Budibase App -`yarn initialise` will initialise your budibase installation. A Budibase apps folder will have been created in `~/.budibase`. +`yarn initialise` will initialise your budibase installation. A Budibase apps folder will have been created in `~/.budibase`. You can also just start up the budibase electron app and it should initialise budibase for you. This is a blank apps folder, so you will need to create yourself an app. @@ -149,7 +149,25 @@ The backend schema, models and records are stored using PouchDB when developing ### Publishing Budibase to NPM -You can publish all the latest versions of the monorepo packages by running: +#### Testing In Electron + +At budibase, we pride ourselves on giving our users a fast, native and slick local development experience. As a result, we use the electron to provide a native GUI for the budibase builder. In order to release budibase out into the wild, you should test your changes in a packaged electron application. To do this, first build budibase from the root directory. +``` +yarn build +``` + +Now everything is built, you can package up your electron application. +``` +cd packages/server +yarn build:electron +``` + +Your new electron application will be stored in `packages/server/dist/`. Open up the executable and make sure everything is working smoothly. + + +#### Publishing to NPM + +Once you are happy that your changes work in electron, you can publish all the latest versions of the monorepo packages by running: ``` yarn publishnpm @@ -157,6 +175,10 @@ yarn publishnpm from your root directory. +#### CI Release + +After NPM has successfully published the budibase packages, a new tag will be pushed to master. This will kick off a github action (can be found at `.github/workflows/release.yml`) this will build and package the electron application for every OS (Windows, Mac, Linux). The binaries will be stored under the new tag on the [budibase releases page](https://github.com/Budibase/budibase/releases). + ### Troubleshooting Sometimes, things go wrong. This can be due to incompatible updates on the budibase platform. To clear down your development environment and start again: @@ -186,4 +208,4 @@ Or if you are in the builder you can run `yarn cy:test`. * This project uses a modified version of the MPLv2 license, see [LICENSE](https://github.com/budibase/server/blob/master/LICENSE). * We use the [C4 (Collective Code Construction Contract)](https://rfc.zeromq.org/spec:42/C4/) process for contributions. - Please read this if you are unfamiliar with it. \ No newline at end of file + Please read this if you are unfamiliar with it. diff --git a/lerna.json b/lerna.json index 360bc19a6a..84810e37f7 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.0.32", + "version": "0.1.12", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/builder/assets/deploy-rocket.jpg b/packages/builder/assets/deploy-rocket.jpg new file mode 100644 index 0000000000..497afe87af Binary files /dev/null and b/packages/builder/assets/deploy-rocket.jpg differ diff --git a/packages/builder/assets/orange-landscape.png b/packages/builder/assets/orange-landscape.png new file mode 100644 index 0000000000..d96fc315e6 Binary files /dev/null and b/packages/builder/assets/orange-landscape.png differ diff --git a/packages/builder/assets/rocket.jpg b/packages/builder/assets/rocket.jpg deleted file mode 100644 index cc2edf02a4..0000000000 Binary files a/packages/builder/assets/rocket.jpg and /dev/null differ diff --git a/packages/builder/assets/spacex.jpg b/packages/builder/assets/spacex.jpg deleted file mode 100644 index 30004eadd9..0000000000 Binary files a/packages/builder/assets/spacex.jpg and /dev/null differ diff --git a/packages/builder/package.json b/packages/builder/package.json index ba1ff617e5..a93609b4ed 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "0.0.32", + "version": "0.1.11", "license": "AGPL-3.0", "private": true, "scripts": { @@ -55,18 +55,20 @@ ] }, "dependencies": { - "@budibase/bbui": "^1.15.0", - "@budibase/client": "^0.0.32", + "@budibase/bbui": "^1.16.0", + "@budibase/client": "^0.1.1", + "@budibase/colorpicker": "^1.0.1", "@nx-js/compiler-util": "^2.0.0", + "@sentry/browser": "5.19.1", "codemirror": "^5.51.0", "date-fns": "^1.29.0", "deepmerge": "^4.2.2", "feather-icons": "^4.21.0", "flatpickr": "^4.5.7", "lodash": "^4.17.13", - "logrocket": "^1.0.6", "lunr": "^2.3.5", "mustache": "^4.0.1", + "posthog-js": "^1.3.1", "safe-buffer": "^5.1.2", "shortid": "^2.2.8", "string_decoder": "^1.2.0", @@ -87,6 +89,7 @@ "babel-jest": "^24.8.0", "browser-sync": "^2.26.7", "cypress": "^4.8.0", + "eslint-plugin-cypress": "^2.11.1", "http-proxy-middleware": "^0.19.1", "jest": "^24.8.0", "ncp": "^2.0.0", @@ -109,4 +112,4 @@ "svelte-jester": "^1.0.6" }, "gitHead": "115189f72a850bfb52b65ec61d932531bf327072" -} \ No newline at end of file +} diff --git a/packages/builder/rollup.config.js b/packages/builder/rollup.config.js index 575939ac19..a269b11bec 100644 --- a/packages/builder/rollup.config.js +++ b/packages/builder/rollup.config.js @@ -180,6 +180,9 @@ export default { "process.env.NODE_ENV": JSON.stringify( production ? "production" : "development" ), + "process.env.POSTHOG_TOKEN": JSON.stringify(process.env.POSTHOG_TOKEN), + "process.env.POSTHOG_URL": JSON.stringify(process.env.POSTHOG_URL), + "process.env.SENTRY_DSN": JSON.stringify(process.env.SENTRY_DSN), }), svelte({ diff --git a/packages/builder/src/App.svelte b/packages/builder/src/App.svelte index b4ab4b7791..16156d7af7 100644 --- a/packages/builder/src/App.svelte +++ b/packages/builder/src/App.svelte @@ -5,17 +5,9 @@ import { routes } from "../routify/routes" import { store, initialise } from "builderStore" import NotificationDisplay from "components/common/Notification/NotificationDisplay.svelte" - import { notifier } from "builderStore/store/notifications" - - function showErrorBanner() { - notifier.danger( - "Whoops! Looks like we're having trouble. Please refresh the page." - ) - } onMount(async () => { - window.addEventListener("error", showErrorBanner) - window.addEventListener("unhandledrejection", showErrorBanner) + await initialise() }) $basepath = "/_builder" diff --git a/packages/builder/src/analytics.js b/packages/builder/src/analytics.js new file mode 100644 index 0000000000..092a6f6303 --- /dev/null +++ b/packages/builder/src/analytics.js @@ -0,0 +1,24 @@ +import * as Sentry from "@sentry/browser" +import posthog from "posthog-js" + +function activate() { + Sentry.init({ dsn: process.env.SENTRY_DSN }) + posthog.init(process.env.POSTHOG_TOKEN, { + api_host: process.env.POSTHOG_URL, + }) +} + +function captureException(err) { + Sentry.captureException(err) +} + +function captureEvent(event) { + if (process.env.NODE_ENV !== "production") return + posthog.capture(event) +} + +export default { + activate, + captureException, + captureEvent, +} diff --git a/packages/builder/src/budibase.css b/packages/builder/src/budibase.css index eed164131d..8de82530b1 100644 --- a/packages/builder/src/budibase.css +++ b/packages/builder/src/budibase.css @@ -1,11 +1,5 @@ /* Budibase Component Styles */ -.header { - font-size: 0.75rem; - color: var(--ink); - text-transform: uppercase; - margin-top: 1rem; - font-weight: 500; -} + .budibase__title { font-weight: 900; @@ -69,7 +63,7 @@ .budibase__nav-item.selected { color: var(--ink); - background: var(--blue-light); + background: var(--grey-2); } .budibase__nav-item:hover { diff --git a/packages/builder/src/builderStore/index.js b/packages/builder/src/builderStore/index.js index 2af3a66667..6a72690524 100644 --- a/packages/builder/src/builderStore/index.js +++ b/packages/builder/src/builderStore/index.js @@ -1,7 +1,7 @@ import { getStore } from "./store" import { getBackendUiStore } from "./store/backend" import { getWorkflowStore } from "./store/workflow/" -import LogRocket from "logrocket" +import analytics from "../analytics" export const store = getStore() export const backendUiStore = getBackendUiStore() @@ -10,7 +10,7 @@ export const workflowStore = getWorkflowStore() export const initialise = async () => { try { if (process.env.NODE_ENV === "production") { - LogRocket.init("knlald/budibase") + analytics.activate() } } catch (err) { console.log(err) diff --git a/packages/builder/src/builderStore/store/backend.js b/packages/builder/src/builderStore/store/backend.js index 12e94aea60..393371ce85 100644 --- a/packages/builder/src/builderStore/store/backend.js +++ b/packages/builder/src/builderStore/store/backend.js @@ -2,23 +2,24 @@ import { writable } from "svelte/store" import { cloneDeep } from "lodash/fp" import api from "../api" -export const getBackendUiStore = () => { - const INITIAL_BACKEND_UI_STATE = { - models: [], - views: [], - users: [], - selectedDatabase: {}, - selectedModel: {}, - draftModel: {}, - tabs: { - SETUP_PANEL: "SETUP", - NAVIGATION_PANEL: "NAVIGATE", - }, - } +const INITIAL_BACKEND_UI_STATE = { + models: [], + views: [], + users: [], + selectedDatabase: {}, + selectedModel: {}, + draftModel: {}, + tabs: { + SETUP_PANEL: "SETUP", + NAVIGATION_PANEL: "NAVIGATE", + }, +} - const store = writable(INITIAL_BACKEND_UI_STATE) +export const getBackendUiStore = () => { + const store = writable({ ...INITIAL_BACKEND_UI_STATE }) store.actions = { + reset: () => store.set({ ...INITIAL_BACKEND_UI_STATE }), database: { select: async db => { const modelsResponse = await api.get(`/api/models`) @@ -78,7 +79,6 @@ export const getBackendUiStore = () => { } const SAVE_MODEL_URL = `/api/models` - console.log(updatedModel) const response = await api.post(SAVE_MODEL_URL, updatedModel) const savedModel = await response.json() await store.actions.models.fetch() diff --git a/packages/builder/src/builderStore/store/index.js b/packages/builder/src/builderStore/store/index.js index a6386c29c2..c6ab194379 100644 --- a/packages/builder/src/builderStore/store/index.js +++ b/packages/builder/src/builderStore/store/index.js @@ -29,7 +29,8 @@ import { export const getStore = () => { const initial = { apps: [], - appname: "", + name: "", + description: "", pages: DEFAULT_PAGES_OBJECT, mainUi: {}, unauthenticatedUi: {}, @@ -52,7 +53,6 @@ export const getStore = () => { store.createDatabaseForApp = backendStoreActions.createDatabaseForApp(store) store.saveScreen = saveScreen(store) - store.deleteScreen = deleteScreen(store) store.setCurrentScreen = setCurrentScreen(store) store.setCurrentPage = setCurrentPage(store) store.createScreen = createScreen(store) @@ -101,7 +101,8 @@ const setPackage = (store, initial) => async pkg => { initial.libraries = pkg.application.componentLibraries initial.components = await fetchComponentLibDefinitions(pkg.application._id) - initial.appname = pkg.application.name + initial.name = pkg.application.name + initial.description = pkg.application.description initial.appId = pkg.application._id initial.pages = pkg.pages initial.hasAppPackage = true @@ -160,6 +161,7 @@ const createScreen = store => (screenName, route, layoutComponentName) => { props: createProps(rootComponent).props, } newScreen.route = route + newScreen.name = newScreen.props._id newScreen.props._instanceName = screenName || "" state.currentPreviewItem = newScreen state.currentComponentInfo = newScreen.props @@ -189,24 +191,6 @@ const setCurrentScreen = store => screenName => { }) } -const deleteScreen = store => name => { - store.update(s => { - const components = s.components.filter(c => c.name !== name) - const screens = s.screens.filter(c => c.name !== name) - - s.components = components - s.screens = screens - if (s.currentPreviewItem.name === name) { - s.currentPreviewItem = null - s.currentFrontEndType = "" - } - - api.delete(`/_builder/api/${s.appId}/screen/${name}`) - - return s - }) -} - const savePage = store => async page => { store.update(state => { if (state.currentFrontEndType !== "page" || !state.currentPageName) { diff --git a/packages/builder/src/components/common/Block.svelte b/packages/builder/src/components/common/Block.svelte index fc1958a211..eccf798742 100644 --- a/packages/builder/src/components/common/Block.svelte +++ b/packages/builder/src/components/common/Block.svelte @@ -28,12 +28,15 @@ } i { - font-size: 30px; + font-size: 24px; + color: var(--grey-7); } span { font-size: 14px; text-align: center; + margin-top: 8px; + line-height: 1.25; } div:hover { diff --git a/packages/builder/src/components/common/Checkbox.svelte b/packages/builder/src/components/common/Checkbox.svelte index 37eb385d79..fe3f5756eb 100644 --- a/packages/builder/src/components/common/Checkbox.svelte +++ b/packages/builder/src/components/common/Checkbox.svelte @@ -1,13 +1,112 @@ -{label} - + +