From 13dd99be027597da762c27516bd6f42a79c9fd13 Mon Sep 17 00:00:00 2001 From: michael shanks Date: Sat, 13 Jul 2019 10:35:57 +0100 Subject: [PATCH] moving builder into web... --- packages/builder/.gitignore | 7 + packages/builder/AUTHORS.md | 4 + packages/builder/CONTRIBUTING.md | 22 + packages/builder/LICENSE.md | 661 +++++++++++++++++ packages/builder/README.md | 6 + packages/builder/package.json | 40 ++ packages/builder/rollup.config.js | 113 +++ packages/builder/src/App.svelte | 38 + packages/builder/src/NoPackage.svelte | 55 ++ packages/builder/src/PackageRoot.svelte | 49 ++ .../src/accessLevels/AccessLevelView.svelte | 96 +++ .../src/accessLevels/AccessLevelsRoot.svelte | 116 +++ .../src/actionsAndTriggers/ActionView.svelte | 115 +++ .../src/actionsAndTriggers/Actions.svelte | 95 +++ .../ActionsAndTriggersRoot.svelte | 115 +++ .../src/actionsAndTriggers/TriggerView.svelte | 64 ++ .../src/actionsAndTriggers/Triggers.svelte | 84 +++ .../builder/src/assets/budibase-logo-only.png | Bin 0 -> 4980 bytes .../src/assets/budibase-logo-white.png | Bin 0 -> 12600 bytes packages/builder/src/assets/budibase-logo.png | Bin 0 -> 12702 bytes .../builder/src/assets/lato-latin-ext.woff2 | Bin 0 -> 5480 bytes packages/builder/src/assets/lato-latin.woff2 | Bin 0 -> 23484 bytes .../builder/src/builderStore/createPackage.js | 663 ++++++++++++++++++ packages/builder/src/builderStore/index.js | 19 + packages/builder/src/builderStore/store.js | 330 +++++++++ packages/builder/src/common/Button.svelte | 161 +++++ .../builder/src/common/ButtonGroup.svelte | 27 + packages/builder/src/common/Checkbox.svelte | 16 + packages/builder/src/common/CodeArea.svelte | 21 + packages/builder/src/common/ComingSoon.svelte | 17 + packages/builder/src/common/DatePicker.svelte | 61 ++ packages/builder/src/common/Dropdown.svelte | 59 ++ .../builder/src/common/DropdownButton.svelte | 68 ++ packages/builder/src/common/ErrorsBox.svelte | 29 + packages/builder/src/common/Modal.svelte | 36 + packages/builder/src/common/NumberBox.svelte | 46 ++ packages/builder/src/common/Textbox.svelte | 32 + packages/builder/src/common/ValuesList.svelte | 47 ++ packages/builder/src/common/core.js | 75 ++ packages/builder/src/common/icon.js | 2 + .../builder/src/database/ActionsHeader.svelte | 62 ++ .../src/database/CollectionView.svelte | 20 + .../builder/src/database/DatabaseRoot.svelte | 129 ++++ .../builder/src/database/FieldView.svelte | 117 ++++ .../builder/src/database/HierarchyRow.svelte | 44 ++ .../builder/src/database/IndexView.svelte | 76 ++ .../builder/src/database/RecordView.svelte | 258 +++++++ packages/builder/src/favicon.png | Bin 0 -> 9059 bytes packages/builder/src/fonts.css | 61 ++ packages/builder/src/global.css | 91 +++ .../builder/src/imgs/budibase-logo-only.png | Bin 0 -> 4980 bytes .../builder/src/imgs/budibase-logo-white.png | Bin 0 -> 12600 bytes packages/builder/src/imgs/budibase-logo.png | Bin 0 -> 12702 bytes packages/builder/src/index.html | 18 + packages/builder/src/main.js | 15 + packages/builder/src/nav/Nav.svelte | 38 + packages/builder/src/nav/NavItem.svelte | 75 ++ .../userInterface/UserInterfaceRoot.svelte | 11 + packages/core | 2 +- packages/server/.vscode/launch.json | 55 +- packages/server/app.js | 4 +- .../appPackages/testApp/dist/package.tar.gz | Bin 1213 -> 1211 bytes packages/server/config.js | 3 +- packages/server/config.sample.js | 7 +- packages/server/index.js | 9 +- .../server/initialise/initialiseBudibase.js | 2 +- packages/server/middleware/routers.js | 31 + .../testApp/3-VYAktSELSd/access_levels.json | 75 -- .../testApp/3-VYAktSELSd/appDefinition.json | 84 --- .../testApp/3-VYAktSELSd/plugins.js | 9 - packages/server/tests/testApp.js | 4 +- packages/server/utilities/builder.js | 31 + packages/server/utilities/createAppPackage.js | 14 +- packages/server/utilities/fsawait.js | 1 + packages/server/utilities/targzAppPackage.js | 2 +- packages/server/yarn.lock | 13 +- 76 files changed, 4533 insertions(+), 217 deletions(-) create mode 100644 packages/builder/.gitignore create mode 100644 packages/builder/AUTHORS.md create mode 100644 packages/builder/CONTRIBUTING.md create mode 100644 packages/builder/LICENSE.md create mode 100644 packages/builder/README.md create mode 100644 packages/builder/package.json create mode 100644 packages/builder/rollup.config.js create mode 100644 packages/builder/src/App.svelte create mode 100644 packages/builder/src/NoPackage.svelte create mode 100644 packages/builder/src/PackageRoot.svelte create mode 100644 packages/builder/src/accessLevels/AccessLevelView.svelte create mode 100644 packages/builder/src/accessLevels/AccessLevelsRoot.svelte create mode 100644 packages/builder/src/actionsAndTriggers/ActionView.svelte create mode 100644 packages/builder/src/actionsAndTriggers/Actions.svelte create mode 100644 packages/builder/src/actionsAndTriggers/ActionsAndTriggersRoot.svelte create mode 100644 packages/builder/src/actionsAndTriggers/TriggerView.svelte create mode 100644 packages/builder/src/actionsAndTriggers/Triggers.svelte create mode 100644 packages/builder/src/assets/budibase-logo-only.png create mode 100644 packages/builder/src/assets/budibase-logo-white.png create mode 100644 packages/builder/src/assets/budibase-logo.png create mode 100644 packages/builder/src/assets/lato-latin-ext.woff2 create mode 100644 packages/builder/src/assets/lato-latin.woff2 create mode 100644 packages/builder/src/builderStore/createPackage.js create mode 100644 packages/builder/src/builderStore/index.js create mode 100644 packages/builder/src/builderStore/store.js create mode 100644 packages/builder/src/common/Button.svelte create mode 100644 packages/builder/src/common/ButtonGroup.svelte create mode 100644 packages/builder/src/common/Checkbox.svelte create mode 100644 packages/builder/src/common/CodeArea.svelte create mode 100644 packages/builder/src/common/ComingSoon.svelte create mode 100644 packages/builder/src/common/DatePicker.svelte create mode 100644 packages/builder/src/common/Dropdown.svelte create mode 100644 packages/builder/src/common/DropdownButton.svelte create mode 100644 packages/builder/src/common/ErrorsBox.svelte create mode 100644 packages/builder/src/common/Modal.svelte create mode 100644 packages/builder/src/common/NumberBox.svelte create mode 100644 packages/builder/src/common/Textbox.svelte create mode 100644 packages/builder/src/common/ValuesList.svelte create mode 100644 packages/builder/src/common/core.js create mode 100644 packages/builder/src/common/icon.js create mode 100644 packages/builder/src/database/ActionsHeader.svelte create mode 100644 packages/builder/src/database/CollectionView.svelte create mode 100644 packages/builder/src/database/DatabaseRoot.svelte create mode 100644 packages/builder/src/database/FieldView.svelte create mode 100644 packages/builder/src/database/HierarchyRow.svelte create mode 100644 packages/builder/src/database/IndexView.svelte create mode 100644 packages/builder/src/database/RecordView.svelte create mode 100644 packages/builder/src/favicon.png create mode 100644 packages/builder/src/fonts.css create mode 100644 packages/builder/src/global.css create mode 100644 packages/builder/src/imgs/budibase-logo-only.png create mode 100644 packages/builder/src/imgs/budibase-logo-white.png create mode 100644 packages/builder/src/imgs/budibase-logo.png create mode 100644 packages/builder/src/index.html create mode 100644 packages/builder/src/main.js create mode 100644 packages/builder/src/nav/Nav.svelte create mode 100644 packages/builder/src/nav/NavItem.svelte create mode 100644 packages/builder/src/userInterface/UserInterfaceRoot.svelte delete mode 100644 packages/server/runtime_apps/testApp/3-VYAktSELSd/access_levels.json delete mode 100644 packages/server/runtime_apps/testApp/3-VYAktSELSd/appDefinition.json delete mode 100644 packages/server/runtime_apps/testApp/3-VYAktSELSd/plugins.js create mode 100644 packages/server/utilities/builder.js diff --git a/packages/builder/.gitignore b/packages/builder/.gitignore new file mode 100644 index 000000000..328f7f0f3 --- /dev/null +++ b/packages/builder/.gitignore @@ -0,0 +1,7 @@ +.DS_Store +node_modules +node_modules_win +package-lock.json +yarn.lock +release/ +dist/ \ No newline at end of file diff --git a/packages/builder/AUTHORS.md b/packages/builder/AUTHORS.md new file mode 100644 index 000000000..3411a7267 --- /dev/null +++ b/packages/builder/AUTHORS.md @@ -0,0 +1,4 @@ +Contributors +=== + +* Michael Shanks - [@mikebudi](https://github.com/mikebudi) \ No newline at end of file diff --git a/packages/builder/CONTRIBUTING.md b/packages/builder/CONTRIBUTING.md new file mode 100644 index 000000000..24bd68258 --- /dev/null +++ b/packages/builder/CONTRIBUTING.md @@ -0,0 +1,22 @@ +### Contributing to budibase-core + +* The contributors are listed in [AUTHORS.md](https://github.com/budibase/builder/blob/master/AUTHORS.md) (add yourself). + +* This project uses a modified version of the MPLv2 license, see [LICENSE](https://github.com/budibase/builder/blob/master/LICENSE.md). + +* 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. + +* Please maintain the existing code style. + +* Please try to keep your commits small and focussed. + +* If the project diverges from your branch, please rebase instead of merging. This makes the commit graph easier to read. + +#### p.S... + +I am using contribution guidelines from the fantastic [ZeroMQ](https://github.com/zeromq) community. If you are interested why, it's because I believe in the ethos laid out by this community, and written about in depth in the book ["Social Architecture"](https://www.amazon.com/Social-Architecture-Building-line-Communities/dp/1533112452) by Pieter Hintjens. + +I am very much open to evolving this to suit our needs. + +Love from [Mike](https://github.com/mikebudi). diff --git a/packages/builder/LICENSE.md b/packages/builder/LICENSE.md new file mode 100644 index 000000000..0ad25db4b --- /dev/null +++ b/packages/builder/LICENSE.md @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/packages/builder/README.md b/packages/builder/README.md new file mode 100644 index 000000000..7256dfd00 --- /dev/null +++ b/packages/builder/README.md @@ -0,0 +1,6 @@ +## Get Started + +`npm install` + +Webpack dev server (port 8080): `npm run dev` +Build `npm run build` diff --git a/packages/builder/package.json b/packages/builder/package.json new file mode 100644 index 000000000..7d681ab64 --- /dev/null +++ b/packages/builder/package.json @@ -0,0 +1,40 @@ +{ + "name": "budibase-builder", + "version": "0.0.1", + "license": "AGPL-3.0", + "scripts": { + "build": "rollup -c", + "start": "rollup -c -w" + }, + "dependencies": { + "@nx-js/compiler-util": "^2.0.0", + "budibase-core": "file:../core/dist", + "date-fns": "^1.29.0", + "feather-icons": "^4.21.0", + "flatpickr": "^4.5.7", + "lodash": "^4.17.11", + "lunr": "^2.3.5", + "safe-buffer": "^5.1.2", + "shortid": "^2.2.8", + "string_decoder": "^1.2.0", + "uikit": "^3.1.5" + }, + "devDependencies": { + "browser-sync": "^2.26.7", + "http-proxy-middleware": "^0.19.1", + "npm-run-all": "^4.1.5", + "rollup": "^1.12.0", + "rollup-plugin-alias": "^1.5.2", + "rollup-plugin-browsersync": "^1.0.0", + "rollup-plugin-commonjs": "^10.0.0", + "rollup-plugin-copy": "^3.0.0", + "rollup-plugin-livereload": "^1.0.0", + "rollup-plugin-node-builtins": "^2.1.2", + "rollup-plugin-node-globals": "^1.4.0", + "rollup-plugin-node-resolve": "^5.2.0", + "rollup-plugin-svelte": "^5.0.3", + "rollup-plugin-terser": "^4.0.4", + "rollup-plugin-url": "^2.2.2", + "svelte": "^3.0.0" + } +} diff --git a/packages/builder/rollup.config.js b/packages/builder/rollup.config.js new file mode 100644 index 000000000..6f7eddcd1 --- /dev/null +++ b/packages/builder/rollup.config.js @@ -0,0 +1,113 @@ +import svelte from 'rollup-plugin-svelte'; +import resolve from 'rollup-plugin-node-resolve'; +import commonjs from 'rollup-plugin-commonjs'; +import url from 'rollup-plugin-url'; +import livereload from 'rollup-plugin-livereload'; +import { terser } from 'rollup-plugin-terser'; +import builtins from 'rollup-plugin-node-builtins'; +import nodeglobals from 'rollup-plugin-node-globals'; +import copy from 'rollup-plugin-copy'; +import browsersync from "rollup-plugin-browsersync"; +import proxy from "http-proxy-middleware"; + +const apiProxy = proxy('/api', { + target: 'http://localhost:4001/_builder', + logLevel: "debug", + changeOrigin: true, + cookieDomainRewrite: true, + onProxyReq(proxyReq) { + if (proxyReq.getHeader("origin")) { + proxyReq.setHeader("origin", target) + } + } +}); + +const production = !process.env.ROLLUP_WATCH; + +const lodash_fp_exports = ["union", "reduce", "isUndefined", "cloneDeep", "split", "some", "map", "filter", "isEmpty", "countBy", "includes", "last", "find", "constant", +"take", "first", "intersection", "mapValues", "isNull", "has", "isNumber", "isString", "isBoolean", "isDate", "isArray", "isObject", "clone", "values", "keyBy", +"keys", "orderBy", "concat", "reverse", "difference", "merge", "flatten", "each", "pull", "join", "defaultCase", "uniqBy", "every", "uniqWith", "isFunction", "groupBy", +"differenceBy", "intersectionBy", "isEqual", "max", "sortBy", "assign"]; + +const lodash_exports = ["toNumber", "flow", "isArray", "join", "replace", "trim", "dropRight", "takeRight", "head", "isUndefined", "isNull", "isNaN", "reduce", "isEmpty", +"constant", "tail", "includes", "startsWith", "findIndex", "isInteger", "isDate", "isString", "split", "clone", "keys", "isFunction", "merge", "has", "isBoolean", "isNumber", +"isObjectLike", "assign", "some", "each", "find", "orderBy", "union", "cloneDeep"]; + +const writeoptions = {dest: "output/output.js"}; + +export default { + input: 'src/main.js', + output: { + sourcemap: true, + format: 'iife', + name: 'app', + file: 'dist/bundle.js' + }, + plugins: [ + copy({ + targets: [ + { src: 'src/index.html', dest: 'dist' }, + { src: 'src/favicon.png', dest: 'dist' } + ] + }), + + svelte({ + // enable run-time checks when not in production + dev: !production, + include: 'src/**/*.svelte', + // we'll extract any component CSS out into + // a separate file — better for performance + css: css => { + css.write('dist/bundle.css'); + } + }), + + // If you have external dependencies installed from + // npm, you'll most likely need these plugins. In + // some cases you'll need additional configuration — + // consult the documentation for details: + // https://github.com/rollup/rollup-plugin-commonjs + resolve({ + browser: true, + dedupe: importee => importee === 'svelte' || importee.startsWith('svelte/') + + }), + commonjs({ + namedExports: { + "lodash/fp": lodash_fp_exports, + "lodash":lodash_exports, + "shortid": ["generate"] + }, + include: /node_modules/ + }), + url({ + limit: 0, + include: ["**/*.woff2", "**/*.png"], + fileName: "[dirname][name][extname]", + emitFiles: true + }), + url({ + limit: 0, + include: ["**/*.css"], + fileName: "[name][extname]", + emitFiles: true + }), + builtins(), + nodeglobals(), + + // Watch the `dist` directory and refresh the + // browser on changes when not in production + !production && livereload('dist'), + !production && browsersync({ + server: 'dist', + middleware: [apiProxy] + }), + + // If we're building for production (npm run build + // instead of npm run dev), minify + production && terser() + ], + watch: { + clearScreen: false + } +}; diff --git a/packages/builder/src/App.svelte b/packages/builder/src/App.svelte new file mode 100644 index 000000000..cc1beff9b --- /dev/null +++ b/packages/builder/src/App.svelte @@ -0,0 +1,38 @@ + + +
+ + {#await init} + +

loading

+ + {:then result} + {#if $database.hasAppPackage} + + {/if} + + {#if !$database.hasAppPackage} + + {/if} + + {:catch err} +

{err}

+ {/await} +
+ + \ No newline at end of file diff --git a/packages/builder/src/NoPackage.svelte b/packages/builder/src/NoPackage.svelte new file mode 100644 index 000000000..eb0cade2e --- /dev/null +++ b/packages/builder/src/NoPackage.svelte @@ -0,0 +1,55 @@ + + +
+
+ +
+ +
+

What would you like not to do?

+ + +
+
+
+
+ + \ No newline at end of file diff --git a/packages/builder/src/PackageRoot.svelte b/packages/builder/src/PackageRoot.svelte new file mode 100644 index 000000000..adf483381 --- /dev/null +++ b/packages/builder/src/PackageRoot.svelte @@ -0,0 +1,49 @@ + + +
+
+ + + + \ No newline at end of file diff --git a/packages/builder/src/accessLevels/AccessLevelView.svelte b/packages/builder/src/accessLevels/AccessLevelView.svelte new file mode 100644 index 000000000..24e962cc3 --- /dev/null +++ b/packages/builder/src/accessLevels/AccessLevelView.svelte @@ -0,0 +1,96 @@ + + +
+ + + + + + {#each permissionMatrix as permission} +
+ +
+ {/each} + + + + + + + + +
+ + \ No newline at end of file diff --git a/packages/builder/src/accessLevels/AccessLevelsRoot.svelte b/packages/builder/src/accessLevels/AccessLevelsRoot.svelte new file mode 100644 index 000000000..b6d46f32e --- /dev/null +++ b/packages/builder/src/accessLevels/AccessLevelsRoot.svelte @@ -0,0 +1,116 @@ + + +
+ + + + + +{#if $database.accessLevels} + + + + + + + + + + {#each $database.accessLevels as level} + + + + + + {/each} + +
NamePermissions
{level.name}{getPermissionsString(level.permissions)} + onLevelEdit(level)}>{@html getIcon("edit")} + onLevelDelete(level)}>{@html getIcon("trash")} +
+{:else} +(no actions added) +{/if} + + + + {#if isEditing} + + {/if} + + + +
+ + \ No newline at end of file diff --git a/packages/builder/src/actionsAndTriggers/ActionView.svelte b/packages/builder/src/actionsAndTriggers/ActionView.svelte new file mode 100644 index 000000000..8f06b4257 --- /dev/null +++ b/packages/builder/src/actionsAndTriggers/ActionView.svelte @@ -0,0 +1,115 @@ + + +
+ + + + + + + + +
+ +
+ + + +
+
+ {#each initialOptions as option} + {option.key} : {option.value} removeOption(option)}>{@html getIcon("trash-2")} + {/each} +
+
+ + + + + + + +
+ + + \ No newline at end of file diff --git a/packages/builder/src/actionsAndTriggers/Actions.svelte b/packages/builder/src/actionsAndTriggers/Actions.svelte new file mode 100644 index 000000000..91c5cd57e --- /dev/null +++ b/packages/builder/src/actionsAndTriggers/Actions.svelte @@ -0,0 +1,95 @@ + + +

Actions

+ +{#if $database.actions} + + + + + + + + + + + + {#each $database.actions as action} + + + + + + + + {/each} + +
DescriptionBehaviour SourceBehaviour NameDefault Options
{action.name}{action.behaviourSource}{action.behaviourName}{@html getDefaultOptionsHtml(action.initialOptions)} + onActionEdit(action)}>{@html getIcon("edit")} + onActionDelete(action)}>{@html getIcon("trash")} +
+{:else} +(no actions added) +{/if} + + + + {#if isEditing} + + {/if} + + + + \ No newline at end of file diff --git a/packages/builder/src/actionsAndTriggers/ActionsAndTriggersRoot.svelte b/packages/builder/src/actionsAndTriggers/ActionsAndTriggersRoot.svelte new file mode 100644 index 000000000..aeae9f398 --- /dev/null +++ b/packages/builder/src/actionsAndTriggers/ActionsAndTriggersRoot.svelte @@ -0,0 +1,115 @@ + + +
+ + + + + + + + + + +
+ + \ No newline at end of file diff --git a/packages/builder/src/actionsAndTriggers/TriggerView.svelte b/packages/builder/src/actionsAndTriggers/TriggerView.svelte new file mode 100644 index 000000000..58520f459 --- /dev/null +++ b/packages/builder/src/actionsAndTriggers/TriggerView.svelte @@ -0,0 +1,64 @@ + + +
+ + + + + + + + + + + + + +
+ + \ No newline at end of file diff --git a/packages/builder/src/actionsAndTriggers/Triggers.svelte b/packages/builder/src/actionsAndTriggers/Triggers.svelte new file mode 100644 index 000000000..bccd45ee1 --- /dev/null +++ b/packages/builder/src/actionsAndTriggers/Triggers.svelte @@ -0,0 +1,84 @@ + + +

Triggers

+ +{#if $database.triggers} + + + + + + + + + + + + {#each $database.triggers as trigger} + + + + + + + + {/each} + +
EventActionConditionCreate Options
{trigger.eventName}{trigger.actionName}{trigger.condition}{trigger.optionsCreator} + onTriggerEdit(trigger)}>{@html getIcon("edit")} + onTriggerDelete(trigger)}>{@html getIcon("trash")} +
+{:else} +(no triggers added) +{/if} + + + + {#if isEditing} + + {/if} + + + \ No newline at end of file diff --git a/packages/builder/src/assets/budibase-logo-only.png b/packages/builder/src/assets/budibase-logo-only.png new file mode 100644 index 0000000000000000000000000000000000000000..652444e5bdcad3ad5a11c9a781acf69b1f93fc68 GIT binary patch literal 4980 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 Zr5oRgtwB=Zt{Mm= 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 WLMMb$jYUhZR2d0*@lw&Re*XuLUll+A literal 0 HcmV?d00001 diff --git a/packages/builder/src/assets/lato-latin-ext.woff2 b/packages/builder/src/assets/lato-latin-ext.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..0a0ee5eaed224a66bf69a2887e059cbfd5d579c2 GIT binary patch literal 5480 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 literal 0 HcmV?d00001 diff --git a/packages/builder/src/assets/lato-latin.woff2 b/packages/builder/src/assets/lato-latin.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..6904b6649ffa9ae838ec975c22159a5352ab92a9 GIT binary patch literal 23484 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 { + packageInfo.createNewPackage(""); + const root = createNewHeirarchy(); + database.importAppDefinition({ + hierarchy:root, + actions:[], + triggers:[], + accessLevels: [], + accessLevelsVersion: 0 + }); +}; + +const testroot = { + "name": "root", + "type": "root", + "children": [ + { + "name": "settings", + "type": "record", + "fields": [ + { + "name": "appName", + "type": "string", + "typeOptions": { + "maxLength": null, + "values": null, + "allowDeclaredValuesOnly": false + }, + "label": "appName", + "getInitialValue": "default", + "getUndefinedValue": "default" + } + ], + "children": [], + "validationRules": [], + "nodeId": 1, + "indexes": [], + "allidsShardFactor": 64, + "collectionName": "", + "isSingle": true + }, + { + "name": "customer", + "type": "record", + "fields": [ + { + "name": "surname", + "type": "string", + "typeOptions": { + "maxLength": null, + "values": null, + "allowDeclaredValuesOnly": false + }, + "label": "surname", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "isalive", + "type": "bool", + "typeOptions": { + "allowNulls": true + }, + "label": "isalive", + "getInitialValue": "true", + "getUndefinedValue": "default" + }, + { + "name": "createddate", + "type": "datetime", + "typeOptions": { + "maxValue": "+275760-09-13T00:00:00.000Z", + "minValue": "-271821-04-20T00:00:00.000Z" + }, + "label": "createddate", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "age", + "type": "number", + "typeOptions": { + "maxValue": 9007199254740991, + "minValue": -9007199254740991, + "decimalPlaces": 0 + }, + "label": "age", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "profilepic", + "type": "file", + "typeOptions": {}, + "label": "profilepic", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "partner", + "type": "reference", + "typeOptions": { + "indexNodeKey": "/partnersReference", + "displayValue": "name", + "reverseIndexNodeKeys": [ + "/partners/4-{id}/partnerCustomers" + ] + }, + "label": "partner", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "referredBy", + "type": "reference", + "typeOptions": { + "indexNodeKey": "/customer_index", + "displayValue": "surname", + "reverseIndexNodeKeys": [ + "/customers/2-{id}/referredToCustomers" + ] + }, + "label": "referredBy", + "getInitialValue": "default", + "getUndefinedValue": "default" + } + ], + "children": [ + { + "name": "invoice", + "type": "record", + "fields": [ + { + "name": "totalIncVat", + "type": "number", + "typeOptions": { + "maxValue": 9007199254740991, + "minValue": -9007199254740991, + "decimalPlaces": 2 + }, + "label": "totalIncVat", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "createdDate", + "type": "datetime", + "typeOptions": { + "maxValue": "+275760-09-13T00:00:00.000Z", + "minValue": "-271821-04-20T00:00:00.000Z" + }, + "label": "createdDate", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "paidAmount", + "type": "number", + "typeOptions": { + "maxValue": 9007199254740991, + "minValue": -9007199254740991, + "decimalPlaces": 0 + }, + "label": "paidAmount", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "invoiceType", + "type": "string", + "typeOptions": { + "maxLength": null, + "values": null, + "allowDeclaredValuesOnly": false + }, + "label": "invoiceType", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "isWrittenOff", + "type": "bool", + "typeOptions": { + "allowNulls": true + }, + "label": "isWrittenOff", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "customer", + "type": "reference", + "typeOptions": { + "indexNodeKey": "/customersReference", + "reverseIndexNodeKeys": [ + "/customers/2-{id}/invoice_index" + ], + "displayValue": "name" + }, + "label": "customer", + "getInitialValue": "default", + "getUndefinedValue": "default" + } + ], + "children": [ + { + "name": "charge", + "type": "record", + "fields": [ + { + "name": "amount", + "type": "number", + "typeOptions": { + "maxValue": 9007199254740991, + "minValue": -9007199254740991, + "decimalPlaces": 0 + }, + "label": "amount", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "partnerInvoice", + "type": "reference", + "typeOptions": { + "reverseIndexNodeKeys": [ + "/partners/4-{id}/invoices/6-{id}/partnerCharges" + ], + "displayValue": "createdDate", + "indexNodeKey": "/partners/4-{id}/partnerInvoices_index" + }, + "label": "partnerInvoice", + "getInitialValue": "default", + "getUndefinedValue": "default" + } + ], + "children": [], + "validationRules": [], + "nodeId": 10, + "indexes": [], + "allidsShardFactor": 1, + "collectionName": "charges", + "isSingle": false + } + ], + "validationRules": [], + "nodeId": 8, + "indexes": [ + { + "name": "charge_index", + "type": "index", + "map": "return {...record};", + "filter": "", + "indexType": "ancestor", + "getShardName": "", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [ + 10 + ], + "nodeId": 11 + } + ], + "allidsShardFactor": 1, + "collectionName": "invoices", + "isSingle": false + } + ], + "validationRules": [], + "nodeId": 2, + "indexes": [ + { + "name": "invoice_index", + "type": "index", + "map": "return {createdDate: record.createdDate, totalIncVat: record.totalIncVat};", + "filter": "", + "indexType": "ancestor", + "getShardName": "", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [ + 8 + ], + "nodeId": 9 + }, + { + "name": "referredToCustomers", + "type": "index", + "map": "return {...record};", + "filter": "", + "indexType": "reference", + "getShardName": "return !record.surname ? 'null' : record.surname.substring(0,1);", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [ + 2 + ], + "nodeId": 14 + }, + { + "name": "invoicesByOutstanding", + "type": "index", + "map": "return {...record};", + "filter": "", + "indexType": "ancestor", + "getShardName": "return (record.totalIncVat > record.paidAmount ? 'outstanding' : 'paid');", + "getSortKey": "record.id", + "aggregateGroups": [ + { + "name": "all_invoices_by_type", + "type": "aggregateGroup", + "groupBy": "return record.invoiceType", + "aggregates": [ + { + "name": "totalIncVat", + "aggregatedValue": "return record.totalIncVat" + } + ], + "condition": "", + "nodeId": 26 + } + ], + "allowedRecordNodeIds": [ + 6, + 8 + ], + "nodeId": 25 + } + ], + "allidsShardFactor": 64, + "collectionName": "customers", + "isSingle": false + }, + { + "name": "partner", + "type": "record", + "fields": [ + { + "name": "businessName", + "type": "string", + "typeOptions": { + "maxLength": null, + "values": null, + "allowDeclaredValuesOnly": false + }, + "label": "businessName", + "getInitialValue": "default", + "getUndefinedValue": "default" + } + ], + "children": [ + { + "name": "invoice", + "type": "record", + "fields": [ + { + "name": "totalIncVat", + "type": "number", + "typeOptions": { + "maxValue": 9007199254740991, + "minValue": -9007199254740991, + "decimalPlaces": 2 + }, + "label": "totalIncVat", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "createdDate", + "type": "datetime", + "typeOptions": { + "maxValue": "+275760-09-13T00:00:00.000Z", + "minValue": "-271821-04-20T00:00:00.000Z" + }, + "label": "createdDate", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "paidAmount", + "type": "number", + "typeOptions": { + "maxValue": 9007199254740991, + "minValue": -9007199254740991, + "decimalPlaces": 0 + }, + "label": "paidAmount", + "getInitialValue": "default", + "getUndefinedValue": "default" + } + ], + "children": [], + "validationRules": [], + "nodeId": 6, + "indexes": [ + { + "name": "partnerCharges", + "type": "index", + "map": "return {...record};", + "filter": "", + "indexType": "reference", + "getShardName": "", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [ + { + "name": "charge", + "type": "record", + "fields": [ + { + "name": "amount", + "type": "number", + "typeOptions": { + "maxValue": 9007199254740991, + "minValue": -9007199254740991, + "decimalPlaces": 0 + }, + "label": "amount", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "partnerInvoice", + "type": "reference", + "typeOptions": { + "reverseIndexNodeKeys": [ + "/partners/4-{id}/invoices/6-{id}/partnerCharges" + ], + "displayValue": "createdDate", + "indexNodeKey": "/partners/4-{id}/partnerInvoices_index" + }, + "label": "partnerInvoice", + "getInitialValue": "default", + "getUndefinedValue": "default" + } + ], + "children": [], + "validationRules": [], + "nodeId": 10, + "indexes": [], + "allidsShardFactor": 1, + "collectionName": "charges", + "isSingle": false + } + ], + "nodeId": 15 + } + ], + "allidsShardFactor": 1, + "collectionName": "invoices", + "isSingle": false + } + ], + "validationRules": [], + "nodeId": 4, + "indexes": [ + { + "name": "partnerInvoices_index", + "type": "index", + "map": "return {...record};", + "filter": "", + "indexType": "ancestor", + "getShardName": "", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [ + 6 + ], + "nodeId": 7 + }, + { + "name": "partnerCustomers", + "type": "index", + "map": "return {...record};", + "filter": "record.isalive === true", + "indexType": "reference", + "getShardName": "", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [ + 2 + ], + "nodeId": 13 + } + ], + "allidsShardFactor": 64, + "collectionName": "partners", + "isSingle": false + } + ], + "pathMaps": [], + "indexes": [ + { + "name": "customer_index", + "type": "index", + "map": "return record;", + "filter": "", + "indexType": "ancestor", + "getShardName": "", + "getSortKey": "record.id", + "aggregateGroups": [ + { + "name": "Customers Summary", + "type": "aggregateGroup", + "groupBy": "", + "aggregates": [ + { + "name": "all customers - age breakdown", + "aggregatedValue": "return record.age" + } + ], + "condition": "", + "nodeId": 24 + } + ], + "allowedRecordNodeIds": [ + 2 + ], + "nodeId": 3 + }, + { + "name": "partner_index", + "type": "index", + "map": "return {...record};", + "filter": "", + "indexType": "ancestor", + "getShardName": "", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [ + 4 + ], + "nodeId": 5 + }, + { + "name": "partnersReference", + "type": "index", + "map": "return {name:record.businessName};", + "filter": "", + "indexType": "ancestor", + "getShardName": "", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [ + 4 + ], + "nodeId": 12 + }, + { + "name": "customersReference", + "type": "index", + "map": "return {name:record.surname}", + "filter": "record.isalive === true", + "indexType": "ancestor", + "getShardName": "", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [ + 2 + ], + "nodeId": 16 + }, + { + "name": "deceased", + "type": "index", + "map": "return {surname: record.surname, age:record.age};", + "filter": "record.isalive === false", + "indexType": "ancestor", + "getShardName": "", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [ + 2 + ], + "nodeId": 17 + }, + { + "name": "customer_invoices", + "type": "index", + "map": "return record;", + "filter": "record.type === 'invoice'", + "indexType": "ancestor", + "getShardName": "", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [ + 8 + ], + "nodeId": 18 + }, + { + "name": "Outstanding Invoices", + "type": "index", + "map": "return {...record};", + "filter": "record.type === 'invoice' && record.paidAmount < record.totalIncVat", + "indexType": "ancestor", + "getShardName": "", + "getSortKey": "record.id", + "aggregateGroups": [ + { + "name": "all_invoices", + "type": "aggregateGroup", + "groupBy": "", + "aggregates": [], + "condition": "", + "nodeId": 20 + }, + { + "name": "all_invoices_by_type", + "type": "aggregateGroup", + "groupBy": "return record.invoiceType", + "aggregates": [ + { + "name": "totalIncVat", + "aggregatedValue": "return record.totalIncVat" + }, + { + "name": "paidAmount", + "aggregatedValue": "return record.paidAmount" + } + ], + "condition": "", + "nodeId": 21 + }, + { + "name": "written_off", + "type": "aggregateGroup", + "groupBy": "return record.invoiceType", + "aggregates": [ + { + "name": "totalIncVat", + "aggregatedValue": "return record.totalIncVat" + } + ], + "condition": "record.isWrittenOff === true", + "nodeId": 22 + } + ], + "allowedRecordNodeIds": [ + 8, + 6 + ], + "nodeId": 19 + }, + { + "name": "customersBySurname", + "type": "index", + "map": "return {...record};", + "filter": "", + "indexType": "ancestor", + "getShardName": "return !record.surname ? 'null' : record.surname.substring(0,1);", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [ + 2 + ], + "nodeId": 23 + } + ], + "nodeId": 0 +} \ No newline at end of file diff --git a/packages/builder/src/builderStore/index.js b/packages/builder/src/builderStore/index.js new file mode 100644 index 000000000..6918c207d --- /dev/null +++ b/packages/builder/src/builderStore/index.js @@ -0,0 +1,19 @@ +import {createPackage} from "./createPackage"; +import getStore from "./store"; +import { last } from "lodash/fp"; + +const appName = last(window.location.hash.substr(1).split("/")); + +export const database = getStore(appName); + +export const createNewPackage = () => + createPackage(packageInfo, database); + +export const initialise = async () => { + try { + await database.initialise(); + } catch(err) { + console.log(err); + } + +} diff --git a/packages/builder/src/builderStore/store.js b/packages/builder/src/builderStore/store.js new file mode 100644 index 000000000..8e5be4623 --- /dev/null +++ b/packages/builder/src/builderStore/store.js @@ -0,0 +1,330 @@ +import {hierarchy as hierarchyFunctions, + common, getTemplateApi } from "budibase-core"; +import {filter, cloneDeep, sortBy, map, + find, isEmpty, groupBy, reduce} from "lodash/fp"; +import {chain, getNode, validate, + constructHierarchy, templateApi} from "../common/core"; +import {writable} from "svelte/store"; + +export const getStore = (appname) => { + + const initial = { + hierarchy: {}, + actions: [], + triggers: [], + currentNodeIsNew: false, + errors: [], + activeNav: "database", + hasAppPackage: (!!appname && appname.length > 0), + accessLevels: [], + currentNode: null}; + + const store = writable(initial); + + store.appname = appname; + store.initialise = initialise(store, initial, appname); + store.newChildRecord = newRecord(store, false); + store.newRootRecord = newRecord(store, true); + store.selectExistingNode = selectExistingNode(store); + store.newChildIndex = newIndex(store, false); + store.newRootIndex = newIndex(store, true); + store.saveCurrentNode = saveCurrentNode(store); + store.importAppDefinition = importAppDefinition(store); + store.deleteCurrentNode = deleteCurrentNode(store); + store.saveField = saveField(store); + store.deleteField = deleteField(store); + store.saveAction = saveAction(store); + store.deleteAction = deleteAction(store); + store.saveTrigger = saveTrigger(store); + store.deleteTrigger = deleteTrigger(store); + store.saveLevel = saveLevel(store); + store.deleteLevel = deleteLevel(store); + store.setActiveNav = setActiveNav(store); + return store; +} + +export default getStore; + +const initialise = (store, initial) => async () => { + + const pkg = await fetch(`/api/${store.appname}/appPackage`) + .then(r => r.json()); + + initial.hierarchy = pkg.appDefinition.hierarchy; + initial.accessLevels = pkg.accessLevels; + initial.actions = reduce((arr, action) => { + arr.push(action); + return arr; + })(pkg.appDefinition.actions, []); + initial.triggers = pkg.appDefinition.triggers; + + if(!!initial.hierarchy && !isEmpty(initial.hierarchy)) { + initial.hierarchy = constructHierarchy(initial.hierarchy); + const shadowHierarchy = createShadowHierarchy(initial.hierarchy); + if(initial.currentNode !== null) + initial.currentNode = getNode( + shadowHierarchy, initial.currentNode.nodeId + ); + } + store.set(initial); + return initial; +} + +const newRecord = (store, useRoot) => () => { + store.update(s => { + s.currentNodeIsNew = true; + const shadowHierarchy = createShadowHierarchy(s.hierarchy); + parent = useRoot ? shadowHierarchy + : getNode( + shadowHierarchy, + s.currentNode.nodeId); + s.errors = []; + s.currentNode = templateApi(shadowHierarchy) + .getNewRecordTemplate(parent, "", true); + return s; + }); +} + + +const selectExistingNode = (store) => (nodeId) => { + store.update(s => { + const shadowHierarchy = createShadowHierarchy(s.hierarchy); + s.currentNode = getNode( + shadowHierarchy, nodeId + ); + s.currentNodeIsNew = false; + s.errors = []; + return s; + }) +} + +const newIndex = (store, useRoot) => () => { + store.update(s => { + s.currentNodeIsNew = true; + s.errors = []; + const shadowHierarchy = createShadowHierarchy(s.hierarchy); + parent = useRoot ? shadowHierarchy + : getNode( + shadowHierarchy, + s.currentNode.nodeId); + + s.currentNode = templateApi(shadowHierarchy) + .getNewIndexTemplate(parent); + return s; + }); +} + +const saveCurrentNode = (store) => () => { + store.update(s => { + + const errors = validate.node(s.currentNode); + s.errors = errors; + if(errors.length > 0) { + return s; + } + + const parentNode = getNode( + s.hierarchy, s.currentNode.parent().nodeId); + + const existingNode = getNode( + s.hierarchy, s.currentNode.nodeId); + + let index = parentNode.children.length; + if(!!existingNode) { + // remove existing + index = existingNode.parent().children.indexOf(existingNode); + existingNode.parent().children = chain(existingNode.parent().children, [ + filter(c => c.nodeId !== existingNode.nodeId) + ]); + } + + // should add node into existing hierarchy + const cloned = cloneDeep(s.currentNode); + templateApi(s.hierarchy).constructNode( + parentNode, + cloned + ); + + const newIndexOfchild = child => { + if(child === cloned) return index; + const currentIndex = parentNode.children.indexOf(child); + return currentIndex >= index ? currentIndex + 1 : currentIndex; + } + + parentNode.children = chain(parentNode.children, [ + sortBy(newIndexOfchild) + ]); + + s.currentNodeIsNew = false; + + savePackage(store, s); + + return s; + }); +} + +const importAppDefinition = store => appDefinition => { + store.update(s => { + s.hierarchy = appDefinition.hierarchy; + s.currentNode = appDefinition.hierarchy.children.length > 0 + ? appDefinition.hierarchy.children[0] + : null; + s.actions = appDefinition.actions; + s.triggers = appDefinition.triggers; + s.currentNodeIsNew = false; + return s; + }); +} + +const deleteCurrentNode = store => () => { + store.update(s => { + const nodeToDelete = getNode(s.hierarchy, s.currentNode.nodeId); + s.currentNode = hierarchyFunctions.isRoot(nodeToDelete.parent()) + ? find(n => n != s.currentNode) + (s.hierarchy.children) + : nodeToDelete.parent(); + if(hierarchyFunctions.isRecord(nodeToDelete)) { + nodeToDelete.parent().children = filter(c => c.nodeId !== nodeToDelete.nodeId) + (nodeToDelete.parent().children); + } else { + nodeToDelete.parent().indexes = filter(c => c.nodeId !== nodeToDelete.nodeId) + (nodeToDelete.parent().indexes); + } + s.errors = []; + savePackage(store, s); + return s; + }); +} + +const saveField = databaseStore => (field) => { + databaseStore.update(db => { + db.currentNode.fields = filter(f => f.name !== field.name) + (db.currentNode.fields); + + templateApi(db.hierarchy).addField(db.currentNode, field); + return db; + }); +} + + +const deleteField = databaseStore => field => { + databaseStore.update(db => { + db.currentNode.fields = filter(f => f.name !== field.name) + (db.currentNode.fields); + + return db; + }); +} + + +const saveAction = store => (newAction, isNew, oldAction=null) => { + store.update(s => { + + const existingAction = isNew + ? null + : find(a => a.name === oldAction.name)(s.actions); + + if(existingAction) { + s.actions = chain(s.actions, [ + map(a => a === existingAction ? newAction : a) + ]); + } else { + s.actions.push(newAction); + } + savePackage(store, s); + return s; + }); +} + +const deleteAction = store => action => { + store.update(s => { + s.actions = filter(a => a.name !== action.name)(s.actions); + savePackage(store, s); + return s; + }); +} + +const saveTrigger = store => (newTrigger, isNew, oldTrigger=null) => { + store.update(s => { + + const existingTrigger = isNew + ? null + : find(a => a.name === oldTrigger.name)(s.triggers); + + if(existingTrigger) { + s.triggers = chain(s.triggers, [ + map(a => a === existingTrigger ? newTrigger : a) + ]); + } else { + s.triggers.push(newTrigger); + } + savePackage(store, s); + return s; + }); +} + +const deleteTrigger = store => trigger => { + store.update(s => { + s.triggers = filter(t => t.name !== trigger.name)(s.triggers); + return s; + }); +} + +const saveLevel = store => (newLevel, isNew, oldLevel=null) => { + store.update(s => { + + const existingLevel = isNew + ? null + : find(a => a.name === oldLevel.name)(s.accessLevels); + + if(existingLevel) { + s.accessLevels = chain(s.accessLevels, [ + map(a => a === existingLevel ? newLevel : a) + ]); + } else { + s.accessLevels.push(newLevel); + } + savePackage(store, s); + return s; + }); +} + +const deleteLevel = store => level => { + store.update(s => { + s.accessLevels = filter(t => t.name !== level.name)(s.accessLevels); + savePackage(store, s); + return s; + }); +} + +const setActiveNav = databaseStore => navName => { + databaseStore.update(db => { + db.activeNav = navName; + return db; + }); +} + +const createShadowHierarchy = hierarchy => + constructHierarchy(JSON.parse(JSON.stringify(hierarchy))); + +const savePackage = (store, db) => { + + const appDefinition = { + hierarchy:db.hierarchy, + triggers:db.triggers, + actions: groupBy("name")(db.actions) + }; + + const data = { + appDefinition, + accessLevels:db.accessLevels + } + + fetch(`/api/${store.appname}/appPackage`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), // body data type must match "Content-Type" header + }); +} diff --git a/packages/builder/src/common/Button.svelte b/packages/builder/src/common/Button.svelte new file mode 100644 index 000000000..7bd6f8e96 --- /dev/null +++ b/packages/builder/src/common/Button.svelte @@ -0,0 +1,161 @@ + + + + + \ No newline at end of file diff --git a/packages/builder/src/common/ButtonGroup.svelte b/packages/builder/src/common/ButtonGroup.svelte new file mode 100644 index 000000000..e0842f08d --- /dev/null +++ b/packages/builder/src/common/ButtonGroup.svelte @@ -0,0 +1,27 @@ + + +
+ +
+ + \ No newline at end of file diff --git a/packages/builder/src/common/Checkbox.svelte b/packages/builder/src/common/Checkbox.svelte new file mode 100644 index 000000000..c1cea90df --- /dev/null +++ b/packages/builder/src/common/Checkbox.svelte @@ -0,0 +1,16 @@ + + +{label} + + \ No newline at end of file diff --git a/packages/builder/src/common/CodeArea.svelte b/packages/builder/src/common/CodeArea.svelte new file mode 100644 index 000000000..29208130c --- /dev/null +++ b/packages/builder/src/common/CodeArea.svelte @@ -0,0 +1,21 @@ + + +
{label}
+ + + \ No newline at end of file diff --git a/packages/builder/src/common/ComingSoon.svelte b/packages/builder/src/common/ComingSoon.svelte new file mode 100644 index 000000000..328ccc24a --- /dev/null +++ b/packages/builder/src/common/ComingSoon.svelte @@ -0,0 +1,17 @@ + + +
+

Coming Sometime: {name}

+
+ + \ No newline at end of file diff --git a/packages/builder/src/common/DatePicker.svelte b/packages/builder/src/common/DatePicker.svelte new file mode 100644 index 000000000..8f09f9091 --- /dev/null +++ b/packages/builder/src/common/DatePicker.svelte @@ -0,0 +1,61 @@ + + + +
+
{label}
+ +
+ + \ No newline at end of file diff --git a/packages/builder/src/common/Dropdown.svelte b/packages/builder/src/common/Dropdown.svelte new file mode 100644 index 000000000..cbe9b9822 --- /dev/null +++ b/packages/builder/src/common/Dropdown.svelte @@ -0,0 +1,59 @@ + + +
+
{label}
+ + {#if multiple} + + + + {:else} + + + {/if} + +
+ + \ No newline at end of file diff --git a/packages/builder/src/common/DropdownButton.svelte b/packages/builder/src/common/DropdownButton.svelte new file mode 100644 index 000000000..61808a74b --- /dev/null +++ b/packages/builder/src/common/DropdownButton.svelte @@ -0,0 +1,68 @@ + + + +
isDroppedDown = !isDroppedDown}> + {@html getIcon(iconName)} + + + + + +
+ + + \ No newline at end of file diff --git a/packages/builder/src/common/ErrorsBox.svelte b/packages/builder/src/common/ErrorsBox.svelte new file mode 100644 index 000000000..3d863f19e --- /dev/null +++ b/packages/builder/src/common/ErrorsBox.svelte @@ -0,0 +1,29 @@ + + +{#if hasErrors} +
+ {#each errors as error} +
{error.field ? `${error.field}: ` : ""}{error.error}
+ {/each} +
+{/if} + + \ No newline at end of file diff --git a/packages/builder/src/common/Modal.svelte b/packages/builder/src/common/Modal.svelte new file mode 100644 index 000000000..6714ba12a --- /dev/null +++ b/packages/builder/src/common/Modal.svelte @@ -0,0 +1,36 @@ + + +
+
+ +
+
+ + + \ No newline at end of file diff --git a/packages/builder/src/common/NumberBox.svelte b/packages/builder/src/common/NumberBox.svelte new file mode 100644 index 000000000..69c471e34 --- /dev/null +++ b/packages/builder/src/common/NumberBox.svelte @@ -0,0 +1,46 @@ + + +
+
{label}
+ +
+ + \ No newline at end of file diff --git a/packages/builder/src/common/Textbox.svelte b/packages/builder/src/common/Textbox.svelte new file mode 100644 index 000000000..f0386da82 --- /dev/null +++ b/packages/builder/src/common/Textbox.svelte @@ -0,0 +1,32 @@ + + +
+
{label}
+ +
+ + \ No newline at end of file diff --git a/packages/builder/src/common/ValuesList.svelte b/packages/builder/src/common/ValuesList.svelte new file mode 100644 index 000000000..ef9039a7f --- /dev/null +++ b/packages/builder/src/common/ValuesList.svelte @@ -0,0 +1,47 @@ + + +
+
{label}
+ +
+ + \ No newline at end of file diff --git a/packages/builder/src/common/core.js b/packages/builder/src/common/core.js new file mode 100644 index 000000000..4b9302794 --- /dev/null +++ b/packages/builder/src/common/core.js @@ -0,0 +1,75 @@ +import {hierarchy as hierarchyFunctions, + common, getTemplateApi, getAuthApi } from "budibase-core"; +import {find, filter, includes, keyBy, some, + flatten, map} from "lodash/fp"; + +export const chain = common.$; + +export const events = common.eventsList; + +export const getNode = (hierarchy, nodeId) => + chain(hierarchy, [ + hierarchyFunctions.getFlattenedHierarchy, + find(n => n.nodeId === nodeId || n.nodeKey() === nodeId) + ]); + +export const constructHierarchy = node => { + if(!node) return node; + return templateApi(node).constructHeirarchy(node); +} + +export const createNewHeirarchy = () => { + return templateApi().getNewRootLevel(); +} + +export const templateApi = hierarchy => getTemplateApi({heirarchy:hierarchy}) +export const authApi = (hierarchy, actions) => getAuthApi({ + heirarchy:hierarchy, actions: keyBy("name")(actions), publish:()=>{}}) + +export const allTypes = templateApi({}).allTypes; + +export const validate = { + all: templateApi({}).validateAll, + node: templateApi({}).validateNode, + field: templateApi({}).validateField +}; + +export const getPotentialReverseReferenceIndexes = (hierarchy, refIndex) => { + const res = chain(hierarchy, [ + hierarchyFunctions.getFlattenedHierarchy, + filter(n => hierarchyFunctions.isAncestor(refIndex)(n) + || hierarchyFunctions.isAncestor(refIndex)(n.parent())), + map(n => n.indexes), + flatten, + filter(hierarchyFunctions.isReferenceIndex) + ]); + + return res; +} + +export const getPotentialReferenceIndexes = (hierarchy, record) => + chain(hierarchy, [ + hierarchyFunctions.getFlattenedHierarchy, + filter(hierarchyFunctions.isAncestorIndex), + filter(i => hierarchyFunctions.isAncestor(record)(i.parent()) + || i.parent().nodeId === record.parent().nodeId + || hierarchyFunctions.isRoot(i.parent())) + ]); + +export const getDefaultTypeOptions = type => + !type ? {} : allTypes[type].getDefaultOptions(); + +export const getNewAction = () => templateApi({}).createAction(); +export const getNewTrigger = () => templateApi({}).createTrigger(); + +export const validateActions = actions => templateApi({}).validateActions(actions); +export const validateTriggers = (triggers, actions) => templateApi({}).validateTriggers(triggers, actions); + +export const generateFullPermissions = (hierarchy, actions) => + authApi(hierarchy,actions).generateFullPermissions(); + +export const getNewAccessLevel = () => + authApi().getNewAccessLevel(); + +export const validateAccessLevels = (hierarchy, actions, accessLevels) => + authApi(hierarchy, actions).validateAccessLevels(accessLevels); \ No newline at end of file diff --git a/packages/builder/src/common/icon.js b/packages/builder/src/common/icon.js new file mode 100644 index 000000000..4648d4ebf --- /dev/null +++ b/packages/builder/src/common/icon.js @@ -0,0 +1,2 @@ +import feather from "feather-icons"; +export default icon => feather.toSvg(icon); \ No newline at end of file diff --git a/packages/builder/src/database/ActionsHeader.svelte b/packages/builder/src/database/ActionsHeader.svelte new file mode 100644 index 000000000..bf1196254 --- /dev/null +++ b/packages/builder/src/database/ActionsHeader.svelte @@ -0,0 +1,62 @@ + + +
+ + + + + {#if !$database.currentNodeIsNew} + + {/if} + + + {#if !!$database.errors && $database.errors.length > 0} +
+ +
+ {/if} + + +
Are you sure you want to delete {$database.currentNode.name} ?
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/packages/builder/src/database/CollectionView.svelte b/packages/builder/src/database/CollectionView.svelte new file mode 100644 index 000000000..b4006b73f --- /dev/null +++ b/packages/builder/src/database/CollectionView.svelte @@ -0,0 +1,20 @@ + + +
+
{record.name}
+
+
{record.nodeKey()}
+
+
+ + \ No newline at end of file diff --git a/packages/builder/src/database/DatabaseRoot.svelte b/packages/builder/src/database/DatabaseRoot.svelte new file mode 100644 index 000000000..cd7fcbd80 --- /dev/null +++ b/packages/builder/src/database/DatabaseRoot.svelte @@ -0,0 +1,129 @@ + + +
+
+
+
Records
+ +
+ {#each $database.hierarchy.children as record} + + {/each} + +
+
Indexes
+ +
+ {#each $database.hierarchy.indexes as index} + + {/each} +
+
+
+ {#if $database.currentNode} + + {/if} +
+
+ {#if !$database.currentNode} +

:)

+ {:else if $database.currentNode.type === "record"} + + {:else} + + {/if} +
+
+
+ + + \ No newline at end of file diff --git a/packages/builder/src/database/FieldView.svelte b/packages/builder/src/database/FieldView.svelte new file mode 100644 index 000000000..5e26dd0c3 --- /dev/null +++ b/packages/builder/src/database/FieldView.svelte @@ -0,0 +1,117 @@ + + +
+ + + + + + {#if isNew} + + {:else} +
{clonedField.name}
+ {/if} + + + + {#if clonedField.type === "string"} + + + + {:else if clonedField.type === "bool"} + + {:else if clonedField.type === "datetime"} + + + {:else if clonedField.type === "number"} + + + + {:else if clonedField.type === "reference"} + n.nodeKey()} + textMember={n => n.name} + bind:selected={clonedField.typeOptions.indexNodeKey} /> + + n.nodeKey()} + textMember={n => n.name} + bind:selected={clonedField.typeOptions.reverseIndexNodeKeys} /> + + + + {:else if clonedField.type.startsWith("array")} + + + {/if} + + + + + + +
+ + \ No newline at end of file diff --git a/packages/builder/src/database/HierarchyRow.svelte b/packages/builder/src/database/HierarchyRow.svelte new file mode 100644 index 000000000..7d5ec35d0 --- /dev/null +++ b/packages/builder/src/database/HierarchyRow.svelte @@ -0,0 +1,44 @@ + + +
+
database.selectExistingNode(node.nodeId)} style="padding-left: {20 + (level * 20)}px"> + {node.name} +
+ {#if node.children} + {#each node.children as child} + + {/each} + {/if} +
+ + + \ No newline at end of file diff --git a/packages/builder/src/database/IndexView.svelte b/packages/builder/src/database/IndexView.svelte new file mode 100644 index 000000000..c1f5bfd7a --- /dev/null +++ b/packages/builder/src/database/IndexView.svelte @@ -0,0 +1,76 @@ + + +
+ + +
+
Records to Index
+ {#each indexableRecords as rec} + toggleAllowedRecord(rec)}/> + {rec.node.name} + {/each} +
+ + + + + + + + + +
+ + \ No newline at end of file diff --git a/packages/builder/src/database/RecordView.svelte b/packages/builder/src/database/RecordView.svelte new file mode 100644 index 000000000..ea3be006c --- /dev/null +++ b/packages/builder/src/database/RecordView.svelte @@ -0,0 +1,258 @@ + + +
+ + +
{record.nodeKey()}
+ {#if !record.isSingle} + + + {/if} + +

+ Fields {@html getIcon("plus")} +

+ + {#if record.fields.length > 0} + + + + + + + + + + + {#each record.fields as field} + + + + + + + {/each} + +
NameTypeOptions
+
{field.label}
+
{field.name}
+
{field.type}{@html getTypeOptions(field.typeOptions)} + editField(field)}>{@html getIcon("edit")} + deleteField(field)}>{@html getIcon("trash")} +
+ {:else} + (no fields added) + {/if} + + {#if editingField} + + + + {/if} + +

+ Indexes +

+ + {#each record.indexes as index} +
+
+ {index.name} + editIndex(index)}>{@html getIcon("edit")} +
+
+ records indexed: + {getIndexAllowedRecords(index)} + type: + {index.indexType} +
+
+ map: + {index.map} +
+ {#if index.filter} +
+ filter: + {index.filter} +
+ {/if} +
+ {:else} + (no indexes added) + {/each} + +
+ + + \ No newline at end of file diff --git a/packages/builder/src/favicon.png b/packages/builder/src/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..897909662a99fe024b8e8e4d6240d824c2b80b2b GIT binary patch literal 9059 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 I+BTv83z1IvmjD0& literal 0 HcmV?d00001 diff --git a/packages/builder/src/fonts.css b/packages/builder/src/fonts.css new file mode 100644 index 000000000..4901cee9f --- /dev/null +++ b/packages/builder/src/fonts.css @@ -0,0 +1,61 @@ +/* latin-ext */ +@font-face { + font-family: 'Lato'; + font-weight: 400; + src: local('Lato Regular'), local('Lato-Regular'), url(./assets/lato-latin-ext.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} + /* latin */ +@font-face { + font-family: 'Lato'; + font-weight: 400; + src: local('Lato Regular'), local('Lato-Regular'), url(./assets/lato-latin.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + + +/* Black latin-ext */ +@font-face { + font-family: 'Lato Black'; + font-weight: 900; + src: local('Lato Regular'), local('Lato-Regular'), url(./assets/lato-latin-ext.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} + /* Black latin */ +@font-face { + font-family: 'Lato Black'; + font-weight: 900; + src: local('Lato Regular'), local('Lato-Regular'), url(./assets/lato-latin.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +/* Bold latin-ext */ +@font-face { + font-family: 'Lato Bold'; + font-weight: 700; + src: local('Lato Regular'), local('Lato-Regular'), url(./assets/lato-latin-ext.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} + /* Bold latin */ +@font-face { + font-family: 'Lato Bold'; + font-weight: 700; + src: local('Lato Regular'), local('Lato-Regular'), url(./assets/lato-latin.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +/* Semi Bold latin-ext */ +@font-face { + font-family: 'Lato Semi Bold'; + font-weight: 600; + src: local('Lato Regular'), local('Lato-Regular'), url(./assets/lato-latin-ext.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} + /* Semi Bold latin */ +@font-face { + font-family: 'Lato Semi Bold'; + font-weight: 600; + src: local('Lato Regular'), local('Lato-Regular'), url(./assets/lato-latin.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + \ No newline at end of file diff --git a/packages/builder/src/global.css b/packages/builder/src/global.css new file mode 100644 index 000000000..241ae0a87 --- /dev/null +++ b/packages/builder/src/global.css @@ -0,0 +1,91 @@ +:root { + --primary100: #454CA0FF; + --primary75: #454CA0BF; + --primary25: #454CA040; + --primary10: #454CA01A; + --primarydark: #3F448A; + + --secondary100: #162B4DFF; + --secondary75: #162B4DBF; + --secondary25: #162B4D40; + --secondary10: #162B4D1A; + --secondarydark: #3F448A; + + --tertiary: #F2F5F7; + + --success100: #49C39EFF; + --success75: #49C39EBF; + --success25: #49C39E40; + --success10: #49C39E1A; + --successdark: #44B492; + + --deletion100: #F2545BFF; + --deletion75: #F2545BBF; + --deletion25: #F2545B40; + --deletion10: #F2545B1A; + --deletiondark: #CF4046; + + --white: #FFFFFF; + --darkslate: #5C6B82; + --slate: #8B95A6; + + --borderradius: 2px; + --borderradiusall: 2px 2px 2px 2px; + + --fontblack: "Lato Black"; + --fontbold: "Lato Bold"; + --fontsemibold: "Lato Semi Bold"; + --fontnormal: "Lato"; + + --bodytext: var(--fontnormal) "regular" var(--secondary100) 16pt; + --bigbodytext: var(--fontnormal) "regular" var(--secondary100) 20pt; + --smallbodytext: var(--fontnormal) "regular" var(--secondary100) 12pt; + --lightbodytext: var(--fontnormal) "regular" var(--darkslate) 16pt; + --heavybodytext: var(--fontbold) "regular" var(--secondary100) 16pt; + --quotation: var(--fontnormal) "italics" var(--darkslate) 16pt; + --smallheavybodytext: var(--fontbold) "regular" var(--secondary100) 14pt; + +} + +html, body { + font-family: var(--fontnormal); + color: var(--secondary100); + padding: 0; + margin: 0; +} + +h1 { + font-family: var(--fontblack); + font-size: 36pt; + color: var(--secondary100); +} + +h2 { + font-family: var(--fontbold); + font-size: 30pt; + color: var(--secondary100); +} + +h3 { + font-family: var(--fontbold); + font-size: 24pt; + color: var(--darkslate); +} + +h4 { + font-family: var(--fontsemibold); + font-size: 18pt; + color: var(--secondary100); +} + +h5 { + font-family: var(--fontblack); + font-size: 14pt; + color: var(--secondary100); +} + +h5 { + font-family: var(--fontblack); + font-size: 12pt; + color: var(--darkslate); +} \ No newline at end of file diff --git a/packages/builder/src/imgs/budibase-logo-only.png b/packages/builder/src/imgs/budibase-logo-only.png new file mode 100644 index 0000000000000000000000000000000000000000..652444e5bdcad3ad5a11c9a781acf69b1f93fc68 GIT binary patch literal 4980 zcmV-)6N~JLP)00001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BKPWN%_+AW3auXJt}lVPtu6$z?nM001F$MObu0a%Ew3X>V>IRB3Hx05UK!IXW;j zIxsjOGBG+eGCDLk)SOef000uVNkl6@bs|t`pmFVyCIsiR%z26dT*L zNqH!tNF}rswW&?ZqY@xQWAOtd9*L27NCi@h@&ke7q)0&jkQAXJNMC8(00P>OBATG8 zaSFDH+vZWbb=Ss;oy4!$JC}Q|??mJEuDy?WoO@?JDczY{*}Hr9+xs}@%osvKLPA19 zLcGF|k0Du5*|=j%#E9O<4>vOg6@~%Zfw55rMi)QkkMMWKl1GPoj&#laM95-<@?}9) zW6Mt7Q@i-#mbsS2;bI=;|JgUx+xd)a3Q0pK-y+~hXF#+=jBt5?5;91(g(G2lLiy5A zzWLsY<+I5S1B{)rsW2GZJ5>~IA3JquRJMe0qVh3B5^rkRU6eGRHVk8%Y$_c7yJAW6 zt1II5)8oT^$7O5a2}eFjRnt9uYK?U8!>rbI1;D3Zvn|p6+);TRSOPC!RsFrS5HnFa z+{JnZ19rfejkYIFA37(S0!Luw!*yNptht-7$9C~)u|hU`3uB}Fx%VZy4?iSZ0!1L@ zi#Igi2NA#xMXhY|6+Q}{0~6YU7Mcl^e1(Qi+y+B4Ml#YGl&Lrn@`)*SCb@@Cal2&` zb=s$5k-fTyX0(@2WG8@i__nUg7hDg5(U#~rd_cBnhqm&07&>tkF%=tTyN;n5?c~GI z35zB7IF_9t0)}R$W6?I9redw+t7>X_$k)(`+h`V=(Lz3)Vi_3wsf144217FjuvXQl zVx{F1Q*6}SPc?Mn0nfl}q)pY(jFR$Q%T567nQI9=N`_{Xt7^f}Nz63=$k#r1$)*s1 z?NQVGTv=uP*!XatGPQ%sjC^8U$0BDE~5crpM z3-tn4k|STxLMI+TvVfJ8e0~*n1_)B284~h^p%V|0SrQ7N8QJs)$NEQeo$3KD+`xyR8fw))$HM-u@YQ;`kMK@}+Tct}{-CW(t-sNTCyyZr45KP_rf` zTjnz`G7I~j8w-SloPrBj3zARSYhrWc&dnw8gZo!!lr9yN@H@Y`0LS~LWQ(R07@EmT zzMzCow$&Ajk#1|du2;TmXuEv02q;{bq<}NbU4!ChQbR1At6AQ z$&#&$O~s4KC;tS%etD`LUQ3q>O8BFL7va*RDO)sSi493c`E(XClrNtcS&67mty1oLC5Q}6=$NGq%CojCUT@e76c&6MRgKLTbqJ>{l?qb@old zh0+y{CE>o#G1)=`OFojHD#qwKA6zTecA8668K*yizR09jJw;NXe&LJ~m`=NXe&czA_{)NXdtxflxsA z=oz>wk7z({&4*RIA@1<-!MyKm;R@vB`^%|GQLPc;EZC>iY5~c~hhUQY3mrqEY$&8K zun(~>DON(0&+Y13nd~-{E1yZH*X&^DHUIb>RSPFQ2m9zNzZ!;;qQqkqY zAg4j;aHLb=LL=qs`BK4ZmoOEl=5@ZxOuL!DQlaJ_4nqGwCIF_Dss48k{+{u@V;`s_ zo*iZ7+j-qGI8#RfW5OfD)9}<7{W}~ex8_?^x>Piiko8`j zlkU>eCGjZX!-*;Q>t(u;0cGUdS{j3IaOt*|=5Zl7N_bld7@O3bmU59Ul@k+5_&Fa5 zPfXC0ki2{aNtc3A69WTB!W+~G&#<><#k!6S6fO=$2}$pEaWnDT4W*8Vhv0{3K6wSq zr>=+(mMZw#@HOIVbwWG@`w;t*;--Y0d>>yKg9odM<(acwldy95|1#mPg#5YjHJHD&$+2nliY$q++x3|oNMOX;XWO1|Eyq&)HgE(V4*gcwds zXp>HaPC^9ard{8Iqjm|q3M^(#mCi|_^MG3RgPeSi{BIgAB?;tcQNm-Bc~6nnR8B!U z1p5@zZA5Ohrd~-siiAa#+=0He?Bc0znX&cy=r214sPCf(${N&kj_&JqP5V40v z&Mch1C`yNYhkdyH^(+3ar!zo4x4SB8h>XVrtCxvmN?_U!@ghc-3n<-V7q7yB3s>oU zd2J|DOlqxFKK8~H(V3J$>8Oc^BOUe?_8CR-?2wnw0z2}@i77FKs8F-!HP|QEH!4VH zp^SVMxM=?F+moS$5=%Pl6KWfZrBF^j3+(8J%T~aH+usX4HLGQ7aKQKcxnNY5b z9$B`gR7khx!|#$U3qkoFIQAOU4quindXP@KR7PHU69zkb;p)hQY@vx#@?|4kDj)3` zn`QC3 zTJGXbdFmTD;;sH*jXZOfnOH;2EHj-mh?AFfucS8p;~z4?)O30hBe|f zxe%#_5BS{QX#I$IEpCiT()v};hd&_-$bEP^f}N{1sIZYWg3l8;<& zH(QE|ilOSljj-v(55bzA^$?k%b^9+jiA^qp%2T!Cy<;C>U#N(3BOiA3dp6w)H*UOj zUZmZd@QMjHF!N{!loI2wgp{aSTS z%ZiDKQRwM=o~(pQ$d`|FsmzvKg^P7>D<@&uz#3THS1s0e`GOLj>V6L1euqv8JwjT( zidF021GjuyJURtRIMUP)6IG+Kg(gl&m&)+SS$MhYDJ~<8YnsXKc1ufF!)>>I*-`Nj z{4lFtemAT;UI)b^SW-?4d`&mJ*dTVXPKt+AuGt75zwK+}cE#l6TWUj5DEJ|xfK(*3 zzn*26+>2LYpKfltN1oAuoO~PB-y)CP#r~l?JA>f}=fWx0>ybB{b{Ao0W>Ow`4=(iGl+cn6p97yOgq(a+B0S(HD8>yh zHs%~#%LM)oO#e}k&hNfWh1{ACgQI?f!c_FFgY_@ml(&TVGx)RkJ1|g80SbLBigy;it@qg&}a738F&n%`BbumD2@>B^`=7GjlG^_-@)zO%DXzWRG>A!eSH zrz8m_%#2DkeGBA6s+wAq_yZ0o9!|wr-xqXLlFmYD`7AIaf)aX_lA{LhU~yeXrCKE` z7#mIWbc$5gyg0y$%KGhw0k!g!Jort=UEKMBld!C)1S-mDU9{~MDBVjhKQ1;Cs*H9P z42^{e?%c$Yj?21~+0{%_^VN?74Tj@S#ZF7Mb&zgAMZYZ$PP%O~#7 zJAc|$VAGKeSija#f4g|p0hF$n?_Tjyd1fOU6Q>WI!^3&zsJpXOo~DsclhMx(#X$99P`&n|U~HovvLNv|K5}}rEMAXNZl7yW zpRr4WA{;R>IVwg$sxiVj>5jn5T~EU0E41&ok_YXH-e;eY$ASeTpGCZ}? zJ)LdxYynHkhhWhG0|O;gCIFo)US&&O=fYuDLTBmtG<(hf)|%*k?x<`^OIGq(R5i6c z#BJUMhM~r`F%R65P{~wSt}r&r45NLh`|w`bvM4#phhQj%#gcn;o{ABaaC6g+f-g4= zgmfI-R7}UBZDXenWqqMY&hlBv`o9i-xMi+IPx8%{=oTQ(1a2q{!)#w_icLq}@>x_h zw(t>V?i1lF9+^=hJ+KxR_GCnz~{hAIDQ*1KQYEO|Bf}`?T#2cFLg9vo! z9GVFd7&-wH+J<^N=cUIA#TEGwF%{36yLAuEXbrCG3}auS`|v}u#Zg?7&q7wo;I3GU zGOeJ1p%Y^^+V0d8n-16Ivj|FPMgzJ4%(i?&C%NL8d=~MhmfZ$pxHAr?VoEp=I>{B! zZzO{C`?2bVM`KB|mKo&@JXd zCqJ2vMO!cY=ddrMogES*pPeu?;~LMvY^2T2&`GY4lg}au1*{(7S?DBJ$jWCCgaTGq z$g!}~56H`hV5)BUY!Y+DS{JZ7MLva{exQVW7Gf%9kv(B(COv+KPI5&l`7DA`z?v-> zIx(2h?qznu2}p!maz%z_9t}e?f_4m@c%7Ya0wqU2J3%U7wc~VQrynRUpG8m#Sj7~Z z#Wk@ippASM+J7n<>*u+tB;n|9N2Ei|J-0jp1ioqiCAk3$F`UF?8bgHL)rX%4fra0#>qxoqiC?mj=hL zEmokg(+@)VGT>MN>s;uhoqA!XAB6HPLB63G)e1ZPAe1jl#sN~2dr(&&N?Hryw~XXq9)LAYs_^0ik7K~;gXS?REj zy*2-d_D+-8N(yl6-Cy^$+$a7?-#GSX*Z;qZjY=}(OR%<%4r6z;kYH$W#nZ~`+~Uw; zb}p_uNa{Z_Rowm?wA{sC{PivTf7Y3hRMAG^UkqZMn*}->HAFxuneV`VOh-DQfiN2@ zZV{ky(f4=%pbAgaM8v;G0)v1L7TM=-xR@N$&H?|R zemsg)a8Kne+UVP2x_`(YW+53a$y7!NDuX8HKja3Vvi5z1!9}ll5A;6@K!_o2>afUF zq);LDpMTfyg%q-UM|jiZmoZ)_zv9p27%QEom=YR@U!J=_ztt~jR?4dD+Gm(vfDnV8 zf^1iPqp8b(o>ug##epL%;{@Ia&4$hx3H#7}`t&J_%i@K47QT@Ui7)+S^-XM3vSi44 zm&fxTj8^R}#wD3@>__l`(5ZcaC=o`!z1CN=%bWJ$1 zkiRTKQZ7sx6ZsDNc|`}7qh%KV3`1{iCPVg_ccEJ~q1TXbR6c%EH}LYzOO;SLWUs&{ z8jLB^uSB_1TxMeA`u^7nVjIY)cAlCA??JuRP$-#fk7w0U}B}QuzTlIiiakC-6 z-~RR+TodpDeV5^s6#YB)HpA6)^%JF7@Au$sI&NKeipBuH9T=|g@UL3db zlJU#Sa-lO*XZHH5dXoA^^NC1sg(oj%hDga-p@8dJ)}}g?SO3>E0XS5C6OvE^Ew=i3 zE@gTqhZ=~e@p4TbdA6FskaH(frjHHkXYnW7q7MyRo#iHPnb_dPSdbuKgUpFISwj3h zbXRNoq%1jdFAr^Z4R5!Oy^Qff^xC4@F79_p9u{*@oP?OTts_(f5?*Z5QNaBRk4`i+`g zoWv{R{t4i1J=n(gE10-wa+60S=+?>Z1@EU0kV3}uumQj)dH)7{mGlyxBA_@zORQ{#u^TwO<&-q28rhO!ZUtCC zaHLKTVog#De^EPT=BY{6ANDgpxMY8J4^eyF_;Yd z(1k+tWdwM_e|24N76>`~de+pp>xM-Ol%nBcl!YXuR@hB@2v#S$R9I6<5V0c@y!qVP ztUUJI9V~pvf3usrrI_nXt>@lsq%U2$H8F_H;Q{&E##|IQN`IcT*?c5uSF`k>pHD+A zwNQT!7#<~A*Ei!iI20SSp~R}9M@Bd9e&x3`s}uf90M86~^a+4sp8Ffk=T@dcQTYmq z6?bC25{GR6;^<{4^>r5y|J$Z!`5Xf6>4L6j%+L5eE1vz>f^t%&oqsMqE_wPII6yt@ zF9dyVjIyc)R|7$ZIhV7;_iha(+Fyd`R1}uVv;CEAioYiP@*et@%#DX3_Hof!AQLG2 zii~)O0R;{f=iBCT{7~!JzKoYA%QdsqB~eA*aQ?~S*sbgy&-tAaeccq@rpGYLPzC%u zsw90w=p81N#PxWm#T#n|Nd z7H}=-e}QCpk>pNisDk?3 z5t?zRP~*GzJG96F2o8`0Z7MRlv0r)tUxxtRNH2EBk?*5eb*hc&tt?U#Ou@sWqi+DN zxKk4Y78?Z&y7PQRIw`Z>65h)udW&QB&o_$T!dNZ$GLDM!4 zWis$~2|LvZMgFL*DsIc1g4`Y>u)hSqBke)ozO%r-Gi~pZgi>rwb}*@aN!#|bHP(`P z-IG?G(QBdILmQqMm5AE?U;{(m7QTs>0JIm}0>(LLbn{+Y#icm*6LUs1L}u)Iby84> zbp@ZS)B~SsI5=BVhCG=s#D~T2`h~teNQNmmKst}a^Anch>Kz4ES)i4hSaA!b8AsKm z#90ovCru!3UA~X%h=|#;KnX~3AUUh}{LePr*G}Rdqm=_eMa23rln-qEZ`x}uPW3a1Noa)&S zY!!+=nF#LG7|09LKSi01ylSpi%JkqwR3K-T&uLz0T>MAZ<+9KZD!3BA~UaNuY3RM&;{; z@vL7ppGG0c{E^XU!={=^Bzhv@$!Jv_qfYiCRA50XVkr@_K+SM(gcCJcM~*mJZ8l;9Maz=aEz(-F!al`Vu2dOHc}Zdk(3l$$EJa?3?qTOU_cc2| zRPtYS@s1rHn0S$W`P`V1f91?8>3nr-1Da4I9`Bc($e10RM1I<`Iv?G6GHnR_+c-Ao zA2j;f$eo+>{ofOhtm|^`Xx*thFDlTlFIy8I_SNKDOe7we_}?%HjK-yFW^6jdMUZ?DFhJ0Cwa zU*DgnYj4-?h3%!@qbDkYWw*Ui5RM&9v2iU?arfQN@NK3C4rkOW4m<_VhBG!(^Us$XTP;y3H zQwdeKA&9b*Max-C?=Pz_ex6UdXc;6zC-eUNkV*2b%p4Gw5`eLgTzQkvJ4nhpG9mZ? z#8~dHUEMD~I@g)pm2D4BW@2=2RpOvMkAvd*qDF z*a6wxU+sWv0W^f6vU+(<@P1}|*`61vIy`S$Um*6|DgPgu%MhbO`L(db0#|SGyY(($ zpB=ng%}olw=AHg}kA)FHqXSAURYm63s*gfIk-m6(vp1gEdF^~+RKQ3t0&2KF^v{HL zU6%2-QbMppR-$p*4J_#By%>+k*wVljhpl`Vxeqa|!_hc4jYu>rhkrZoBpiRc%I~0H zJ%leQT5CyUn)6*oVz~j+9`8nTTo@It2mpT$^C({T4e4Z5xd@dPC4&mg52zO(&OA27 z0>t8^p3~w~GvhC+EsGuiAPd=?=R|axtVq<6f zxx$R_fuIfCl!MLn2Wa4e5Q+Mgk^AFMN;V@xRgV~tRS^fq-PQ?MMEZ$%HaBcKM2J20 zEC&mEu0E2#YVByGT>=DguzJbcu2gQ4(5k`cmL*^JfHUb=)QDe-mhG{k?T_R)i)dwY Zr5oRgtwB=Zt{Mm= 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 WLMMb$jYUhZR2d0*@lw&Re*XuLUll+A literal 0 HcmV?d00001 diff --git a/packages/builder/src/index.html b/packages/builder/src/index.html new file mode 100644 index 000000000..8f5b05b48 --- /dev/null +++ b/packages/builder/src/index.html @@ -0,0 +1,18 @@ + + + + + + + Budibase Builder + + + + + + + + + + + \ No newline at end of file diff --git a/packages/builder/src/main.js b/packages/builder/src/main.js new file mode 100644 index 000000000..ef35ef2a8 --- /dev/null +++ b/packages/builder/src/main.js @@ -0,0 +1,15 @@ +import App from "./App.svelte"; +import "./global.css"; +import "./fonts.css"; +import "./assets/lato-latin-ext.woff2"; +import "./assets/lato-latin.woff2"; +import "./assets/budibase-logo.png"; +import "./assets/budibase-logo-only.png"; +import "uikit/dist/css/uikit.min.css"; +import "uikit/dist/js/uikit.min.js"; + +const app = new App({ + target: document.getElementById("app") +}); + + diff --git a/packages/builder/src/nav/Nav.svelte b/packages/builder/src/nav/Nav.svelte new file mode 100644 index 000000000..01a9d3ce5 --- /dev/null +++ b/packages/builder/src/nav/Nav.svelte @@ -0,0 +1,38 @@ + + + + + + + \ No newline at end of file diff --git a/packages/builder/src/nav/NavItem.svelte b/packages/builder/src/nav/NavItem.svelte new file mode 100644 index 000000000..5feebab58 --- /dev/null +++ b/packages/builder/src/nav/NavItem.svelte @@ -0,0 +1,75 @@ + + +
+ +
+ + + \ No newline at end of file diff --git a/packages/builder/src/userInterface/UserInterfaceRoot.svelte b/packages/builder/src/userInterface/UserInterfaceRoot.svelte new file mode 100644 index 000000000..5ad9d7a3f --- /dev/null +++ b/packages/builder/src/userInterface/UserInterfaceRoot.svelte @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/packages/core b/packages/core index ab14ab9db..d418f210e 160000 --- a/packages/core +++ b/packages/core @@ -1 +1 @@ -Subproject commit ab14ab9db1698a82b1f98b692ecfa6b71c17752a +Subproject commit d418f210e2af6f6a37d590ec255730a0da2241c7 diff --git a/packages/server/.vscode/launch.json b/packages/server/.vscode/launch.json index 1c6688a46..023c59ffd 100644 --- a/packages/server/.vscode/launch.json +++ b/packages/server/.vscode/launch.json @@ -4,35 +4,32 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ - { - "type": "node", - "request": "launch", - "name": "Jest All", - "program": "${workspaceFolder}/node_modules/.bin/jest", - "args": ["--runInBand"], - "console": "integratedTerminal", - "internalConsoleOptions": "neverOpen", - "disableOptimisticBPs": true, - "windows": { - "program": "${workspaceFolder}/node_modules/jest-cli/bin/jest", - } - }, - { - "type": "node", - "request": "launch", - "name": "Jest Current File", - "program": "${workspaceFolder}/node_modules/.bin/jest", - "args": [ - "${fileBasenameNoExtension}", - "--config", - "jest.config.js" - ], - "console": "integratedTerminal", - "internalConsoleOptions": "neverOpen", - "disableOptimisticBPs": true, - "windows": { - "program": "${workspaceFolder}/node_modules/jest/bin/jest", - } + { + "type": "node", + "request": "launch", + "name": "Start Server", + "program": "${workspaceFolder}/index.js" + }, + { + "type": "node", + "request": "launch", + "name": "Jest All", + "program": "${workspaceFolder}/node_modules/.bin/jest", + "args": ["--runInBand"], + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "disableOptimisticBPs": true, + "windows": { + "program": "${workspaceFolder}/node_modules/jest-cli/bin/jest", } + }, + { + "type": "node", + "request": "launch", + "name": "Initialise Budibase", + "program": "${workspaceFolder}/initialise/initialiseBudibase.js", + "args": ["--datastore=local", "--username=test", "--password=test", "--rootPath=./.data", "--cleanDev"], + "console": "externalTerminal" + } ] } \ No newline at end of file diff --git a/packages/server/app.js b/packages/server/app.js index d4c492642..6b288b9e0 100644 --- a/packages/server/app.js +++ b/packages/server/app.js @@ -12,9 +12,9 @@ module.exports = async (budibaseContext) => { app.context.getAppPackage = await initialiseRuntimePackages( budibaseContext, app.context.master, - config.latestAppsPath + config.latestPackagesFolder ); app.use(koaBody({ multipart : true })); app.use(router(config, app).routes()); - return app.listen(); + return app.listen(config.port); }; diff --git a/packages/server/appPackages/testApp/dist/package.tar.gz b/packages/server/appPackages/testApp/dist/package.tar.gz index 49eb5212faa909082a4f94411c01e29e1a26fade..26e2b97a8d553cfa4a184a229d4e3cb45accec75 100644 GIT binary patch literal 1211 zcmV;s1VsBEiwFP!000003hf!&Zre6A&jIoeoG_pX=Gl^b+gx-&k)lAcH650AFN2XX z5^Zy!NtL9W1cv^-hm<8tvYd+@CmZ4e1eV0ZbH9;k9_$`m*X{Ls$ov9Sf72JQ-F18Y zuGjH=V9W{{xPoz&C?%P;dn~myCbeRkxnE39uYaE zN>RZJ+e%w4n!btb_COM>36dlbGF*~LS%{GQPHqfZD*$(hDUqt>{XC~(;w&+f#$8N8 z!pP2<#8J3=O~6{=j#+H#krw4ML7`~0{HHVCR!lbyi>;V$=E1F4UP%gSYBG%&7+Gx+ z4Y7hGf5<*XG>WiNS4Phb7#eAX#PSBEjp#u%2*;O~WYr*!Q6&>CC`J277?qqr>F6 z+uj})fTQRg8BtD+E1zfn>vY;}JO6pzZpUx?cK-9d{rvY7kj{S-N}vb_6VsIzX`fGi zQV5;3uw{EIehem*g_7{%AXq3KIi;-I6&qrqVOD#kGoplrmGQDtmI~DEZ=#*KXGQv zJi<(oGJaAOkKs$g*6KDU`h&?^%q-z_)EVKJ={nRe&@3R&7g7|Fi@3@1Wmt4Yor?{u zbH-whS?iCw$!M*|YZ#T7;i-uEiqa*1Jf2>b1FwW~OAJ_?Ddm~jeqBNhwKQh#jT@4H zPBHtF;lKuwzlv223cD{4j9XN{e|Ti*_X`m#RQbcO>c?WZtSmyxP&fvF!T*YxReKf3 z49OotW0C5L9eUR6f^4IqI-g(}zQ=(U(xmN*Z29DJRt{FR5{^`zL)BoUE?w7U${pG* zH7g3XPODmtdYw{cuBekADoVw4oh}PKGOkX9_2eUtN}|+>w^YP6AJQ;&a8OAkN5ndc z^@SD}BWk(V+%1$*mX{2dWP)c@#PS^eg2nhrc^$@CiPmTFzD$XxnNY~{q%fi`gohq6 z9vi#W+=JkfiPuUD^EB5P7LN7gZA1s@S?3GP-2=f-1)R^|JX+W!QmIZ2n)NW0M;%L! z=E#sYW*WRQC#7_1e}#U6@tbRMt(#_;ZyJO~`ibj7wj_yy)NPu5r{F4-ye_Z=q|lCh zhT9L>mdZ&kD?N{Ch0oc6@2%BkCk8pY#U8hq!6`(<@THtl;N+}#&EuZ;|DNyn;Q-*m z{O@|6zrX)~3W!)drrg~8?~cb^{%?1B`Tu{qy$&+oxA?mgX$ddf|4;#yMk9sZAW6Q( zRFY$7q@0u2M~6p;QxU=p(fy+_KjC0WkHiIWZS0f8m)cyAtmWSTphC*Sw`{XVh3NY&r$CFu10 z{-76hgEsN~LB}7Eo!%4Jwv%W>6`Jx;IaTNWCq%;#v_9o<4qP|?)lxjZj$88I3Hk$@ z{{Wu`ouEVfpgrieas2U3S*91B|LeV7LcA>f-jMubUkSO+esDz4Dd2ZcUIM#F~=b5 zb*drJxXAA_PlF*b)%wEvxrRb(tyEN9k!&Nnmkbc}j02I1L`=KKd)uGIEYnS9UGP5h zIn%~zU1Qq%TBlUdF%TvqxV(3|thEo<9ZJq2G}!-(v-8K3?7_XCIFa5t#>jFHiNCj- zKKHh_r5VvUeg`8am`&yL;J}n=rs898T=6G+Xv_ zuvv9MuQ_eyWXfJYU0S!qiJ>F&2t8Jssh zqnH@i4u6Wx48>L?6Wi=A{{S&I6C4dNt&Js)bIKF2lSRV$@-XFGUc7^lQw7oAj`x$` zHq0Z+HI(_&s(GBA0bl9c7|aK|ZYg(yGpIA72{(1DUvRU)bw0DA$Xw)27cVEpRMe%| z(yC<4aLmel)FGpl8Lv@PQbwmT5lc>&^oeA8RxZ2}%MCT)c&1F`Vf%GKHPW)0xifDB zA)8YEC#Rt+qV_UZwJ6-Yd12h(`rXSTXTMvCIHSrRPO5nVivA87U|;&RndDI8ma8EU9xSCT#m}cs+Y=<>0|5~9O{q~dd}U8c8ESt;enR*y3|yL~1@leI(8xXsGt7q+Xk5BYJMR!vMbg&=mBGivq|Df&oH)qmeo18PG?n!F(j zz9me-zBkg|!Rx){0ca*oZr7dmgzenEz>V(1003rYY*x6@n diff --git a/packages/server/config.js b/packages/server/config.js index b42293059..57e35921b 100644 --- a/packages/server/config.js +++ b/packages/server/config.js @@ -7,7 +7,8 @@ module.exports = () => ({ }, keys: ["secret1", "secret2"], port: 4001, - latestAppsPath: "./appPackages", + latestPackagesFolder: "appPackages", extraMasterPlugins: {}, + dev:true, customizeMaster: appDefinition => appDefinition }) \ No newline at end of file diff --git a/packages/server/config.sample.js b/packages/server/config.sample.js index 355c29d3a..165757c2a 100644 --- a/packages/server/config.sample.js +++ b/packages/server/config.sample.js @@ -18,12 +18,15 @@ module.exports = () => ({ port: 4001, // path to where your appDefinition etc is stored (dev time) - latestAppsPath: "./", + latestPackagesFolder: "./", // register plugins for master extraMasterPlugins: {}, // make modifications to master's appdefinition - e.g. add plugins - customizeMaster: appDefinition => appDefinition + customizeMaster: appDefinition => appDefinition, + + // false for production - serves builder if true + dev:false }) \ No newline at end of file diff --git a/packages/server/index.js b/packages/server/index.js index ae369e079..e47b44aa1 100644 --- a/packages/server/index.js +++ b/packages/server/index.js @@ -2,5 +2,10 @@ const app = require("./app"); const config = require("./config"); const buildAppContext = require("./initialise/buildAppContext"); -buildAppContext(config, true) - .then((appContext) => app(appContext)); \ No newline at end of file +(async () => { + const bbContext = await buildAppContext(config(), true); + const server = await app(bbContext); + server.on("listening", () => { + console.log(`Budibase Server listening on port ${bbContext.config.port}`); + }) +})() diff --git a/packages/server/initialise/initialiseBudibase.js b/packages/server/initialise/initialiseBudibase.js index 3d9f9d4b1..9775c8740 100644 --- a/packages/server/initialise/initialiseBudibase.js +++ b/packages/server/initialise/initialiseBudibase.js @@ -67,7 +67,7 @@ const question = async (q) => { await mkdir(rootconfig.rootPath); } - const appContext = await buildAppContext(budibaseConfig, false); + const appContext = await buildAppContext(budibaseConfig(), false); await create( appContext, datastoreModule, diff --git a/packages/server/middleware/routers.js b/packages/server/middleware/routers.js index e669c1e22..e9fbec67d 100644 --- a/packages/server/middleware/routers.js +++ b/packages/server/middleware/routers.js @@ -2,6 +2,7 @@ const Router = require("@koa/router"); const session = require("./session"); const StatusCodes = require("../utilities/statusCodes"); const fs = require("fs"); +const { getPackageForBuilder, savePackage } = require("../utilities/builder"); module.exports = (config, app) => { @@ -19,6 +20,10 @@ module.exports = (config, app) => { ctx.session.accessed = true; await next(); }) + .get("/_builder", async (ctx) => { + ctx.response.status = StatusCodes.OK; + ctx.response.body = "Builder UI Served Here"; + }) .get("/:appname", async (ctx) => { ctx.response.status = StatusCodes.OK; ctx.response.body = "UI Served Here"; @@ -69,6 +74,32 @@ module.exports = (config, app) => { ctx.response.status = StatusCodes.OK; }) + .get("/_builder/api/:appname/appPackage", async (ctx) => { + if(!config.dev) { + ctx.request.status = StatusCodes.FORBIDDEN; + ctx.request.body = "run in dev mode to access builder"; + return; + } + + ctx.body = await getPackageForBuilder( + config, + ctx.params.appname); + ctx.response.status = StatusCodes.OK; + + }) + .post("/_builder/api/:appname/appPackage", async (ctx) => { + if(!config.dev) { + ctx.request.status = StatusCodes.FORBIDDEN; + ctx.body = "run in dev mode to access builder"; + return; + } + + ctx.body = await savePackage( + config, + ctx.params.appname, + ctx.request.body); + ctx.reqponse.status = StatusCodes.OK; + }) .use(async (ctx, next) => { const pathParts = ctx.path.split("/"); diff --git a/packages/server/runtime_apps/testApp/3-VYAktSELSd/access_levels.json b/packages/server/runtime_apps/testApp/3-VYAktSELSd/access_levels.json deleted file mode 100644 index 4e01e4e9a..000000000 --- a/packages/server/runtime_apps/testApp/3-VYAktSELSd/access_levels.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "levels": [ - { - "name": "owner", - "permissions": [ - { - "type": "create record", - "nodeKey": "/customers/1-{id}" - }, - { - "type": "delete record", - "nodeKey": "/customers/1-{id}" - }, - { - "type": "update record", - "nodeKey": "/customers/1-{id}" - }, - { - "type": "read record", - "nodeKey": "/customers/1-{id}" - }, - { - "type": "create record", - "nodeKey": "/customers/1-{id}/invoices/2-{id}" - }, - { - "type": "update record", - "nodeKey": "/customers/1-{id}/invoices/2-{id}" - }, - { - "type": "delete record", - "nodeKey": "/customers/1-{id}/invoices/2-{id}" - }, - { - "type": "read record", - "nodeKey": "/customers/1-{id}/invoices/2-{id}" - }, - { - "type": "write templates" - }, - { - "type": "create user" - }, - { - "type": "set password" - }, - { - "type": "create temporary access" - }, - { - "type": "enable or disable user" - }, - { - "type": "write access levels" - }, - { - "type": "list users" - }, - { - "type": "list access levels" - }, - { - "type": "manage index" - }, - { - "type": "set user access levels" - }, - { - "type": "manage collection" - } - ] - } - ], - "version": 0 -} \ No newline at end of file diff --git a/packages/server/runtime_apps/testApp/3-VYAktSELSd/appDefinition.json b/packages/server/runtime_apps/testApp/3-VYAktSELSd/appDefinition.json deleted file mode 100644 index 871524cb9..000000000 --- a/packages/server/runtime_apps/testApp/3-VYAktSELSd/appDefinition.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "hierarchy": { - "name": "root", - "type": "root", - "children": [ - { - "name": "customer", - "type": "record", - "fields": [ - { - "name": "name", - "type": "string", - "typeOptions": { - "maxLength": 1000, - "values": null, - "allowDeclaredValuesOnly": false - }, - "label": "name", - "getInitialValue": "default", - "getUndefinedValue": "default" - } - ], - "children": [ - { - "name": "invoice", - "type": "record", - "fields": [ - { - "name": "amount", - "type": "number", - "typeOptions": { - "minValue": 99999999999, - "maxValue": 99999999999, - "decimalPlaces": 2 - }, - "label": "amount", - "getInitialValue": "default", - "getUndefinedValue": "default" - } - ], - "children": [], - "validationRules": [], - "nodeId": 2, - "indexes": [], - "allidsShardFactor": 1, - "collectionName": "invoices", - "isSingle": false - } - ], - "validationRules": [], - "nodeId": 1, - "indexes": [], - "allidsShardFactor": 64, - "collectionName": "customers", - "isSingle": false - } - ], - "pathMaps": [], - "indexes": [], - "nodeId": 0 - }, - "actions": { - "output_to_file": { - "name": "output_to_file", - "behaviourSource": "main", - "behaviourName": "outputToFile", - "initialOptions": {} - } - }, - "triggers": [ - { - "actionName": "output_to_file", - "eventName": "authApi:createUser:onComplete", - "optionsCreator": "return { filename:'tempaccess' + context.user.name, content:context.result.tempCode };", - "condition": "!context.password" - }, - { - "actionName": "output_to_file", - "eventName": "authApi:createTemporaryAccess:onComplete", - "optionsCreator": "return { filename:'tempaccess' + context.userName, content:context.result };", - "condition": "" - } - ] -} \ No newline at end of file diff --git a/packages/server/runtime_apps/testApp/3-VYAktSELSd/plugins.js b/packages/server/runtime_apps/testApp/3-VYAktSELSd/plugins.js deleted file mode 100644 index 838a10a7f..000000000 --- a/packages/server/runtime_apps/testApp/3-VYAktSELSd/plugins.js +++ /dev/null @@ -1,9 +0,0 @@ -const fs = require("fs"); - -module.exports = (config) => ({ - main: { - outputToFile : ({filename, content}) => { - fs.writeFile(`./tests/.data/${filename}`, content, {encoding:"utf8"}); - } - } -}) \ No newline at end of file diff --git a/packages/server/tests/testApp.js b/packages/server/tests/testApp.js index 004c41e25..2009a9aa6 100644 --- a/packages/server/tests/testApp.js +++ b/packages/server/tests/testApp.js @@ -44,7 +44,7 @@ const config = { }, keys: ["secret1", "secret2"], port: 4002, - latestAppsPath: "./appPackages", + latestPackagesFolder: "./appPackages", extraMasterPlugins, customizeMaster } @@ -61,7 +61,7 @@ module.exports = () => { const budibaseContext = await buildAppContext(config, true); server = await app(budibaseContext); } catch(e) { - console.log(e.message); + console.log(e.stack); } enableDestroy(server); }, diff --git a/packages/server/utilities/builder.js b/packages/server/utilities/builder.js new file mode 100644 index 000000000..7aa5e4893 --- /dev/null +++ b/packages/server/utilities/builder.js @@ -0,0 +1,31 @@ +const { appPackageFolder } = require("./createAppPackage"); +const { writeFile, readFile } = require("./fsawait"); + +module.exports.getPackageForBuilder = async (config, appname) => { + const appPath = appPackageFolder(config, appname); + return ({ + appDefinition: JSON.parse(await readFile( + `${appPath}/appDefinition.json`, + "utf8")), + + accessLevels: JSON.parse(await readFile( + `${appPath}/access_levels.json`, + "utf8")) + }) + +} + + +module.exports.savePackage = async (config, appname, pkg) => { + const appPath = appPackageFolder(config, appname); + await writeFile( + `${appPath}/appDefinition.json`, + JSON.stringify(pkg.appDefinition), + "utf8"); + + await writeFile( + `${appPath}/access_levels.json`, + JSON.stringify(pkg.accessLevels), + "utf8"); + +} \ No newline at end of file diff --git a/packages/server/utilities/createAppPackage.js b/packages/server/utilities/createAppPackage.js index a879c961b..d38253d51 100644 --- a/packages/server/utilities/createAppPackage.js +++ b/packages/server/utilities/createAppPackage.js @@ -1,8 +1,9 @@ -const { join } = require("path"); +const { resolve, join } = require("path"); const constructHierarchy = require("./constructHierarchy"); const { common } = require("budibase-core"); const { getRuntimePackageDirectory } = require("../utilities/runtimePackages"); const injectPlugins = require("./injectedPlugins"); +const { cwd } = require("process"); const createAppPackage = (context, appPath) => { @@ -24,9 +25,15 @@ const createAppPackage = (context, appPath) => { }) } +const appPackageFolder = (config, appname) => + resolve(cwd(), config.latestPackagesFolder, appname); + +module.exports.appPackageFolder = appPackageFolder; + module.exports.masterAppPackage = (context) => { const { config } = context; - const standardPackage = createAppPackage(context, "../appPackages/master"); + const standardPackage = createAppPackage( + context, "../appPackages/master"); const customizeMaster = config && config.customizeMaster ? config.customizeMaster @@ -37,8 +44,7 @@ module.exports.masterAppPackage = (context) => { constructHierarchy ]); - const plugins = require("../appPackages/master/plugins.js") - (context); + const plugins = standardPackage.behaviourSources; return ({ appDefinition, diff --git a/packages/server/utilities/fsawait.js b/packages/server/utilities/fsawait.js index b2c99adc2..49965e193 100644 --- a/packages/server/utilities/fsawait.js +++ b/packages/server/utilities/fsawait.js @@ -2,6 +2,7 @@ const util = require("util"); const fs = require("fs"); module.exports.readFile = util.promisify(fs.readFile); +module.exports.writeFile = util.promisify(fs.writeFile); module.exports.rimraf = util.promisify(require("rimraf")); module.exports.mkdir = util.promisify(fs.mkdir); module.exports.unlink = util.promisify(fs.unlink); diff --git a/packages/server/utilities/targzAppPackage.js b/packages/server/utilities/targzAppPackage.js index b35f3f08a..f88ba5471 100644 --- a/packages/server/utilities/targzAppPackage.js +++ b/packages/server/utilities/targzAppPackage.js @@ -10,7 +10,7 @@ const { getRuntimePackageDirectory, getRuntimeAppsDirectory } = require("./runti module.exports.createTarGzPackage = async (config, appName) => { - const appPath = join(config.latestAppsPath, appName); + const appPath = join(config.latestPackagesFolder, appName); const distPath = join(appPath, "dist"); if(!await exists(distPath)) { diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index a755e7449..04a696124 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -2498,9 +2498,9 @@ lodash.sortby@^4.7.0: integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= lodash@^4.17.11: - version "4.17.11" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" - integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== + version "4.17.14" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba" + integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw== loose-envify@^1.0.0: version "1.4.0" @@ -3362,11 +3362,16 @@ rsvp@^4.8.4: resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== -safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-buffer@^5.1.2: + version "5.2.0" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" + integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== + safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"