diff --git a/packages/client/src/api/authenticate.js b/packages/client/src/api/authenticate.js new file mode 100644 index 0000000000..6e77317bea --- /dev/null +++ b/packages/client/src/api/authenticate.js @@ -0,0 +1,24 @@ + +export const USER_STATE_PATH = "_bbuser"; + +export const authenticate = (api) => async ({username, password}) => { + + if(!username) { + api.error("Authenticate: username not set"); + return; + } + + if(!password) { + api.error("Authenticate: password not set"); + return; + } + + const user = await post({ + url:`${rootPath}/api/authenticate`, + body : {username, password} + }); + + // set user even if error - so it is defined at least + api.setState(USER_STATE_PATH, user); + localStorage.setItem("budibase:user", user); +} \ No newline at end of file diff --git a/packages/client/src/api/index.js b/packages/client/src/api/index.js index c9bbc75da9..bba44786c2 100644 --- a/packages/client/src/api/index.js +++ b/packages/client/src/api/index.js @@ -1,6 +1,7 @@ import { ERROR } from "../state/standardState"; import {loadRecord} from "./loadRecord"; import {listRecords} from "./listRecords"; +import {authenticate} from "./authenticate"; export const createApi = ({rootPath, setState, getState}) => { @@ -54,7 +55,8 @@ export const createApi = ({rootPath, setState, getState}) => { return { loadRecord:loadRecord(apiOpts), - listRecords: listRecords(apiOpts) + listRecords: listRecords(apiOpts), + authenticate: authenticate(apiOpts) } } diff --git a/packages/client/src/core/createCoreApp.js b/packages/client/src/core/createCoreApp.js index 6dc857a79f..67e8aa8a36 100644 --- a/packages/client/src/core/createCoreApp.js +++ b/packages/client/src/core/createCoreApp.js @@ -6,10 +6,9 @@ export const createCoreApp = (appDefinition, user) => { crypto:null, publish: () => {}, hierarchy: appDefinition.hierarchy, - actions: appDefinition.actions + actions: appDefinition.actions, + user }; - app.asUser(user); - return app; } \ No newline at end of file diff --git a/packages/client/src/createApp.js b/packages/client/src/createApp.js index 513f5b1216..67e9562d3c 100644 --- a/packages/client/src/createApp.js +++ b/packages/client/src/createApp.js @@ -19,7 +19,8 @@ export const createApp = (componentLibraries, appDefinition, user) => { const component = new (componentLibraries[libName][componentName])({ target: htmlElement, - props: {...initialProps, _app} + props: {...initialProps, _app}, + hydrate:true }); bind(component); @@ -27,7 +28,9 @@ export const createApp = (componentLibraries, appDefinition, user) => { } const coreApi = createCoreApi(appDefinition, user); - const store = writable({}); + const store = writable({ + _bbuser: user + }); const _app = { initialiseComponent, diff --git a/packages/client/src/state/eventHandlers.js b/packages/client/src/state/eventHandlers.js index 718f61b69b..707d514a17 100644 --- a/packages/client/src/state/eventHandlers.js +++ b/packages/client/src/state/eventHandlers.js @@ -38,6 +38,8 @@ export const eventHandlers = (store,coreApi) => { "Get New Record": handler( ["collectionKey", "childRecordType", "statePath"], getNewRecordToState(store, coreApi)), + + "Authenticate": handler(["username", "password"], api.authenticate) }; }; diff --git a/packages/client/src/state/stateBinding.js b/packages/client/src/state/stateBinding.js index f70dc05847..39454204a4 100644 --- a/packages/client/src/state/stateBinding.js +++ b/packages/client/src/state/stateBinding.js @@ -87,9 +87,9 @@ export const setupBinding = (store, props, coreApi) => { closuredHandlers.push(() => handlerType.execute(parameters)); } - newProps[boundHandler.propName] = () => { + newProps[boundHandler.propName] = async () => { for(let runHandler of closuredHandlers) { - runHandler(); + await runHandler(); } } diff --git a/packages/standard-components/components.json b/packages/standard-components/components.json index 33bdb61ab3..9ee184faed 100644 --- a/packages/standard-components/components.json +++ b/packages/standard-components/components.json @@ -106,12 +106,47 @@ "text": { "importPath": "Text", "name": "Text", - "desciption": "A div with text inside ", + "desciption": "stylable block of text", "props" : { "value": "string", "containerClass": "string", + "font": "string", + "color": "string", + "textAlign": { + "type": "options", + "default":"inline", + "options": [ + "left", "center", "right" + ] + }, + "verticalAlign": { + "type": "options", + "default":"inline", + "options": [ + "top", "middle", "bottom" + ] + }, + "display": { + "type": "options", + "default":"inline", + "options": [ + "inline", "block", "inline-block" + ] + } + }, + "tags": ["div", "container"] + }, + "panel": { + "importPath": "Panel", + "name": "Panel", + "desciption": "A stylable div with a component inside", + "props" : { + "text": "string", + "component": "component", + "containerClass": "string", "background": "string", "border": "string", + "borderRadius":"string", "font": "string", "color": "string", "padding": "string", @@ -124,5 +159,29 @@ } }, "tags": ["div", "container"] + }, + "nav": { + "importPath": "Nav", + "name": "Nav", + "desciption": "A nav - a side bar of buttons that control the currently active component", + "props" : { + "navBarBackground": {"type" :"string", "default":"silver"}, + "navBarBorder": "string", + "navBarColor": {"type" :"string", "default":"black"}, + "selectedItemBackground": {"type" :"string", "default":"white"}, + "selectedItemColor": {"type" :"string", "default":"black"}, + "selectedItemBorder": "string", + "itemHoverBackground": {"type" :"string", "default":"gainsboro"}, + "itemHoverColor": {"type" :"string", "default":"black"}, + "items": { + "type": "array", + "elementDefinition" : { + "title": "string", + "component": "component" + } + } + + }, + "tags": ["nav", "navigation", "sidebar"] } } \ No newline at end of file diff --git a/packages/standard-components/public/bundle.css b/packages/standard-components/public/bundle.css index 9378dabd46..1f0f6febdc 100644 --- a/packages/standard-components/public/bundle.css +++ b/packages/standard-components/public/bundle.css @@ -1,8 +1,9 @@ #current_component.svelte-1xqz9vm{height:100%;width:100%} .root.svelte-1oto99m{height:100%;display:grid;grid-template-columns:[left] 1fr [middle] auto [right] 1fr;grid-template-rows:[top] 1fr [center] auto [bottom] 1fr}.content.svelte-1oto99m{grid-column-start:middle;grid-row-start:center;width:400px}.logo-container.svelte-1oto99m{margin-bottom:20px }.logo-container.svelte-1oto99m>img.svelte-1oto99m{max-width:100%}.login-button-container.svelte-1oto99m{text-align:right;margin-top:20px}.incorrect-details-panel.svelte-1oto99m{margin-top:30px;padding:10px;border-style:solid;border-width:1px;border-color:maroon;border-radius:1px;text-align:center;color:maroon;background-color:mistyrose}.form-root.svelte-1oto99m{display:grid;grid-template-columns:[label] auto [control] 1fr}.label.svelte-1oto99m{grid-column-start:label;padding:5px 10px;vertical-align:middle}.control.svelte-1oto99m{grid-column-start:control;padding:5px 10px} -.root.svelte-10kw8to{display:grid} .default.svelte-1ec4wqj{width:100%;font-family:inherit;font-size:inherit;padding:0.4em;margin:0 0 0.5em 0;box-sizing:border-box;border:1px solid #ccc;border-radius:2px;width:100%}.default.svelte-1ec4wqj:disabled{color:#ccc} +.root.svelte-10kw8to{display:grid} +.root.svelte-aihwli{height:100%;width:100%;grid-template-columns:[navbar] auto [content] 1fr;display:grid}.navbar.svelte-aihwli{grid-column:navbar;background:var(--navBarBackground);border:var(--navBarBorder);color:var(--navBarColor)}.navitem.svelte-aihwli{padding:10px 17px;cursor:pointer}.navitem.svelte-aihwli:hover{background:var(--itemHoverBackground);color:var(--itemHoverColor)}.navitem.selected.svelte-aihwli{background:var(--selectedItemBackground);border:var(--selectedItemBorder);color:var(--selectedItemColor)}.content.svelte-aihwli{grid-column:content} .form-root.svelte-m9d6ue{display:grid;grid-template-columns:[label] auto [control] 1fr}.label.svelte-m9d6ue{grid-column-start:label;padding:5px 10px;vertical-align:middle}.control.svelte-m9d6ue{grid-column-start:control;padding:5px 10px}.overflow.svelte-m9d6ue{grid-column-start:overflow}.full-width.svelte-m9d6ue{width:100%} .default.svelte-1q8lga0{font-family:inherit;font-size:inherit;padding:0.4em;margin:0 0 0.5em 0;box-sizing:border-box;border:1px solid #ccc;border-radius:2px;color:#333;background-color:#f4f4f4;outline:none}.default.svelte-1q8lga0:active{background-color:#ddd}.default.svelte-1q8lga0:focus{border-color:#666} diff --git a/packages/standard-components/public/bundle.css.map b/packages/standard-components/public/bundle.css.map index 816a9cdbf2..77e3240ca3 100644 --- a/packages/standard-components/public/bundle.css.map +++ b/packages/standard-components/public/bundle.css.map @@ -4,19 +4,21 @@ "sources": [ "..\\src\\Test\\TestApp.svelte", "..\\src\\Login.svelte", - "..\\src\\Grid.svelte", "..\\src\\Textbox.svelte", + "..\\src\\Grid.svelte", + "..\\src\\Nav.svelte", "..\\src\\Form.svelte", "..\\src\\Button.svelte" ], "sourcesContent": [ - "\n\n{#await _appPromise}\nloading\n{:then _app}\n\n