Merge pull request #1437 from Budibase/fix/views-and-prettier
Fix prettier and other misc fixes
This commit is contained in:
commit
2942b4f6bc
|
@ -3,6 +3,8 @@
|
||||||
"semi": false,
|
"semi": false,
|
||||||
"singleQuote": false,
|
"singleQuote": false,
|
||||||
"trailingComma": "es5",
|
"trailingComma": "es5",
|
||||||
|
"arrowParens": "avoid",
|
||||||
|
"jsxBracketSameLine": false,
|
||||||
"plugins": ["prettier-plugin-svelte"],
|
"plugins": ["prettier-plugin-svelte"],
|
||||||
"svelteSortOrder" : "scripts-markup-styles"
|
"svelteSortOrder" : "options-scripts-markup-styles"
|
||||||
}
|
}
|
|
@ -14,7 +14,7 @@
|
||||||
"prettier-plugin-svelte": "^2.2.0",
|
"prettier-plugin-svelte": "^2.2.0",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"rollup-plugin-replace": "^2.2.0",
|
"rollup-plugin-replace": "^2.2.0",
|
||||||
"svelte": "^3.30.0"
|
"svelte": "^3.37.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"bootstrap": "lerna link && lerna bootstrap",
|
"bootstrap": "lerna link && lerna bootstrap",
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
let Pouch
|
let Pouch
|
||||||
|
|
||||||
module.exports.setDB = (pouch) => {
|
module.exports.setDB = pouch => {
|
||||||
Pouch = pouch
|
Pouch = pouch
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.getDB = (dbName) => {
|
module.exports.getDB = dbName => {
|
||||||
return new Pouch(dbName)
|
return new Pouch(dbName)
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ exports.getGroupParams = (id = "", otherProps = {}) => {
|
||||||
* Generates a new global user ID.
|
* Generates a new global user ID.
|
||||||
* @returns {string} The new user ID which the user doc can be stored under.
|
* @returns {string} The new user ID which the user doc can be stored under.
|
||||||
*/
|
*/
|
||||||
exports.generateGlobalUserID = (id) => {
|
exports.generateGlobalUserID = id => {
|
||||||
return `${DocumentTypes.USER}${SEPARATOR}${id || newid()}`
|
return `${DocumentTypes.USER}${SEPARATOR}${id || newid()}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ exports.getGlobalUserParams = (globalId, otherProps = {}) => {
|
||||||
* Generates a template ID.
|
* Generates a template ID.
|
||||||
* @param ownerId The owner/user of the template, this could be global or a group level.
|
* @param ownerId The owner/user of the template, this could be global or a group level.
|
||||||
*/
|
*/
|
||||||
exports.generateTemplateID = (ownerId) => {
|
exports.generateTemplateID = ownerId => {
|
||||||
return `${DocumentTypes.TEMPLATE}${SEPARATOR}${ownerId}${newid()}`
|
return `${DocumentTypes.TEMPLATE}${SEPARATOR}${ownerId}${newid()}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ const determineScopedConfig = async function (db, { type, user, group }) {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
const configs = response.rows.map((row) => {
|
const configs = response.rows.map(row => {
|
||||||
const config = row.doc
|
const config = row.doc
|
||||||
|
|
||||||
// Config is specific to a user and a group
|
// Config is specific to a user and a group
|
||||||
|
|
|
@ -4,7 +4,7 @@ const { v4 } = require("uuid")
|
||||||
|
|
||||||
const SALT_ROUNDS = env.SALT_ROUNDS || 10
|
const SALT_ROUNDS = env.SALT_ROUNDS || 10
|
||||||
|
|
||||||
exports.hash = async (data) => {
|
exports.hash = async data => {
|
||||||
const salt = await bcrypt.genSalt(SALT_ROUNDS)
|
const salt = await bcrypt.genSalt(SALT_ROUNDS)
|
||||||
return bcrypt.hash(data, salt)
|
return bcrypt.hash(data, salt)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ function confirmAppId(possibleAppId) {
|
||||||
* @param {object} ctx The main request body to look through.
|
* @param {object} ctx The main request body to look through.
|
||||||
* @returns {string|undefined} If an appId was found it will be returned.
|
* @returns {string|undefined} If an appId was found it will be returned.
|
||||||
*/
|
*/
|
||||||
exports.getAppId = (ctx) => {
|
exports.getAppId = ctx => {
|
||||||
const options = [ctx.headers["x-budibase-app-id"], ctx.params.appId]
|
const options = [ctx.headers["x-budibase-app-id"], ctx.params.appId]
|
||||||
if (ctx.subdomains) {
|
if (ctx.subdomains) {
|
||||||
options.push(ctx.subdomains[1])
|
options.push(ctx.subdomains[1])
|
||||||
|
@ -41,7 +41,7 @@ exports.getAppId = (ctx) => {
|
||||||
}
|
}
|
||||||
let appPath =
|
let appPath =
|
||||||
ctx.request.headers.referrer ||
|
ctx.request.headers.referrer ||
|
||||||
ctx.path.split("/").filter((subPath) => subPath.startsWith(APP_PREFIX))
|
ctx.path.split("/").filter(subPath => subPath.startsWith(APP_PREFIX))
|
||||||
if (!appId && appPath.length !== 0) {
|
if (!appId && appPath.length !== 0) {
|
||||||
appId = confirmAppId(appPath[0])
|
appId = confirmAppId(appPath[0])
|
||||||
}
|
}
|
||||||
|
@ -101,11 +101,11 @@ exports.clearCookie = (ctx, name) => {
|
||||||
* @param {object} ctx The koa context object to be tested.
|
* @param {object} ctx The koa context object to be tested.
|
||||||
* @return {boolean} returns true if the call is from the client lib (a built app rather than the builder).
|
* @return {boolean} returns true if the call is from the client lib (a built app rather than the builder).
|
||||||
*/
|
*/
|
||||||
exports.isClient = (ctx) => {
|
exports.isClient = ctx => {
|
||||||
return ctx.headers["x-budibase-type"] === "client"
|
return ctx.headers["x-budibase-type"] === "client"
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getGlobalUserByEmail = async (email) => {
|
exports.getGlobalUserByEmail = async email => {
|
||||||
const db = getDB(StaticDatabases.GLOBAL.name)
|
const db = getDB(StaticDatabases.GLOBAL.name)
|
||||||
try {
|
try {
|
||||||
let users = (
|
let users = (
|
||||||
|
@ -114,7 +114,7 @@ exports.getGlobalUserByEmail = async (email) => {
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
})
|
})
|
||||||
).rows
|
).rows
|
||||||
users = users.map((user) => user.doc)
|
users = users.map(user => user.doc)
|
||||||
return users.length <= 1 ? users[0] : users
|
return users.length <= 1 ? users[0] : users
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err != null && err.name === "not_found") {
|
if (err != null && err.name === "not_found") {
|
||||||
|
|
|
@ -42,12 +42,14 @@
|
||||||
class="spectrum-ActionButton spectrum-ActionButton--size{size}"
|
class="spectrum-ActionButton spectrum-ActionButton--size{size}"
|
||||||
{disabled}
|
{disabled}
|
||||||
on:longPress
|
on:longPress
|
||||||
on:click|preventDefault>
|
on:click|preventDefault
|
||||||
|
>
|
||||||
{#if longPressable}
|
{#if longPressable}
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-UIIcon-CornerTriangle100 spectrum-ActionButton-hold"
|
class="spectrum-Icon spectrum-UIIcon-CornerTriangle100 spectrum-ActionButton-hold"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true">
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-css-icon-CornerTriangle100" />
|
<use xlink:href="#spectrum-css-icon-CornerTriangle100" />
|
||||||
</svg>
|
</svg>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -56,7 +58,8 @@
|
||||||
class="spectrum-Icon spectrum-Icon--size{size}"
|
class="spectrum-Icon spectrum-Icon--size{size}"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
aria-label={icon}>
|
aria-label={icon}
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-icon-18-{icon}" />
|
<use xlink:href="#spectrum-icon-18-{icon}" />
|
||||||
</svg>
|
</svg>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// Attaches a spectrum-ActionGroup-item class to buttons inside the div
|
// Attaches a spectrum-ActionGroup-item class to buttons inside the div
|
||||||
function group(element) {
|
function group(element) {
|
||||||
const buttons = Array.from(element.getElementsByTagName("button"))
|
const buttons = Array.from(element.getElementsByTagName("button"))
|
||||||
buttons.forEach((button) => {
|
buttons.forEach(button => {
|
||||||
button.classList.add("spectrum-ActionGroup-item")
|
button.classList.add("spectrum-ActionGroup-item")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ export default function positionDropdown(element, { anchor, align }) {
|
||||||
element.style[positionSide] = `${dimensions[positionSide]}px`
|
element.style[positionSide] = `${dimensions[positionSide]}px`
|
||||||
element.style.left = `${calcLeftPosition(dimensions).toFixed(0)}px`
|
element.style.left = `${calcLeftPosition(dimensions).toFixed(0)}px`
|
||||||
|
|
||||||
const resizeObserver = new ResizeObserver((entries) => {
|
const resizeObserver = new ResizeObserver(entries => {
|
||||||
entries.forEach(() => {
|
entries.forEach(() => {
|
||||||
dimensions = getDimensions()
|
dimensions = getDimensions()
|
||||||
element.style[positionSide] = `${dimensions[positionSide]}px`
|
element.style[positionSide] = `${dimensions[positionSide]}px`
|
||||||
|
|
|
@ -23,13 +23,15 @@
|
||||||
class:active
|
class:active
|
||||||
class="spectrum-Button spectrum-Button--size{size.toUpperCase()}"
|
class="spectrum-Button spectrum-Button--size{size.toUpperCase()}"
|
||||||
{disabled}
|
{disabled}
|
||||||
on:click|preventDefault>
|
on:click|preventDefault
|
||||||
|
>
|
||||||
{#if icon}
|
{#if icon}
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-Icon--size{size.toUpperCase()}"
|
class="spectrum-Icon spectrum-Icon--size{size.toUpperCase()}"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
aria-label={icon}>
|
aria-label={icon}
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-icon-18-{icon}" />
|
<use xlink:href="#spectrum-icon-18-{icon}" />
|
||||||
</svg>
|
</svg>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -3,13 +3,17 @@
|
||||||
export let vertical = false
|
export let vertical = false
|
||||||
|
|
||||||
function group(element) {
|
function group(element) {
|
||||||
const buttons = Array.from(element.getElementsByTagName('button'))
|
const buttons = Array.from(element.getElementsByTagName("button"))
|
||||||
buttons.forEach(button => {
|
buttons.forEach(button => {
|
||||||
button.classList.add('spectrum-ButtonGroup-item')
|
button.classList.add("spectrum-ButtonGroup-item")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div use:group class="spectrum-ButtonGroup" class:spectrum-ButtonGroup--vertical={vertical}>
|
<div
|
||||||
|
use:group
|
||||||
|
class="spectrum-ButtonGroup"
|
||||||
|
class:spectrum-ButtonGroup--vertical={vertical}
|
||||||
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
|
@ -35,5 +35,6 @@
|
||||||
{placeholder}
|
{placeholder}
|
||||||
{getOptionLabel}
|
{getOptionLabel}
|
||||||
{getOptionValue}
|
{getOptionValue}
|
||||||
on:change={onChange} />
|
on:change={onChange}
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
|
@ -17,27 +17,31 @@
|
||||||
|
|
||||||
<label
|
<label
|
||||||
class="spectrum-Checkbox spectrum-Checkbox--sizeM spectrum-Checkbox--emphasized"
|
class="spectrum-Checkbox spectrum-Checkbox--sizeM spectrum-Checkbox--emphasized"
|
||||||
class:is-invalid={!!error}>
|
class:is-invalid={!!error}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
checked={value}
|
checked={value}
|
||||||
{disabled}
|
{disabled}
|
||||||
on:change={onChange}
|
on:change={onChange}
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="spectrum-Checkbox-input"
|
class="spectrum-Checkbox-input"
|
||||||
{id} />
|
{id}
|
||||||
|
/>
|
||||||
<span class="spectrum-Checkbox-box">
|
<span class="spectrum-Checkbox-box">
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Checkbox-checkmark"
|
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Checkbox-checkmark"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true">
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
||||||
</svg>
|
</svg>
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-UIIcon-Dash100 spectrum-Checkbox-partialCheckmark"
|
class="spectrum-Icon spectrum-UIIcon-Dash100 spectrum-Checkbox-partialCheckmark"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true">
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-css-icon-Dash100" />
|
<use xlink:href="#spectrum-css-icon-Dash100" />
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
<span class="spectrum-Checkbox-label">{text || ''}</span>
|
<span class="spectrum-Checkbox-label">{text || ""}</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
|
@ -49,7 +49,8 @@
|
||||||
<div
|
<div
|
||||||
class="spectrum-Textfield spectrum-InputGroup-textfield"
|
class="spectrum-Textfield spectrum-InputGroup-textfield"
|
||||||
class:is-disabled={!!error}
|
class:is-disabled={!!error}
|
||||||
class:is-focused={open || focus}>
|
class:is-focused={open || focus}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
on:focus={() => (focus = true)}
|
on:focus={() => (focus = true)}
|
||||||
|
@ -57,18 +58,21 @@
|
||||||
on:change={onChange}
|
on:change={onChange}
|
||||||
{value}
|
{value}
|
||||||
{placeholder}
|
{placeholder}
|
||||||
class="spectrum-Textfield-input spectrum-InputGroup-input" />
|
class="spectrum-Textfield-input spectrum-InputGroup-input"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
class="spectrum-Picker spectrum-Picker--sizeM spectrum-InputGroup-button"
|
class="spectrum-Picker spectrum-Picker--sizeM spectrum-InputGroup-button"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
aria-haspopup="true"
|
aria-haspopup="true"
|
||||||
disabled={!!error}
|
disabled={!!error}
|
||||||
on:click={() => (open = true)}>
|
on:click={() => (open = true)}
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-UIIcon-ChevronDown100 spectrum-Picker-menuIcon spectrum-InputGroup-icon"
|
class="spectrum-Icon spectrum-UIIcon-ChevronDown100 spectrum-Picker-menuIcon spectrum-InputGroup-icon"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true">
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-css-icon-Chevron100" />
|
<use xlink:href="#spectrum-css-icon-Chevron100" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
@ -76,7 +80,8 @@
|
||||||
<div class="overlay" on:mousedown|self={() => (open = false)} />
|
<div class="overlay" on:mousedown|self={() => (open = false)} />
|
||||||
<div
|
<div
|
||||||
transition:fly={{ y: -20, duration: 200 }}
|
transition:fly={{ y: -20, duration: 200 }}
|
||||||
class="spectrum-Popover spectrum-Popover--bottom is-open">
|
class="spectrum-Popover spectrum-Popover--bottom is-open"
|
||||||
|
>
|
||||||
<ul class="spectrum-Menu" role="listbox">
|
<ul class="spectrum-Menu" role="listbox">
|
||||||
{#if options && Array.isArray(options)}
|
{#if options && Array.isArray(options)}
|
||||||
{#each options as option}
|
{#each options as option}
|
||||||
|
@ -86,13 +91,16 @@
|
||||||
role="option"
|
role="option"
|
||||||
aria-selected="true"
|
aria-selected="true"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
on:click={() => selectOption(getOptionValue(option))}>
|
on:click={() => selectOption(getOptionValue(option))}
|
||||||
<span
|
>
|
||||||
class="spectrum-Menu-itemLabel">{getOptionLabel(option)}</span>
|
<span class="spectrum-Menu-itemLabel"
|
||||||
|
>{getOptionLabel(option)}</span
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon"
|
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true">
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
||||||
</svg>
|
</svg>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -64,7 +64,8 @@
|
||||||
on:close={onClose}
|
on:close={onClose}
|
||||||
options={flatpickrOptions}
|
options={flatpickrOptions}
|
||||||
on:change={handleChange}
|
on:change={handleChange}
|
||||||
element={`#${flatpickrId}`}>
|
element={`#${flatpickrId}`}
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
id={flatpickrId}
|
id={flatpickrId}
|
||||||
class:is-disabled={disabled}
|
class:is-disabled={disabled}
|
||||||
|
@ -73,17 +74,20 @@
|
||||||
class:is-focused={open}
|
class:is-focused={open}
|
||||||
aria-readonly="false"
|
aria-readonly="false"
|
||||||
aria-required="false"
|
aria-required="false"
|
||||||
aria-haspopup="true">
|
aria-haspopup="true"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
on:click={flatpickr?.open}
|
on:click={flatpickr?.open}
|
||||||
class="spectrum-Textfield spectrum-InputGroup-textfield"
|
class="spectrum-Textfield spectrum-InputGroup-textfield"
|
||||||
class:is-disabled={disabled}
|
class:is-disabled={disabled}
|
||||||
class:is-invalid={!!error}>
|
class:is-invalid={!!error}
|
||||||
|
>
|
||||||
{#if !!error}
|
{#if !!error}
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Textfield-validationIcon"
|
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Textfield-validationIcon"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true">
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-icon-18-Alert" />
|
<use xlink:href="#spectrum-icon-18-Alert" />
|
||||||
</svg>
|
</svg>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -94,7 +98,8 @@
|
||||||
class="spectrum-Textfield-input spectrum-InputGroup-input"
|
class="spectrum-Textfield-input spectrum-InputGroup-input"
|
||||||
{placeholder}
|
{placeholder}
|
||||||
{id}
|
{id}
|
||||||
{value} />
|
{value}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -102,12 +107,14 @@
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
{disabled}
|
{disabled}
|
||||||
class:is-invalid={!!error}
|
class:is-invalid={!!error}
|
||||||
on:click={flatpickr?.open}>
|
on:click={flatpickr?.open}
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-Icon--sizeM"
|
class="spectrum-Icon spectrum-Icon--sizeM"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
aria-label="Calendar">
|
aria-label="Calendar"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-icon-18-Calendar" />
|
<use xlink:href="#spectrum-icon-18-Calendar" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -119,13 +119,15 @@
|
||||||
<div
|
<div
|
||||||
class="nav left"
|
class="nav left"
|
||||||
class:visible={selectedImageIdx > 0}
|
class:visible={selectedImageIdx > 0}
|
||||||
on:click={navigateLeft}>
|
on:click={navigateLeft}
|
||||||
|
>
|
||||||
<Icon name="ChevronLeft" />
|
<Icon name="ChevronLeft" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="nav right"
|
class="nav right"
|
||||||
class:visible={selectedImageIdx < fileCount - 1}
|
class:visible={selectedImageIdx < fileCount - 1}
|
||||||
on:click={navigateRight}>
|
on:click={navigateRight}
|
||||||
|
>
|
||||||
<Icon name="ChevronRight" />
|
<Icon name="ChevronRight" />
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">File {selectedImageIdx + 1} of {fileCount}</div>
|
<div class="footer">File {selectedImageIdx + 1} of {fileCount}</div>
|
||||||
|
@ -140,19 +142,22 @@
|
||||||
on:dragleave={handleDragLeave}
|
on:dragleave={handleDragLeave}
|
||||||
on:dragenter={handleDragOver}
|
on:dragenter={handleDragOver}
|
||||||
on:drop={handleDrop}
|
on:drop={handleDrop}
|
||||||
class:is-dragged={fileDragged}>
|
class:is-dragged={fileDragged}
|
||||||
|
>
|
||||||
<div class="spectrum-IllustratedMessage spectrum-IllustratedMessage--cta">
|
<div class="spectrum-IllustratedMessage spectrum-IllustratedMessage--cta">
|
||||||
<input
|
<input
|
||||||
id={fieldId}
|
id={fieldId}
|
||||||
{disabled}
|
{disabled}
|
||||||
type="file"
|
type="file"
|
||||||
multiple
|
multiple
|
||||||
on:change={handleFile} />
|
on:change={handleFile}
|
||||||
|
/>
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-IllustratedMessage-illustration"
|
class="spectrum-IllustratedMessage-illustration"
|
||||||
width="125"
|
width="125"
|
||||||
height="60"
|
height="60"
|
||||||
viewBox="0 0 199 97.7"><defs>
|
viewBox="0 0 199 97.7"
|
||||||
|
><defs>
|
||||||
<style>
|
<style>
|
||||||
.cls-1,
|
.cls-1,
|
||||||
.cls-2 {
|
.cls-2 {
|
||||||
|
@ -170,25 +175,31 @@
|
||||||
</defs>
|
</defs>
|
||||||
<path
|
<path
|
||||||
class="cls-1"
|
class="cls-1"
|
||||||
d="M110.53,85.66,100.26,95.89a1.09,1.09,0,0,1-1.52,0L88.47,85.66" />
|
d="M110.53,85.66,100.26,95.89a1.09,1.09,0,0,1-1.52,0L88.47,85.66"
|
||||||
|
/>
|
||||||
<line class="cls-1" x1="99.5" y1="95.5" x2="99.5" y2="58.5" />
|
<line class="cls-1" x1="99.5" y1="95.5" x2="99.5" y2="58.5" />
|
||||||
<path class="cls-1" d="M105.5,73.5h19a2,2,0,0,0,2-2v-43" />
|
<path class="cls-1" d="M105.5,73.5h19a2,2,0,0,0,2-2v-43" />
|
||||||
<path
|
<path
|
||||||
class="cls-1"
|
class="cls-1"
|
||||||
d="M126.5,22.5h-19a2,2,0,0,1-2-2V1.5h-31a2,2,0,0,0-2,2v68a2,2,0,0,0,2,2h19" />
|
d="M126.5,22.5h-19a2,2,0,0,1-2-2V1.5h-31a2,2,0,0,0-2,2v68a2,2,0,0,0,2,2h19"
|
||||||
|
/>
|
||||||
<line class="cls-1" x1="105.5" y1="1.5" x2="126.5" y2="22.5" />
|
<line class="cls-1" x1="105.5" y1="1.5" x2="126.5" y2="22.5" />
|
||||||
<path
|
<path
|
||||||
class="cls-2"
|
class="cls-2"
|
||||||
d="M47.93,50.49a5,5,0,1,0-4.83-5A4.93,4.93,0,0,0,47.93,50.49Z" />
|
d="M47.93,50.49a5,5,0,1,0-4.83-5A4.93,4.93,0,0,0,47.93,50.49Z"
|
||||||
|
/>
|
||||||
<path
|
<path
|
||||||
class="cls-2"
|
class="cls-2"
|
||||||
d="M36.6,65.93,42.05,60A2.06,2.06,0,0,1,45,60l12.68,13.2" />
|
d="M36.6,65.93,42.05,60A2.06,2.06,0,0,1,45,60l12.68,13.2"
|
||||||
|
/>
|
||||||
<path
|
<path
|
||||||
class="cls-2"
|
class="cls-2"
|
||||||
d="M3.14,73.23,22.42,53.76a1.65,1.65,0,0,1,2.38,0l19.05,19.7" />
|
d="M3.14,73.23,22.42,53.76a1.65,1.65,0,0,1,2.38,0l19.05,19.7"
|
||||||
|
/>
|
||||||
<path
|
<path
|
||||||
class="cls-1"
|
class="cls-1"
|
||||||
d="M139.5,36.5H196A1.49,1.49,0,0,1,197.5,38V72A1.49,1.49,0,0,1,196,73.5H141A1.49,1.49,0,0,1,139.5,72V32A1.49,1.49,0,0,1,141,30.5H154a2.43,2.43,0,0,1,1.67.66l6,5.66" />
|
d="M139.5,36.5H196A1.49,1.49,0,0,1,197.5,38V72A1.49,1.49,0,0,1,196,73.5H141A1.49,1.49,0,0,1,139.5,72V32A1.49,1.49,0,0,1,141,30.5H154a2.43,2.43,0,0,1,1.67.66l6,5.66"
|
||||||
|
/>
|
||||||
<rect
|
<rect
|
||||||
class="cls-1"
|
class="cls-1"
|
||||||
x="1.5"
|
x="1.5"
|
||||||
|
@ -196,16 +207,21 @@
|
||||||
width="58"
|
width="58"
|
||||||
height="39"
|
height="39"
|
||||||
rx="2"
|
rx="2"
|
||||||
ry="2" />
|
ry="2"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<h2
|
<h2
|
||||||
class="spectrum-Heading spectrum-Heading--sizeL spectrum-Heading--light spectrum-IllustratedMessage-heading">
|
class="spectrum-Heading spectrum-Heading--sizeL spectrum-Heading--light spectrum-IllustratedMessage-heading"
|
||||||
|
>
|
||||||
Drag and drop your file
|
Drag and drop your file
|
||||||
</h2>
|
</h2>
|
||||||
{#if !disabled}
|
{#if !disabled}
|
||||||
<p
|
<p
|
||||||
class="spectrum-Body spectrum-Body--sizeS spectrum-IllustratedMessage-description">
|
class="spectrum-Body spectrum-Body--sizeS spectrum-IllustratedMessage-description"
|
||||||
<label for={fieldId} class="spectrum-Link">Select a file to upload</label>
|
>
|
||||||
|
<label for={fieldId} class="spectrum-Link"
|
||||||
|
>Select a file to upload</label
|
||||||
|
>
|
||||||
<br />
|
<br />
|
||||||
from your computer
|
from your computer
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -78,4 +78,5 @@
|
||||||
{isOptionSelected}
|
{isOptionSelected}
|
||||||
{getOptionLabel}
|
{getOptionLabel}
|
||||||
{getOptionValue}
|
{getOptionValue}
|
||||||
onSelectOption={toggleOption} />
|
onSelectOption={toggleOption}
|
||||||
|
/>
|
||||||
|
|
|
@ -37,7 +37,8 @@
|
||||||
class:is-invalid={!!error}
|
class:is-invalid={!!error}
|
||||||
class:is-open={open}
|
class:is-open={open}
|
||||||
aria-haspopup="listbox"
|
aria-haspopup="listbox"
|
||||||
on:mousedown={onClick}>
|
on:mousedown={onClick}
|
||||||
|
>
|
||||||
<span class="spectrum-Picker-label" class:is-placeholder={isPlaceholder}>
|
<span class="spectrum-Picker-label" class:is-placeholder={isPlaceholder}>
|
||||||
{fieldText}
|
{fieldText}
|
||||||
</span>
|
</span>
|
||||||
|
@ -46,14 +47,16 @@
|
||||||
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Picker-validationIcon"
|
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Picker-validationIcon"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
aria-label="Folder">
|
aria-label="Folder"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-icon-18-Alert" />
|
<use xlink:href="#spectrum-icon-18-Alert" />
|
||||||
</svg>
|
</svg>
|
||||||
{/if}
|
{/if}
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-UIIcon-ChevronDown100 spectrum-Picker-menuIcon"
|
class="spectrum-Icon spectrum-UIIcon-ChevronDown100 spectrum-Picker-menuIcon"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true">
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-css-icon-Chevron100" />
|
<use xlink:href="#spectrum-css-icon-Chevron100" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
@ -61,7 +64,8 @@
|
||||||
<div
|
<div
|
||||||
use:clickOutside={() => (open = false)}
|
use:clickOutside={() => (open = false)}
|
||||||
transition:fly={{ y: -20, duration: 200 }}
|
transition:fly={{ y: -20, duration: 200 }}
|
||||||
class="spectrum-Popover spectrum-Popover--bottom spectrum-Picker-popover is-open">
|
class="spectrum-Popover spectrum-Popover--bottom spectrum-Picker-popover is-open"
|
||||||
|
>
|
||||||
<ul class="spectrum-Menu" role="listbox">
|
<ul class="spectrum-Menu" role="listbox">
|
||||||
{#if placeholderOption}
|
{#if placeholderOption}
|
||||||
<li
|
<li
|
||||||
|
@ -70,12 +74,14 @@
|
||||||
role="option"
|
role="option"
|
||||||
aria-selected="true"
|
aria-selected="true"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
on:click={() => onSelectOption(null)}>
|
on:click={() => onSelectOption(null)}
|
||||||
|
>
|
||||||
<span class="spectrum-Menu-itemLabel">{placeholderOption}</span>
|
<span class="spectrum-Menu-itemLabel">{placeholderOption}</span>
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon"
|
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true">
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
||||||
</svg>
|
</svg>
|
||||||
</li>
|
</li>
|
||||||
|
@ -88,13 +94,16 @@
|
||||||
role="option"
|
role="option"
|
||||||
aria-selected="true"
|
aria-selected="true"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
on:click={() => onSelectOption(getOptionValue(option, idx))}>
|
on:click={() => onSelectOption(getOptionValue(option, idx))}
|
||||||
<span
|
>
|
||||||
class="spectrum-Menu-itemLabel">{getOptionLabel(option, idx)}</span>
|
<span class="spectrum-Menu-itemLabel"
|
||||||
|
>{getOptionLabel(option, idx)}</span
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon"
|
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true">
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
||||||
</svg>
|
</svg>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -21,14 +21,16 @@
|
||||||
<div
|
<div
|
||||||
title={getOptionLabel(option)}
|
title={getOptionLabel(option)}
|
||||||
class="spectrum-Radio spectrum-FieldGroup-item spectrum-Radio--emphasized"
|
class="spectrum-Radio spectrum-FieldGroup-item spectrum-Radio--emphasized"
|
||||||
class:is-invalid={!!error}>
|
class:is-invalid={!!error}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
on:change={onChange}
|
on:change={onChange}
|
||||||
bind:group={value}
|
bind:group={value}
|
||||||
value={getOptionValue(option)}
|
value={getOptionValue(option)}
|
||||||
type="radio"
|
type="radio"
|
||||||
class="spectrum-Radio-input"
|
class="spectrum-Radio-input"
|
||||||
{disabled} />
|
{disabled}
|
||||||
|
/>
|
||||||
<span class="spectrum-Radio-button" />
|
<span class="spectrum-Radio-button" />
|
||||||
<label class="spectrum-Radio-label">{getOptionLabel(option)}</label>
|
<label class="spectrum-Radio-label">{getOptionLabel(option)}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -34,11 +34,13 @@
|
||||||
<div
|
<div
|
||||||
class="spectrum-Textfield"
|
class="spectrum-Textfield"
|
||||||
class:is-focused={focus}
|
class:is-focused={focus}
|
||||||
class:is-disabled={disabled}>
|
class:is-disabled={disabled}
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Textfield-icon"
|
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Textfield-icon"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true">
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-icon-18-Magnify" />
|
<use xlink:href="#spectrum-icon-18-Magnify" />
|
||||||
</svg>
|
</svg>
|
||||||
<input
|
<input
|
||||||
|
@ -46,23 +48,26 @@
|
||||||
on:keyup={updateValueOnEnter}
|
on:keyup={updateValueOnEnter}
|
||||||
{disabled}
|
{disabled}
|
||||||
{id}
|
{id}
|
||||||
value={value || ''}
|
value={value || ""}
|
||||||
placeholder={placeholder || ''}
|
placeholder={placeholder || ""}
|
||||||
on:blur={onBlur}
|
on:blur={onBlur}
|
||||||
on:focus={onFocus}
|
on:focus={onFocus}
|
||||||
on:input
|
on:input
|
||||||
type="search"
|
type="search"
|
||||||
class="spectrum-Textfield-input spectrum-Search-input"
|
class="spectrum-Textfield-input spectrum-Search-input"
|
||||||
autocomplete="off" />
|
autocomplete="off"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
on:click={() => updateValue('')}
|
on:click={() => updateValue("")}
|
||||||
type="reset"
|
type="reset"
|
||||||
class="spectrum-ClearButton spectrum-Search-clearButton">
|
class="spectrum-ClearButton spectrum-Search-clearButton"
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-UIIcon-Cross75"
|
class="spectrum-Icon spectrum-UIIcon-Cross75"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true">
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-css-icon-Cross75" />
|
<use xlink:href="#spectrum-css-icon-Cross75" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -51,7 +51,8 @@
|
||||||
{options}
|
{options}
|
||||||
{getOptionLabel}
|
{getOptionLabel}
|
||||||
{getOptionValue}
|
{getOptionValue}
|
||||||
isPlaceholder={value == null || value === ''}
|
isPlaceholder={value == null || value === ""}
|
||||||
placeholderOption={placeholder}
|
placeholderOption={placeholder}
|
||||||
isOptionSelected={option => option === value}
|
isOptionSelected={option => option === value}
|
||||||
onSelectOption={selectOption} />
|
onSelectOption={selectOption}
|
||||||
|
/>
|
||||||
|
|
|
@ -21,7 +21,8 @@
|
||||||
on:change={onChange}
|
on:change={onChange}
|
||||||
{id}
|
{id}
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="spectrum-Switch-input" />
|
class="spectrum-Switch-input"
|
||||||
|
/>
|
||||||
<span class="spectrum-Switch-switch" />
|
<span class="spectrum-Switch-switch" />
|
||||||
<label class="spectrum-Switch-label" for={id}>{text}</label>
|
<label class="spectrum-Switch-label" for={id}>{text}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -25,23 +25,28 @@
|
||||||
class="spectrum-Textfield spectrum-Textfield--multiline"
|
class="spectrum-Textfield spectrum-Textfield--multiline"
|
||||||
class:is-invalid={!!error}
|
class:is-invalid={!!error}
|
||||||
class:is-disabled={disabled}
|
class:is-disabled={disabled}
|
||||||
class:is-focused={focus}>
|
class:is-focused={focus}
|
||||||
|
>
|
||||||
{#if error}
|
{#if error}
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Textfield-validationIcon"
|
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Textfield-validationIcon"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true">
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-icon-18-Alert" />
|
<use xlink:href="#spectrum-icon-18-Alert" />
|
||||||
</svg>
|
</svg>
|
||||||
{/if}
|
{/if}
|
||||||
<textarea
|
<textarea
|
||||||
bind:this={textarea}
|
bind:this={textarea}
|
||||||
placeholder={placeholder || ''}
|
placeholder={placeholder || ""}
|
||||||
class="spectrum-Textfield-input"
|
class="spectrum-Textfield-input"
|
||||||
{disabled}
|
{disabled}
|
||||||
{id}
|
{id}
|
||||||
on:focus={() => (focus = true)}
|
on:focus={() => (focus = true)}
|
||||||
on:blur={onChange}>{value || ''}</textarea>
|
on:blur={onChange}
|
||||||
|
>
|
||||||
|
{value || ""}
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -53,12 +53,14 @@
|
||||||
class="spectrum-Textfield"
|
class="spectrum-Textfield"
|
||||||
class:is-invalid={!!error}
|
class:is-invalid={!!error}
|
||||||
class:is-disabled={disabled}
|
class:is-disabled={disabled}
|
||||||
class:is-focused={focus}>
|
class:is-focused={focus}
|
||||||
|
>
|
||||||
{#if error}
|
{#if error}
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Textfield-validationIcon"
|
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Textfield-validationIcon"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true">
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-icon-18-Alert" />
|
<use xlink:href="#spectrum-icon-18-Alert" />
|
||||||
</svg>
|
</svg>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -68,13 +70,14 @@
|
||||||
{disabled}
|
{disabled}
|
||||||
{readonly}
|
{readonly}
|
||||||
{id}
|
{id}
|
||||||
value={value || ''}
|
value={value || ""}
|
||||||
placeholder={placeholder || ''}
|
placeholder={placeholder || ""}
|
||||||
on:blur={onBlur}
|
on:blur={onBlur}
|
||||||
on:focus={onFocus}
|
on:focus={onFocus}
|
||||||
on:input
|
on:input
|
||||||
{type}
|
{type}
|
||||||
class="spectrum-Textfield-input" />
|
class="spectrum-Textfield-input"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -25,5 +25,6 @@
|
||||||
{value}
|
{value}
|
||||||
{placeholder}
|
{placeholder}
|
||||||
{enableTime}
|
{enableTime}
|
||||||
on:change={onChange} />
|
on:change={onChange}
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
|
@ -27,5 +27,6 @@
|
||||||
{fileSizeLimit}
|
{fileSizeLimit}
|
||||||
{processFiles}
|
{processFiles}
|
||||||
{handleFileTooLarge}
|
{handleFileTooLarge}
|
||||||
on:change={onChange} />
|
on:change={onChange}
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
export let error = null
|
export let error = null
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="spectrum-Form-item" class:above={labelPosition === 'above'}>
|
<div class="spectrum-Form-item" class:above={labelPosition === "above"}>
|
||||||
{#if label}
|
{#if label}
|
||||||
<FieldLabel forId={id} {label} position={labelPosition} />
|
<FieldLabel forId={id} {label} position={labelPosition} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -10,8 +10,9 @@
|
||||||
|
|
||||||
<label
|
<label
|
||||||
for={forId}
|
for={forId}
|
||||||
class={`spectrum-FieldLabel spectrum-FieldLabel--sizeM spectrum-Form-itemLabel ${className}`}>
|
class={`spectrum-FieldLabel spectrum-FieldLabel--sizeM spectrum-Form-itemLabel ${className}`}
|
||||||
{label || ''}
|
>
|
||||||
|
{label || ""}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -29,5 +29,6 @@
|
||||||
{type}
|
{type}
|
||||||
on:change={onChange}
|
on:change={onChange}
|
||||||
on:click
|
on:click
|
||||||
on:input />
|
on:input
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
|
@ -31,5 +31,6 @@
|
||||||
{getOptionLabel}
|
{getOptionLabel}
|
||||||
{getOptionValue}
|
{getOptionValue}
|
||||||
on:change={onChange}
|
on:change={onChange}
|
||||||
on:click />
|
on:click
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
|
@ -33,5 +33,6 @@
|
||||||
{options}
|
{options}
|
||||||
{getOptionLabel}
|
{getOptionLabel}
|
||||||
{getOptionValue}
|
{getOptionValue}
|
||||||
on:change={onChange} />
|
on:change={onChange}
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
|
@ -23,5 +23,6 @@
|
||||||
{placeholder}
|
{placeholder}
|
||||||
on:change={onChange}
|
on:change={onChange}
|
||||||
on:click
|
on:click
|
||||||
on:input />
|
on:input
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
|
@ -38,5 +38,6 @@
|
||||||
{getOptionLabel}
|
{getOptionLabel}
|
||||||
{getOptionValue}
|
{getOptionValue}
|
||||||
on:change={onChange}
|
on:change={onChange}
|
||||||
on:click />
|
on:click
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
|
@ -25,5 +25,6 @@
|
||||||
{disabled}
|
{disabled}
|
||||||
{value}
|
{value}
|
||||||
{placeholder}
|
{placeholder}
|
||||||
on:change={onChange} />
|
on:change={onChange}
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
|
@ -17,4 +17,5 @@
|
||||||
class:spectrum-Link--secondary={secondary}
|
class:spectrum-Link--secondary={secondary}
|
||||||
class:spectrum-Link--overBackground={overBackground}
|
class:spectrum-Link--overBackground={overBackground}
|
||||||
class:spectrum-Link--quiet={quiet}
|
class:spectrum-Link--quiet={quiet}
|
||||||
class="spectrum-Link spectrum-Link--size{size}"><slot /></a>
|
class="spectrum-Link spectrum-Link--size{size}"><slot /></a
|
||||||
|
>
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<script>
|
<script>
|
||||||
export let heading
|
export let heading
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<li role="presentation">
|
<li role="presentation">
|
||||||
<span class="spectrum-Menu-sectionHeading">{heading}</span>
|
<span class="spectrum-Menu-sectionHeading">{heading}</span>
|
||||||
<ul class="spectrum-Menu" role="group">
|
<ul class="spectrum-Menu" role="group">
|
||||||
<slot />
|
<slot />
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<li class="spectrum-Menu-divider" role="separator"></li>
|
<li class="spectrum-Menu-divider" role="separator" />
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
<div on:click={increment}>
|
<div on:click={increment}>
|
||||||
Click me
|
Click me
|
||||||
{remaining}
|
{remaining}
|
||||||
more time{remaining === 1 ? '' : 's'}
|
more time{remaining === 1 ? "" : "s"}
|
||||||
to close this modal!
|
to close this modal!
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -50,13 +50,15 @@
|
||||||
<div
|
<div
|
||||||
class="spectrum-Underlay is-open"
|
class="spectrum-Underlay is-open"
|
||||||
transition:fade={{ duration: 200 }}
|
transition:fade={{ duration: 200 }}
|
||||||
on:mousedown|self={hide}>
|
on:mousedown|self={hide}
|
||||||
|
>
|
||||||
<div class="modal-wrapper" on:mousedown|self={hide}>
|
<div class="modal-wrapper" on:mousedown|self={hide}>
|
||||||
<div class="modal-inner-wrapper" on:mousedown|self={hide}>
|
<div class="modal-inner-wrapper" on:mousedown|self={hide}>
|
||||||
<div
|
<div
|
||||||
use:focusFirstInput
|
use:focusFirstInput
|
||||||
class="spectrum-Modal is-open"
|
class="spectrum-Modal is-open"
|
||||||
transition:fly={{ y: 30, duration: 200 }}>
|
transition:fly={{ y: 30, duration: 200 }}
|
||||||
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
import Context from "../context"
|
import Context from "../context"
|
||||||
|
|
||||||
export let title = undefined
|
export let title = undefined
|
||||||
export let size = "small"
|
export let size = "S"
|
||||||
export let cancelText = "Cancel"
|
export let cancelText = "Cancel"
|
||||||
export let confirmText = "Confirm"
|
export let confirmText = "Confirm"
|
||||||
export let showCancelButton = true
|
export let showCancelButton = true
|
||||||
|
@ -30,11 +30,16 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="spectrum-Dialog spectrum-Dialog--{size}"
|
class="spectrum-Dialog"
|
||||||
|
class:spectrum-Dialog--small={size === "S"}
|
||||||
|
class:spectrum-Dialog--medium={size === "M"}
|
||||||
|
class:spectrum-Dialog--large={size === "L"}
|
||||||
|
class:spectrum-Dialog--extraLarge={size === "XL"}
|
||||||
style="position: relative;"
|
style="position: relative;"
|
||||||
role="dialog"
|
role="dialog"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
aria-modal="true">
|
aria-modal="true"
|
||||||
|
>
|
||||||
<div class="spectrum-Dialog-grid">
|
<div class="spectrum-Dialog-grid">
|
||||||
<h1 class="spectrum-Dialog-heading spectrum-Dialog-heading--noHeader">
|
<h1 class="spectrum-Dialog-heading spectrum-Dialog-heading--noHeader">
|
||||||
{title}
|
{title}
|
||||||
|
@ -47,7 +52,8 @@
|
||||||
</section>
|
</section>
|
||||||
{#if showCancelButton || showConfirmButton}
|
{#if showCancelButton || showConfirmButton}
|
||||||
<div
|
<div
|
||||||
class="spectrum-ButtonGroup spectrum-Dialog-buttonGroup spectrum-Dialog-buttonGroup--noFooter">
|
class="spectrum-ButtonGroup spectrum-Dialog-buttonGroup spectrum-Dialog-buttonGroup--noFooter"
|
||||||
|
>
|
||||||
<slot name="footer" />
|
<slot name="footer" />
|
||||||
{#if showCancelButton}
|
{#if showCancelButton}
|
||||||
<Button group secondary on:click={hide}>{cancelText}</Button>
|
<Button group secondary on:click={hide}>{cancelText}</Button>
|
||||||
|
@ -58,7 +64,8 @@
|
||||||
cta
|
cta
|
||||||
{...$$restProps}
|
{...$$restProps}
|
||||||
disabled={confirmDisabled}
|
disabled={confirmDisabled}
|
||||||
on:click={confirm}>
|
on:click={confirm}
|
||||||
|
>
|
||||||
{confirmText}
|
{confirmText}
|
||||||
</Button>
|
</Button>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -73,6 +80,9 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.spectrum-Dialog--extraLarge {
|
||||||
|
width: 1000px;
|
||||||
|
}
|
||||||
.content-grid {
|
.content-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
@ -31,7 +31,8 @@
|
||||||
bind:this={modal}
|
bind:this={modal}
|
||||||
confirmText="Submit"
|
confirmText="Submit"
|
||||||
onConfirm={answerQuiz}
|
onConfirm={answerQuiz}
|
||||||
on:show={resetState}>
|
on:show={resetState}
|
||||||
|
>
|
||||||
{#if error}
|
{#if error}
|
||||||
<p class="error">Wrong answer! Try again.</p>
|
<p class="error">Wrong answer! Try again.</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -3,15 +3,23 @@
|
||||||
import Portal from "svelte-portal"
|
import Portal from "svelte-portal"
|
||||||
import { flip } from "svelte/animate"
|
import { flip } from "svelte/animate"
|
||||||
import { fly } from "svelte/transition"
|
import { fly } from "svelte/transition"
|
||||||
import { notifications } from '../Stores/notifications'
|
import { notifications } from "../Stores/notifications"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Portal target=".modal-container">
|
<Portal target=".modal-container">
|
||||||
<div class="notifications">
|
<div class="notifications">
|
||||||
{#each $notifications as {type, icon, message, id} (id)}
|
{#each $notifications as { type, icon, message, id } (id)}
|
||||||
<div animate:flip transition:fly={{ y: -30 }} class="spectrum-Toast spectrum-Toast--{type} notification-offset">
|
<div
|
||||||
|
animate:flip
|
||||||
|
transition:fly={{ y: -30 }}
|
||||||
|
class="spectrum-Toast spectrum-Toast--{type} notification-offset"
|
||||||
|
>
|
||||||
{#if icon}
|
{#if icon}
|
||||||
<svg class="spectrum-Icon spectrum-Icon--sizeM spectrum-Toast-typeIcon" focusable="false" aria-hidden="true">
|
<svg
|
||||||
|
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Toast-typeIcon"
|
||||||
|
focusable="false"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-icon-18-{icon}" />
|
<use xlink:href="#spectrum-icon-18-{icon}" />
|
||||||
</svg>
|
</svg>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -21,8 +29,9 @@
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</Portal>
|
</Portal>
|
||||||
<style>
|
|
||||||
|
<style>
|
||||||
.notifications {
|
.notifications {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
|
@ -40,5 +49,4 @@
|
||||||
.notification-offset {
|
.notification-offset {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,8 @@
|
||||||
use:clickOutside={hide}
|
use:clickOutside={hide}
|
||||||
on:keydown={handleEscape}
|
on:keydown={handleEscape}
|
||||||
class="spectrum-Popover is-open"
|
class="spectrum-Popover is-open"
|
||||||
role="presentation">
|
role="presentation"
|
||||||
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</Portal>
|
</Portal>
|
||||||
|
|
|
@ -1,29 +1,33 @@
|
||||||
<script>
|
<script>
|
||||||
// WIP! Does not yet work.
|
// WIP! Does not yet work.
|
||||||
import "@spectrum-css/progresscircle/dist/index-vars.css"
|
import "@spectrum-css/progresscircle/dist/index-vars.css"
|
||||||
import { tweened } from 'svelte/motion';
|
import { tweened } from "svelte/motion"
|
||||||
import { cubicOut } from 'svelte/easing';
|
import { cubicOut } from "svelte/easing"
|
||||||
|
|
||||||
export let value = false
|
export let value = false
|
||||||
export let small;
|
export let small
|
||||||
export let large;
|
export let large
|
||||||
|
|
||||||
export let overBackground;
|
export let overBackground
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class:spectrum-ProgressBar--indeterminate={!value} class:spectrum-ProgressCircle--small={small} class:spectrum-ProgressCircle--large={large} class="spectrum-ProgressCircle">
|
<div
|
||||||
<div class="spectrum-ProgressCircle-track"></div>
|
class:spectrum-ProgressBar--indeterminate={!value}
|
||||||
|
class:spectrum-ProgressCircle--small={small}
|
||||||
|
class:spectrum-ProgressCircle--large={large}
|
||||||
|
class="spectrum-ProgressCircle"
|
||||||
|
>
|
||||||
|
<div class="spectrum-ProgressCircle-track" />
|
||||||
<div class="spectrum-ProgressCircle-fills">
|
<div class="spectrum-ProgressCircle-fills">
|
||||||
<div class="spectrum-ProgressCircle-fillMask1">
|
<div class="spectrum-ProgressCircle-fillMask1">
|
||||||
<div class="spectrum-ProgressCircle-fillSubMask1">
|
<div class="spectrum-ProgressCircle-fillSubMask1">
|
||||||
<div class="spectrum-ProgressCircle-fill"></div>
|
<div class="spectrum-ProgressCircle-fill" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="spectrum-ProgressCircle-fillMask2">
|
<div class="spectrum-ProgressCircle-fillMask2">
|
||||||
<div class="spectrum-ProgressCircle-fillSubMask2">
|
<div class="spectrum-ProgressCircle-fillSubMask2">
|
||||||
<div class="spectrum-ProgressCircle-fill"></div>
|
<div class="spectrum-ProgressCircle-fill" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,36 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext } from 'svelte'
|
import { getContext } from "svelte"
|
||||||
const multilevel = getContext('sidenav-type');
|
const multilevel = getContext("sidenav-type")
|
||||||
export let href = "";
|
export let href = ""
|
||||||
export let external = false;
|
export let external = false
|
||||||
export let heading = ""
|
export let heading = ""
|
||||||
export let icon = "";
|
export let icon = ""
|
||||||
export let selected = false;
|
export let selected = false
|
||||||
export let disabled = false;
|
export let disabled = false
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<li class="spectrum-SideNav-item" class:is-selected={selected} class:is-disabled={disabled}>
|
<li
|
||||||
|
class="spectrum-SideNav-item"
|
||||||
|
class:is-selected={selected}
|
||||||
|
class:is-disabled={disabled}
|
||||||
|
>
|
||||||
{#if heading}
|
{#if heading}
|
||||||
<h2 class="spectrum-SideNav-heading" id="nav-heading-{heading}">{heading}</h2>
|
<h2 class="spectrum-SideNav-heading" id="nav-heading-{heading}">
|
||||||
|
{heading}
|
||||||
|
</h2>
|
||||||
{/if}
|
{/if}
|
||||||
<a target={external ? '_blank' : '_self'} {href} class="spectrum-SideNav-itemLink" aria-current="page">
|
<a
|
||||||
|
target={external ? "_blank" : "_self"}
|
||||||
|
{href}
|
||||||
|
class="spectrum-SideNav-itemLink"
|
||||||
|
aria-current="page"
|
||||||
|
>
|
||||||
{#if icon}
|
{#if icon}
|
||||||
<svg class="spectrum-Icon spectrum-Icon--sizeM spectrum-SideNav-itemIcon" focusable="false" aria-hidden="true">
|
<svg
|
||||||
|
class="spectrum-Icon spectrum-Icon--sizeM spectrum-SideNav-itemIcon"
|
||||||
|
focusable="false"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-icon-18-{icon}" />
|
<use xlink:href="#spectrum-icon-18-{icon}" />
|
||||||
</svg>
|
</svg>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<script>
|
<script>
|
||||||
import { setContext } from 'svelte'
|
import { setContext } from "svelte"
|
||||||
import "@spectrum-css/sidenav/dist/index-vars.css"
|
import "@spectrum-css/sidenav/dist/index-vars.css"
|
||||||
export let multilevel = false;
|
export let multilevel = false
|
||||||
setContext('sidenav-type', multilevel)
|
setContext("sidenav-type", multilevel)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<nav>
|
<nav>
|
||||||
|
|
|
@ -7,7 +7,7 @@ export const createNotificationStore = () => {
|
||||||
const _notifications = writable([], () => {
|
const _notifications = writable([], () => {
|
||||||
return () => {
|
return () => {
|
||||||
// clear all the timers
|
// clear all the timers
|
||||||
timeoutIds.forEach((timeoutId) => {
|
timeoutIds.forEach(timeoutId => {
|
||||||
clearTimeout(timeoutId)
|
clearTimeout(timeoutId)
|
||||||
})
|
})
|
||||||
_notifications.set([])
|
_notifications.set([])
|
||||||
|
@ -25,11 +25,11 @@ export const createNotificationStore = () => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let _id = id()
|
let _id = id()
|
||||||
_notifications.update((state) => {
|
_notifications.update(state => {
|
||||||
return [...state, { id: _id, type, message, icon }]
|
return [...state, { id: _id, type, message, icon }]
|
||||||
})
|
})
|
||||||
const timeoutId = setTimeout(() => {
|
const timeoutId = setTimeout(() => {
|
||||||
_notifications.update((state) => {
|
_notifications.update(state => {
|
||||||
return state.filter(({ id }) => id !== _id)
|
return state.filter(({ id }) => id !== _id)
|
||||||
})
|
})
|
||||||
}, NOTIFICATION_TIMEOUT)
|
}, NOTIFICATION_TIMEOUT)
|
||||||
|
@ -41,10 +41,10 @@ export const createNotificationStore = () => {
|
||||||
return {
|
return {
|
||||||
subscribe,
|
subscribe,
|
||||||
send,
|
send,
|
||||||
info: (msg) => send(msg, "info", "Info"),
|
info: msg => send(msg, "info", "Info"),
|
||||||
error: (msg) => send(msg, "error", "Alert"),
|
error: msg => send(msg, "error", "Alert"),
|
||||||
warning: (msg) => send(msg, "warning", "Alert"),
|
warning: msg => send(msg, "warning", "Alert"),
|
||||||
success: (msg) => send(msg, "success", "CheckmarkCircle"),
|
success: msg => send(msg, "success", "CheckmarkCircle"),
|
||||||
blockNotifications,
|
blockNotifications,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,24 +5,28 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<label
|
<label
|
||||||
class="spectrum-Checkbox spectrum-Checkbox--sizeM spectrum-Checkbox--emphasized">
|
class="spectrum-Checkbox spectrum-Checkbox--sizeM spectrum-Checkbox--emphasized"
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="spectrum-Checkbox-input"
|
class="spectrum-Checkbox-input"
|
||||||
id="checkbox-1"
|
id="checkbox-1"
|
||||||
disabled
|
disabled
|
||||||
checked={!!value} />
|
checked={!!value}
|
||||||
|
/>
|
||||||
<span class="spectrum-Checkbox-box">
|
<span class="spectrum-Checkbox-box">
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Checkbox-checkmark"
|
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Checkbox-checkmark"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true">
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
||||||
</svg>
|
</svg>
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-UIIcon-Dash100 spectrum-Checkbox-partialCheckmark"
|
class="spectrum-Icon spectrum-UIIcon-Dash100 spectrum-Checkbox-partialCheckmark"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true">
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-css-icon-Dash100" />
|
<use xlink:href="#spectrum-css-icon-Dash100" />
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
$: renderer = customRenderer?.component ?? typeMap[type]
|
$: renderer = customRenderer?.component ?? typeMap[type]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if renderer && (customRenderer || (value != null && value !== ''))}
|
{#if renderer && (customRenderer || (value != null && value !== ""))}
|
||||||
<svelte:component this={renderer} {row} {schema} {value} on:clickrelationship>
|
<svelte:component this={renderer} {row} {schema} {value} on:clickrelationship>
|
||||||
<slot />
|
<slot />
|
||||||
</svelte:component>
|
</svelte:component>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
export let value
|
export let value
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>{dayjs(value).format('MMMM D YYYY, HH:mm')}</div>
|
<div>{dayjs(value).format("MMMM D YYYY, HH:mm")}</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
div {
|
div {
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
// Table state
|
// Table state
|
||||||
let height = 0
|
let height = 0
|
||||||
let loaded = false
|
let loaded = false
|
||||||
|
$: schema = fixSchema(schema)
|
||||||
$: if (!loading) loaded = true
|
$: if (!loading) loaded = true
|
||||||
$: rows = data ?? []
|
$: rows = data ?? []
|
||||||
$: visibleRowCount = getVisibleRowCount(loaded, height, rows.length, rowCount)
|
$: visibleRowCount = getVisibleRowCount(loaded, height, rows.length, rowCount)
|
||||||
|
@ -50,7 +51,7 @@
|
||||||
rows.length
|
rows.length
|
||||||
)
|
)
|
||||||
|
|
||||||
// Reset state when data chanegs
|
// Reset state when data changes
|
||||||
$: data.length, reset()
|
$: data.length, reset()
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
nextScrollTop = 0
|
nextScrollTop = 0
|
||||||
|
@ -59,6 +60,24 @@
|
||||||
timeout = null
|
timeout = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fixSchema = schema => {
|
||||||
|
let fixedSchema = {}
|
||||||
|
Object.entries(schema || {}).forEach(([fieldName, fieldSchema]) => {
|
||||||
|
if (typeof fieldSchema === "string") {
|
||||||
|
fixedSchema[fieldName] = {
|
||||||
|
type: fieldSchema,
|
||||||
|
name: fieldName,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fixedSchema[fieldName] = {
|
||||||
|
...fieldSchema,
|
||||||
|
name: fieldName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return fixedSchema
|
||||||
|
}
|
||||||
|
|
||||||
const getVisibleRowCount = (loaded, height, allRows, rowCount) => {
|
const getVisibleRowCount = (loaded, height, allRows, rowCount) => {
|
||||||
if (!loaded) {
|
if (!loaded) {
|
||||||
return rowCount || 0
|
return rowCount || 0
|
||||||
|
@ -118,7 +137,6 @@
|
||||||
if (!field || !fieldSchema) {
|
if (!field || !fieldSchema) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
schema[field].name = field
|
|
||||||
if (!fieldSchema?.autocolumn) {
|
if (!fieldSchema?.autocolumn) {
|
||||||
columns.push(fieldSchema)
|
columns.push(fieldSchema)
|
||||||
} else if (showAutoColumns) {
|
} else if (showAutoColumns) {
|
||||||
|
@ -192,7 +210,8 @@
|
||||||
on:scroll={onScroll}
|
on:scroll={onScroll}
|
||||||
class:quiet
|
class:quiet
|
||||||
style={`--row-height: ${rowHeight}px; --header-height: ${headerHeight}px;`}
|
style={`--row-height: ${rowHeight}px; --header-height: ${headerHeight}px;`}
|
||||||
class="container">
|
class="container"
|
||||||
|
>
|
||||||
<div style={contentStyle}>
|
<div style={contentStyle}>
|
||||||
<table class="spectrum-Table" class:spectrum-Table--quiet={quiet}>
|
<table class="spectrum-Table" class:spectrum-Table--quiet={quiet}>
|
||||||
{#if sortedRows?.length}
|
{#if sortedRows?.length}
|
||||||
|
@ -201,7 +220,7 @@
|
||||||
{#if showEditColumn}
|
{#if showEditColumn}
|
||||||
<th class="spectrum-Table-headCell">
|
<th class="spectrum-Table-headCell">
|
||||||
<div class="spectrum-Table-headCell-content">
|
<div class="spectrum-Table-headCell-content">
|
||||||
{editColumnTitle || ''}
|
{editColumnTitle || ""}
|
||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -209,15 +228,19 @@
|
||||||
<th
|
<th
|
||||||
class="spectrum-Table-headCell"
|
class="spectrum-Table-headCell"
|
||||||
class:is-sortable={schema[field].sortable !== false}
|
class:is-sortable={schema[field].sortable !== false}
|
||||||
class:is-sorted-desc={sortColumn === field && sortOrder === 'Descending'}
|
class:is-sorted-desc={sortColumn === field &&
|
||||||
class:is-sorted-asc={sortColumn === field && sortOrder === 'Ascending'}
|
sortOrder === "Descending"}
|
||||||
on:click={() => sortBy(schema[field])}>
|
class:is-sorted-asc={sortColumn === field &&
|
||||||
|
sortOrder === "Ascending"}
|
||||||
|
on:click={() => sortBy(schema[field])}
|
||||||
|
>
|
||||||
<div class="spectrum-Table-headCell-content">
|
<div class="spectrum-Table-headCell-content">
|
||||||
<div class="title">{getDisplayName(schema[field])}</div>
|
<div class="title">{getDisplayName(schema[field])}</div>
|
||||||
{#if schema[field]?.autocolumn}
|
{#if schema[field]?.autocolumn}
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-Table-autoIcon"
|
class="spectrum-Icon spectrum-Table-autoIcon"
|
||||||
focusable="false">
|
focusable="false"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-icon-18-MagicWand" />
|
<use xlink:href="#spectrum-icon-18-MagicWand" />
|
||||||
</svg>
|
</svg>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -225,7 +248,8 @@
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-UIIcon-ArrowDown100 spectrum-Table-sortedIcon"
|
class="spectrum-Icon spectrum-UIIcon-ArrowDown100 spectrum-Table-sortedIcon"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true">
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-css-icon-Arrow100" />
|
<use xlink:href="#spectrum-css-icon-Arrow100" />
|
||||||
</svg>
|
</svg>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -233,7 +257,8 @@
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-Table-editIcon"
|
class="spectrum-Icon spectrum-Table-editIcon"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
on:click={e => editColumn(e, field)}>
|
on:click={e => editColumn(e, field)}
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-icon-18-Edit" />
|
<use xlink:href="#spectrum-icon-18-Edit" />
|
||||||
</svg>
|
</svg>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -249,11 +274,13 @@
|
||||||
<tr
|
<tr
|
||||||
on:click={() => toggleSelectRow(row)}
|
on:click={() => toggleSelectRow(row)}
|
||||||
class="spectrum-Table-row"
|
class="spectrum-Table-row"
|
||||||
class:hidden={idx < firstVisibleRow || idx > lastVisibleRow}>
|
class:hidden={idx < firstVisibleRow || idx > lastVisibleRow}
|
||||||
|
>
|
||||||
{#if idx >= firstVisibleRow && idx <= lastVisibleRow}
|
{#if idx >= firstVisibleRow && idx <= lastVisibleRow}
|
||||||
{#if showEditColumn}
|
{#if showEditColumn}
|
||||||
<td
|
<td
|
||||||
class="spectrum-Table-cell spectrum-Table-cell--divider">
|
class="spectrum-Table-cell spectrum-Table-cell--divider"
|
||||||
|
>
|
||||||
<div class="spectrum-Table-cell-content">
|
<div class="spectrum-Table-cell-content">
|
||||||
<SelectEditRenderer
|
<SelectEditRenderer
|
||||||
data={row}
|
data={row}
|
||||||
|
@ -261,21 +288,25 @@
|
||||||
onToggleSelection={() => toggleSelectRow(row)}
|
onToggleSelection={() => toggleSelectRow(row)}
|
||||||
onEdit={e => editRow(e, row)}
|
onEdit={e => editRow(e, row)}
|
||||||
{allowSelectRows}
|
{allowSelectRows}
|
||||||
{allowEditRows} />
|
{allowEditRows}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
{/if}
|
{/if}
|
||||||
{#each fields as field}
|
{#each fields as field}
|
||||||
<td
|
<td
|
||||||
class="spectrum-Table-cell"
|
class="spectrum-Table-cell"
|
||||||
class:spectrum-Table-cell--divider={!!schema[field].divider}>
|
class:spectrum-Table-cell--divider={!!schema[field]
|
||||||
|
.divider}
|
||||||
|
>
|
||||||
<div class="spectrum-Table-cell-content">
|
<div class="spectrum-Table-cell-content">
|
||||||
<CellRenderer
|
<CellRenderer
|
||||||
{customRenderers}
|
{customRenderers}
|
||||||
{row}
|
{row}
|
||||||
schema={schema[field]}
|
schema={schema[field]}
|
||||||
value={row[field]}
|
value={row[field]}
|
||||||
on:clickrelationship>
|
on:clickrelationship
|
||||||
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</CellRenderer>
|
</CellRenderer>
|
||||||
</div>
|
</div>
|
||||||
|
@ -288,7 +319,8 @@
|
||||||
<div class="placeholder">
|
<div class="placeholder">
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-Icon--sizeXXL"
|
class="spectrum-Icon spectrum-Icon--sizeXXL"
|
||||||
focusable="false">
|
focusable="false"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-icon-18-Table" />
|
<use xlink:href="#spectrum-icon-18-Table" />
|
||||||
</svg>
|
</svg>
|
||||||
<div>No rows found</div>
|
<div>No rows found</div>
|
||||||
|
|
|
@ -30,13 +30,15 @@
|
||||||
on:click={onClick}
|
on:click={onClick}
|
||||||
class:is-selected={$selected.title === title}
|
class:is-selected={$selected.title === title}
|
||||||
class="spectrum-Tabs-item"
|
class="spectrum-Tabs-item"
|
||||||
tabindex="0">
|
tabindex="0"
|
||||||
|
>
|
||||||
{#if icon}
|
{#if icon}
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-Icon--sizeM"
|
class="spectrum-Icon spectrum-Icon--sizeM"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
aria-label="Folder">
|
aria-label="Folder"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-icon-18-{icon}" />
|
<use xlink:href="#spectrum-icon-18-{icon}" />
|
||||||
</svg>
|
</svg>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -44,23 +44,22 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
function id() {
|
function id() {
|
||||||
return (
|
return "_" + Math.random().toString(36).substr(2, 9)
|
||||||
"_" +
|
|
||||||
Math.random()
|
|
||||||
.toString(36)
|
|
||||||
.substr(2, 9)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
bind:this={container}
|
bind:this={container}
|
||||||
class="selected-border spectrum-Tabs spectrum-Tabs--{vertical ? 'vertical' : 'horizontal'}">
|
class="selected-border spectrum-Tabs spectrum-Tabs--{vertical
|
||||||
|
? 'vertical'
|
||||||
|
: 'horizontal'}"
|
||||||
|
>
|
||||||
<slot />
|
<slot />
|
||||||
{#if $tab.info}
|
{#if $tab.info}
|
||||||
<div
|
<div
|
||||||
class="spectrum-Tabs-selectionIndicator indicator-transition"
|
class="spectrum-Tabs-selectionIndicator indicator-transition"
|
||||||
style="width: {width}; height: {height}; left: {left}; top: {top};" />
|
style="width: {width}; height: {height}; left: {left}; top: {top};"
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,29 @@
|
||||||
<script>
|
<script>
|
||||||
import Avatar from '../Avatar/Avatar.svelte'
|
import Avatar from "../Avatar/Avatar.svelte"
|
||||||
import ClearButton from '../ClearButton/ClearButton.svelte'
|
import ClearButton from "../ClearButton/ClearButton.svelte"
|
||||||
export let icon = "";
|
export let icon = ""
|
||||||
export let avatar = "";
|
export let avatar = ""
|
||||||
export let invalid = false;
|
export let invalid = false
|
||||||
export let disabled = false;
|
export let disabled = false
|
||||||
export let closable = false;
|
export let closable = false
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class:is-invalid={invalid} class:is-disabled={disabled} class="spectrum-Tags-item" role="listitem">
|
<div
|
||||||
|
class:is-invalid={invalid}
|
||||||
|
class:is-disabled={disabled}
|
||||||
|
class="spectrum-Tags-item"
|
||||||
|
role="listitem"
|
||||||
|
>
|
||||||
{#if avatar}
|
{#if avatar}
|
||||||
<Avatar url={avatar} />
|
<Avatar url={avatar} />
|
||||||
{/if}
|
{/if}
|
||||||
{#if icon}
|
{#if icon}
|
||||||
<svg class="spectrum-Icon spectrum-Icon--sizeS" focusable="false" aria-hidden="true" aria-label="Tag">
|
<svg
|
||||||
|
class="spectrum-Icon spectrum-Icon--sizeS"
|
||||||
|
focusable="false"
|
||||||
|
aria-hidden="true"
|
||||||
|
aria-label="Tag"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-icon-24-{icon}" />
|
<use xlink:href="#spectrum-icon-24-{icon}" />
|
||||||
</svg>
|
</svg>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -1,20 +1,32 @@
|
||||||
<script>
|
<script>
|
||||||
export let selected = false;
|
export let selected = false
|
||||||
export let open = false;
|
export let open = false
|
||||||
export let title;
|
export let title
|
||||||
export let icon;
|
export let icon
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<li
|
<li
|
||||||
class:is-selected={selected} class:is-open={open} class="spectrum-TreeView-item">
|
class:is-selected={selected}
|
||||||
|
class:is-open={open}
|
||||||
|
class="spectrum-TreeView-item"
|
||||||
|
>
|
||||||
<a on:click class="spectrum-TreeView-itemLink" href="#">
|
<a on:click class="spectrum-TreeView-itemLink" href="#">
|
||||||
{#if $$slots.default}
|
{#if $$slots.default}
|
||||||
<svg class="spectrum-Icon spectrum-UIIcon-ChevronRight100 spectrum-TreeView-itemIndicator" focusable="false" aria-hidden="true">
|
<svg
|
||||||
|
class="spectrum-Icon spectrum-UIIcon-ChevronRight100 spectrum-TreeView-itemIndicator"
|
||||||
|
focusable="false"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-css-icon-Chevron100" />
|
<use xlink:href="#spectrum-css-icon-Chevron100" />
|
||||||
</svg>
|
</svg>
|
||||||
{/if}
|
{/if}
|
||||||
{#if icon}
|
{#if icon}
|
||||||
<svg class="spectrum-TreeView-itemIcon spectrum-Icon spectrum-Icon--sizeM" focusable="false" aria-hidden="true" aria-label="Layers">
|
<svg
|
||||||
|
class="spectrum-TreeView-itemIcon spectrum-Icon spectrum-Icon--sizeM"
|
||||||
|
focusable="false"
|
||||||
|
aria-hidden="true"
|
||||||
|
aria-label="Layers"
|
||||||
|
>
|
||||||
<use xlink:href="#spectrum-icon-18-{icon}" />
|
<use xlink:href="#spectrum-icon-18-{icon}" />
|
||||||
</svg>
|
</svg>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -3,9 +3,14 @@
|
||||||
|
|
||||||
export let quiet = false
|
export let quiet = false
|
||||||
export let standalone = true
|
export let standalone = true
|
||||||
export let width = '250px';
|
export let width = "250px"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ul class:spectrum-TreeView--standalone={standalone} class:spectrum-TreeView--quiet={quiet} class="spectrum-TreeView" style="width: {width}">
|
<ul
|
||||||
|
class:spectrum-TreeView--standalone={standalone}
|
||||||
|
class:spectrum-TreeView--quiet={quiet}
|
||||||
|
class="spectrum-TreeView"
|
||||||
|
style="width: {width}"
|
||||||
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</ul>
|
</ul>
|
|
@ -6,7 +6,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
Cypress.Commands.add("login", () => {
|
Cypress.Commands.add("login", () => {
|
||||||
cy.getCookie("budibase:auth").then((cookie) => {
|
cy.getCookie("budibase:auth").then(cookie => {
|
||||||
// Already logged in
|
// Already logged in
|
||||||
if (cookie) return
|
if (cookie) return
|
||||||
|
|
||||||
|
@ -20,13 +20,13 @@ Cypress.Commands.add("login", () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Cypress.Commands.add("createApp", (name) => {
|
Cypress.Commands.add("createApp", name => {
|
||||||
cy.visit(`localhost:${Cypress.env("PORT")}/builder`)
|
cy.visit(`localhost:${Cypress.env("PORT")}/builder`)
|
||||||
// wait for init API calls on visit
|
// wait for init API calls on visit
|
||||||
cy.wait(100)
|
cy.wait(100)
|
||||||
cy.contains("Create New Web App").click()
|
cy.contains("Create New Web App").click()
|
||||||
cy.get("body")
|
cy.get("body")
|
||||||
.then(($body) => {
|
.then($body => {
|
||||||
if ($body.find("input[name=apiKey]").length) {
|
if ($body.find("input[name=apiKey]").length) {
|
||||||
// input was found, do something else here
|
// input was found, do something else here
|
||||||
cy.get("input[name=apiKey]").type(name).should("have.value", name)
|
cy.get("input[name=apiKey]").type(name).should("have.value", name)
|
||||||
|
@ -50,9 +50,9 @@ Cypress.Commands.add("createApp", (name) => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Cypress.Commands.add("deleteApp", (name) => {
|
Cypress.Commands.add("deleteApp", name => {
|
||||||
cy.visit(`localhost:${Cypress.env("PORT")}/builder`)
|
cy.visit(`localhost:${Cypress.env("PORT")}/builder`)
|
||||||
cy.get(".apps").then(($apps) => {
|
cy.get(".apps").then($apps => {
|
||||||
cy.wait(1000)
|
cy.wait(1000)
|
||||||
if ($apps.find(`[data-cy="app-${name}"]`).length) {
|
if ($apps.find(`[data-cy="app-${name}"]`).length) {
|
||||||
cy.get(`[data-cy="app-${name}"]`).contains("Open").click()
|
cy.get(`[data-cy="app-${name}"]`).contains("Open").click()
|
||||||
|
@ -78,7 +78,7 @@ Cypress.Commands.add("createTestTableWithData", () => {
|
||||||
cy.addColumn("dog", "age", "Number")
|
cy.addColumn("dog", "age", "Number")
|
||||||
})
|
})
|
||||||
|
|
||||||
Cypress.Commands.add("createTable", (tableName) => {
|
Cypress.Commands.add("createTable", tableName => {
|
||||||
// Enter table name
|
// Enter table name
|
||||||
cy.get("[data-cy=new-table]").click()
|
cy.get("[data-cy=new-table]").click()
|
||||||
cy.get(".spectrum-Modal").within(() => {
|
cy.get(".spectrum-Modal").within(() => {
|
||||||
|
@ -104,7 +104,7 @@ Cypress.Commands.add("addColumn", (tableName, columnName, type) => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Cypress.Commands.add("addRow", (values) => {
|
Cypress.Commands.add("addRow", values => {
|
||||||
cy.contains("Create row").click()
|
cy.contains("Create row").click()
|
||||||
cy.get(".spectrum-Modal").within(() => {
|
cy.get(".spectrum-Modal").within(() => {
|
||||||
for (let i = 0; i < values.length; i++) {
|
for (let i = 0; i < values.length; i++) {
|
||||||
|
@ -134,7 +134,7 @@ Cypress.Commands.add("addComponent", (category, component) => {
|
||||||
}
|
}
|
||||||
cy.get(`[data-cy="component-${component}"]`).click()
|
cy.get(`[data-cy="component-${component}"]`).click()
|
||||||
cy.wait(1000)
|
cy.wait(1000)
|
||||||
cy.location().then((loc) => {
|
cy.location().then(loc => {
|
||||||
const params = loc.pathname.split("/")
|
const params = loc.pathname.split("/")
|
||||||
const componentId = params[params.length - 1]
|
const componentId = params[params.length - 1]
|
||||||
cy.getComponent(componentId).should("exist")
|
cy.getComponent(componentId).should("exist")
|
||||||
|
@ -142,7 +142,7 @@ Cypress.Commands.add("addComponent", (category, component) => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Cypress.Commands.add("getComponent", (componentId) => {
|
Cypress.Commands.add("getComponent", componentId => {
|
||||||
return cy
|
return cy
|
||||||
.get("iframe")
|
.get("iframe")
|
||||||
.its("0.contentDocument")
|
.its("0.contentDocument")
|
||||||
|
|
|
@ -106,7 +106,7 @@
|
||||||
"rollup": "^2.44.0",
|
"rollup": "^2.44.0",
|
||||||
"rollup-plugin-copy": "^3.4.0",
|
"rollup-plugin-copy": "^3.4.0",
|
||||||
"start-server-and-test": "^1.12.1",
|
"start-server-and-test": "^1.12.1",
|
||||||
"svelte": "^3.36.0",
|
"svelte": "^3.37.0",
|
||||||
"svelte-jester": "^1.3.2",
|
"svelte-jester": "^1.3.2",
|
||||||
"vite": "^2.1.5"
|
"vite": "^2.1.5"
|
||||||
},
|
},
|
||||||
|
|
|
@ -32,7 +32,7 @@ function identify(id) {
|
||||||
if (!analyticsEnabled || !id) return
|
if (!analyticsEnabled || !id) return
|
||||||
if (posthogConfigured) posthog.identify(id)
|
if (posthogConfigured) posthog.identify(id)
|
||||||
if (sentryConfigured)
|
if (sentryConfigured)
|
||||||
Sentry.configureScope((scope) => {
|
Sentry.configureScope(scope => {
|
||||||
scope.setUser({ id: id })
|
scope.setUser({ id: id })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ if (!localStorage.getItem(APP_FIRST_STARTED_KEY)) {
|
||||||
localStorage.setItem(APP_FIRST_STARTED_KEY, Date.now())
|
localStorage.setItem(APP_FIRST_STARTED_KEY, Date.now())
|
||||||
}
|
}
|
||||||
|
|
||||||
const isFeedbackTimeElapsed = (sinceDateStr) => {
|
const isFeedbackTimeElapsed = sinceDateStr => {
|
||||||
const sinceDate = parseFloat(sinceDateStr)
|
const sinceDate = parseFloat(sinceDateStr)
|
||||||
const feedbackMilliseconds = feedbackHours * 60 * 60 * 1000
|
const feedbackMilliseconds = feedbackHours * 60 * 60 * 1000
|
||||||
return Date.now() > sinceDate + feedbackMilliseconds
|
return Date.now() > sinceDate + feedbackMilliseconds
|
||||||
|
@ -107,7 +107,7 @@ function highlightFeedbackIcon() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opt In/Out
|
// Opt In/Out
|
||||||
const ifAnalyticsEnabled = (func) => () => {
|
const ifAnalyticsEnabled = func => () => {
|
||||||
if (analyticsEnabled && process.env.POSTHOG_TOKEN) {
|
if (analyticsEnabled && process.env.POSTHOG_TOKEN) {
|
||||||
return func()
|
return func()
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { store } from "./index"
|
||||||
import { get as svelteGet } from "svelte/store"
|
import { get as svelteGet } from "svelte/store"
|
||||||
import { removeCookie, Cookies } from "./cookies"
|
import { removeCookie, Cookies } from "./cookies"
|
||||||
|
|
||||||
const apiCall = (method) => async (
|
const apiCall = method => async (
|
||||||
url,
|
url,
|
||||||
body,
|
body,
|
||||||
headers = { "Content-Type": "application/json" }
|
headers = { "Content-Type": "application/json" }
|
||||||
|
|
|
@ -4,7 +4,7 @@ export const Cookies = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCookie(cookieName) {
|
export function getCookie(cookieName) {
|
||||||
return document.cookie.split(";").some((cookie) => {
|
return document.cookie.split(";").some(cookie => {
|
||||||
return cookie.trim().startsWith(`${cookieName}=`)
|
return cookie.trim().startsWith(`${cookieName}=`)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ export const getDataProviderComponents = (asset, componentId) => {
|
||||||
path.pop()
|
path.pop()
|
||||||
|
|
||||||
// Filter by only data provider components
|
// Filter by only data provider components
|
||||||
return path.filter((component) => {
|
return path.filter(component => {
|
||||||
const def = store.actions.components.getDefinition(component._component)
|
const def = store.actions.components.getDefinition(component._component)
|
||||||
return def?.context != null
|
return def?.context != null
|
||||||
})
|
})
|
||||||
|
@ -54,7 +54,7 @@ export const getActionProviderComponents = (asset, componentId, actionType) => {
|
||||||
path.pop()
|
path.pop()
|
||||||
|
|
||||||
// Filter by only data provider components
|
// Filter by only data provider components
|
||||||
return path.filter((component) => {
|
return path.filter(component => {
|
||||||
const def = store.actions.components.getDefinition(component._component)
|
const def = store.actions.components.getDefinition(component._component)
|
||||||
return def?.actions?.includes(actionType)
|
return def?.actions?.includes(actionType)
|
||||||
})
|
})
|
||||||
|
@ -70,7 +70,7 @@ export const getDatasourceForProvider = (asset, component) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this component has a dataProvider setting, go up the stack and use it
|
// If this component has a dataProvider setting, go up the stack and use it
|
||||||
const dataProviderSetting = def.settings.find((setting) => {
|
const dataProviderSetting = def.settings.find(setting => {
|
||||||
return setting.type === "dataProvider"
|
return setting.type === "dataProvider"
|
||||||
})
|
})
|
||||||
if (dataProviderSetting) {
|
if (dataProviderSetting) {
|
||||||
|
@ -82,7 +82,7 @@ export const getDatasourceForProvider = (asset, component) => {
|
||||||
|
|
||||||
// Extract datasource from component instance
|
// Extract datasource from component instance
|
||||||
const validSettingTypes = ["dataSource", "table", "schema"]
|
const validSettingTypes = ["dataSource", "table", "schema"]
|
||||||
const datasourceSetting = def.settings.find((setting) => {
|
const datasourceSetting = def.settings.find(setting => {
|
||||||
return validSettingTypes.includes(setting.type)
|
return validSettingTypes.includes(setting.type)
|
||||||
})
|
})
|
||||||
if (!datasourceSetting) {
|
if (!datasourceSetting) {
|
||||||
|
@ -112,7 +112,7 @@ const getContextBindings = (asset, componentId) => {
|
||||||
let bindings = []
|
let bindings = []
|
||||||
|
|
||||||
// Create bindings for each data provider
|
// Create bindings for each data provider
|
||||||
dataProviders.forEach((component) => {
|
dataProviders.forEach(component => {
|
||||||
const def = store.actions.components.getDefinition(component._component)
|
const def = store.actions.components.getDefinition(component._component)
|
||||||
const contextDefinition = def.context
|
const contextDefinition = def.context
|
||||||
let schema
|
let schema
|
||||||
|
@ -127,7 +127,7 @@ const getContextBindings = (asset, componentId) => {
|
||||||
// Static contexts are fully defined by the components
|
// Static contexts are fully defined by the components
|
||||||
schema = {}
|
schema = {}
|
||||||
const values = contextDefinition.values || []
|
const values = contextDefinition.values || []
|
||||||
values.forEach((value) => {
|
values.forEach(value => {
|
||||||
schema[value.key] = { name: value.label, type: "string" }
|
schema[value.key] = { name: value.label, type: "string" }
|
||||||
})
|
})
|
||||||
} else if (contextDefinition.type === "schema") {
|
} else if (contextDefinition.type === "schema") {
|
||||||
|
@ -148,7 +148,7 @@ const getContextBindings = (asset, componentId) => {
|
||||||
|
|
||||||
// Create bindable properties for each schema field
|
// Create bindable properties for each schema field
|
||||||
const safeComponentId = makePropSafe(component._id)
|
const safeComponentId = makePropSafe(component._id)
|
||||||
keys.forEach((key) => {
|
keys.forEach(key => {
|
||||||
const fieldSchema = schema[key]
|
const fieldSchema = schema[key]
|
||||||
|
|
||||||
// Make safe runtime binding and replace certain bindings with a
|
// Make safe runtime binding and replace certain bindings with a
|
||||||
|
@ -197,7 +197,7 @@ const getUserBindings = () => {
|
||||||
})
|
})
|
||||||
const keys = Object.keys(schema).sort()
|
const keys = Object.keys(schema).sort()
|
||||||
const safeUser = makePropSafe("user")
|
const safeUser = makePropSafe("user")
|
||||||
keys.forEach((key) => {
|
keys.forEach(key => {
|
||||||
const fieldSchema = schema[key]
|
const fieldSchema = schema[key]
|
||||||
// Replace certain bindings with a new property to help display components
|
// Replace certain bindings with a new property to help display components
|
||||||
let runtimeBoundKey = key
|
let runtimeBoundKey = key
|
||||||
|
@ -224,17 +224,17 @@ const getUserBindings = () => {
|
||||||
/**
|
/**
|
||||||
* Gets all bindable properties from URL parameters.
|
* Gets all bindable properties from URL parameters.
|
||||||
*/
|
*/
|
||||||
const getUrlBindings = (asset) => {
|
const getUrlBindings = asset => {
|
||||||
const url = asset?.routing?.route ?? ""
|
const url = asset?.routing?.route ?? ""
|
||||||
const split = url.split("/")
|
const split = url.split("/")
|
||||||
let params = []
|
let params = []
|
||||||
split.forEach((part) => {
|
split.forEach(part => {
|
||||||
if (part.startsWith(":") && part.length > 1) {
|
if (part.startsWith(":") && part.length > 1) {
|
||||||
params.push(part.replace(/:/g, "").replace(/\?/g, ""))
|
params.push(part.replace(/:/g, "").replace(/\?/g, ""))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const safeURL = makePropSafe("url")
|
const safeURL = makePropSafe("url")
|
||||||
return params.map((param) => ({
|
return params.map(param => ({
|
||||||
type: "context",
|
type: "context",
|
||||||
runtimeBinding: `${safeURL}.${makePropSafe(param)}`,
|
runtimeBinding: `${safeURL}.${makePropSafe(param)}`,
|
||||||
readableBinding: `URL.${param}`,
|
readableBinding: `URL.${param}`,
|
||||||
|
@ -250,10 +250,10 @@ export const getSchemaForDatasource = (datasource, isForm = false) => {
|
||||||
const { type } = datasource
|
const { type } = datasource
|
||||||
if (type === "query") {
|
if (type === "query") {
|
||||||
const queries = get(queriesStores).list
|
const queries = get(queriesStores).list
|
||||||
table = queries.find((query) => query._id === datasource._id)
|
table = queries.find(query => query._id === datasource._id)
|
||||||
} else {
|
} else {
|
||||||
const tables = get(tablesStore).list
|
const tables = get(tablesStore).list
|
||||||
table = tables.find((table) => table._id === datasource.tableId)
|
table = tables.find(table => table._id === datasource.tableId)
|
||||||
}
|
}
|
||||||
if (table) {
|
if (table) {
|
||||||
if (type === "view") {
|
if (type === "view") {
|
||||||
|
@ -261,7 +261,7 @@ export const getSchemaForDatasource = (datasource, isForm = false) => {
|
||||||
} else if (type === "query" && isForm) {
|
} else if (type === "query" && isForm) {
|
||||||
schema = {}
|
schema = {}
|
||||||
const params = table.parameters || []
|
const params = table.parameters || []
|
||||||
params.forEach((param) => {
|
params.forEach(param => {
|
||||||
if (param?.name) {
|
if (param?.name) {
|
||||||
schema[param.name] = { ...param, type: "string" }
|
schema[param.name] = { ...param, type: "string" }
|
||||||
}
|
}
|
||||||
|
@ -277,14 +277,23 @@ export const getSchemaForDatasource = (datasource, isForm = false) => {
|
||||||
schema["_rev"] = { type: "string" }
|
schema["_rev"] = { type: "string" }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure there are "name" properties for all fields
|
// Ensure there are "name" properties for all fields and that field schema
|
||||||
if (schema) {
|
// are objects
|
||||||
Object.keys(schema).forEach((field) => {
|
let fixedSchema = {}
|
||||||
if (!schema[field].name) {
|
Object.entries(schema || {}).forEach(([fieldName, fieldSchema]) => {
|
||||||
schema[field].name = field
|
if (typeof fieldSchema === "string") {
|
||||||
|
fixedSchema[fieldName] = {
|
||||||
|
type: fieldSchema,
|
||||||
|
name: fieldName,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fixedSchema[fieldName] = {
|
||||||
|
...fieldSchema,
|
||||||
|
name: fieldName,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
schema = fixedSchema
|
||||||
}
|
}
|
||||||
return { schema, table }
|
return { schema, table }
|
||||||
}
|
}
|
||||||
|
@ -293,14 +302,14 @@ export const getSchemaForDatasource = (datasource, isForm = false) => {
|
||||||
* Builds a form schema given a form component.
|
* Builds a form schema given a form component.
|
||||||
* A form schema is a schema of all the fields nested anywhere within a form.
|
* A form schema is a schema of all the fields nested anywhere within a form.
|
||||||
*/
|
*/
|
||||||
const buildFormSchema = (component) => {
|
const buildFormSchema = component => {
|
||||||
let schema = {}
|
let schema = {}
|
||||||
if (!component) {
|
if (!component) {
|
||||||
return schema
|
return schema
|
||||||
}
|
}
|
||||||
const def = store.actions.components.getDefinition(component._component)
|
const def = store.actions.components.getDefinition(component._component)
|
||||||
const fieldSetting = def?.settings?.find(
|
const fieldSetting = def?.settings?.find(
|
||||||
(setting) => setting.key === "field" && setting.type.startsWith("field/")
|
setting => setting.key === "field" && setting.type.startsWith("field/")
|
||||||
)
|
)
|
||||||
if (fieldSetting && component.field) {
|
if (fieldSetting && component.field) {
|
||||||
const type = fieldSetting.type.split("field/")[1]
|
const type = fieldSetting.type.split("field/")[1]
|
||||||
|
@ -308,7 +317,7 @@ const buildFormSchema = (component) => {
|
||||||
schema[component.field] = { type }
|
schema[component.field] = { type }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
component._children?.forEach((child) => {
|
component._children?.forEach(child => {
|
||||||
const childSchema = buildFormSchema(child)
|
const childSchema = buildFormSchema(child)
|
||||||
schema = { ...schema, ...childSchema }
|
schema = { ...schema, ...childSchema }
|
||||||
})
|
})
|
||||||
|
@ -339,7 +348,7 @@ function bindingReplacement(bindableProperties, textWithBindings, convertTo) {
|
||||||
return textWithBindings
|
return textWithBindings
|
||||||
}
|
}
|
||||||
const convertFromProps = bindableProperties
|
const convertFromProps = bindableProperties
|
||||||
.map((el) => el[convertFrom])
|
.map(el => el[convertFrom])
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
return b.length - a.length
|
return b.length - a.length
|
||||||
})
|
})
|
||||||
|
@ -349,9 +358,7 @@ function bindingReplacement(bindableProperties, textWithBindings, convertTo) {
|
||||||
let newBoundValue = boundValue
|
let newBoundValue = boundValue
|
||||||
for (let from of convertFromProps) {
|
for (let from of convertFromProps) {
|
||||||
if (newBoundValue.includes(from)) {
|
if (newBoundValue.includes(from)) {
|
||||||
const binding = bindableProperties.find(
|
const binding = bindableProperties.find(el => el[convertFrom] === from)
|
||||||
(el) => el[convertFrom] === from
|
|
||||||
)
|
|
||||||
newBoundValue = newBoundValue.replace(from, binding[convertTo])
|
newBoundValue = newBoundValue.replace(from, binding[convertTo])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,16 +12,12 @@ export const automationStore = getAutomationStore()
|
||||||
export const themeStore = getThemeStore()
|
export const themeStore = getThemeStore()
|
||||||
export const hostingStore = getHostingStore()
|
export const hostingStore = getHostingStore()
|
||||||
|
|
||||||
export const currentAsset = derived(store, ($store) => {
|
export const currentAsset = derived(store, $store => {
|
||||||
const type = $store.currentFrontEndType
|
const type = $store.currentFrontEndType
|
||||||
if (type === FrontendTypes.SCREEN) {
|
if (type === FrontendTypes.SCREEN) {
|
||||||
return $store.screens.find(
|
return $store.screens.find(screen => screen._id === $store.selectedScreenId)
|
||||||
(screen) => screen._id === $store.selectedScreenId
|
|
||||||
)
|
|
||||||
} else if (type === FrontendTypes.LAYOUT) {
|
} else if (type === FrontendTypes.LAYOUT) {
|
||||||
return $store.layouts.find(
|
return $store.layouts.find(layout => layout._id === $store.selectedLayoutId)
|
||||||
(layout) => layout._id === $store.selectedLayoutId
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
})
|
})
|
||||||
|
@ -36,24 +32,24 @@ export const selectedComponent = derived(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
export const currentAssetId = derived(store, ($store) => {
|
export const currentAssetId = derived(store, $store => {
|
||||||
return $store.currentFrontEndType === FrontendTypes.SCREEN
|
return $store.currentFrontEndType === FrontendTypes.SCREEN
|
||||||
? $store.selectedScreenId
|
? $store.selectedScreenId
|
||||||
: $store.selectedLayoutId
|
: $store.selectedLayoutId
|
||||||
})
|
})
|
||||||
|
|
||||||
export const currentAssetName = derived(currentAsset, ($currentAsset) => {
|
export const currentAssetName = derived(currentAsset, $currentAsset => {
|
||||||
return $currentAsset?.name
|
return $currentAsset?.name
|
||||||
})
|
})
|
||||||
|
|
||||||
// leave this as before for consistency
|
// leave this as before for consistency
|
||||||
export const allScreens = derived(store, ($store) => {
|
export const allScreens = derived(store, $store => {
|
||||||
return $store.screens
|
return $store.screens
|
||||||
})
|
})
|
||||||
|
|
||||||
export const mainLayout = derived(store, ($store) => {
|
export const mainLayout = derived(store, $store => {
|
||||||
return $store.layouts?.find(
|
return $store.layouts?.find(
|
||||||
(layout) => layout._id === LAYOUT_NAMES.MASTER.PRIVATE
|
layout => layout._id === LAYOUT_NAMES.MASTER.PRIVATE
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { get } from "builderStore/api"
|
||||||
* their props and other metadata from components.json.
|
* their props and other metadata from components.json.
|
||||||
* @param {string} appId - ID of the currently running app
|
* @param {string} appId - ID of the currently running app
|
||||||
*/
|
*/
|
||||||
export const fetchComponentLibDefinitions = async (appId) => {
|
export const fetchComponentLibDefinitions = async appId => {
|
||||||
const LIB_DEFINITION_URL = `/api/${appId}/components/definitions`
|
const LIB_DEFINITION_URL = `/api/${appId}/components/definitions`
|
||||||
try {
|
try {
|
||||||
const libDefinitionResponse = await get(LIB_DEFINITION_URL)
|
const libDefinitionResponse = await get(LIB_DEFINITION_URL)
|
||||||
|
|
|
@ -37,7 +37,7 @@ export default class Automation {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const stepIdx = steps.findIndex((step) => step.id === id)
|
const stepIdx = steps.findIndex(step => step.id === id)
|
||||||
if (stepIdx < 0) throw new Error("Block not found.")
|
if (stepIdx < 0) throw new Error("Block not found.")
|
||||||
steps.splice(stepIdx, 1, updatedBlock)
|
steps.splice(stepIdx, 1, updatedBlock)
|
||||||
this.automation.definition.steps = steps
|
this.automation.definition.steps = steps
|
||||||
|
@ -51,7 +51,7 @@ export default class Automation {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const stepIdx = steps.findIndex((step) => step.id === id)
|
const stepIdx = steps.findIndex(step => step.id === id)
|
||||||
if (stepIdx < 0) throw new Error("Block not found.")
|
if (stepIdx < 0) throw new Error("Block not found.")
|
||||||
steps.splice(stepIdx, 1)
|
steps.splice(stepIdx, 1)
|
||||||
this.automation.definition.steps = steps
|
this.automation.definition.steps = steps
|
||||||
|
|
|
@ -4,14 +4,14 @@ import Automation from "./Automation"
|
||||||
import { cloneDeep } from "lodash/fp"
|
import { cloneDeep } from "lodash/fp"
|
||||||
import analytics from "analytics"
|
import analytics from "analytics"
|
||||||
|
|
||||||
const automationActions = (store) => ({
|
const automationActions = store => ({
|
||||||
fetch: async () => {
|
fetch: async () => {
|
||||||
const responses = await Promise.all([
|
const responses = await Promise.all([
|
||||||
api.get(`/api/automations`),
|
api.get(`/api/automations`),
|
||||||
api.get(`/api/automations/definitions/list`),
|
api.get(`/api/automations/definitions/list`),
|
||||||
])
|
])
|
||||||
const jsonResponses = await Promise.all(responses.map((x) => x.json()))
|
const jsonResponses = await Promise.all(responses.map(x => x.json()))
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
let selected = state.selectedAutomation?.automation
|
let selected = state.selectedAutomation?.automation
|
||||||
state.automations = jsonResponses[0]
|
state.automations = jsonResponses[0]
|
||||||
state.blockDefinitions = {
|
state.blockDefinitions = {
|
||||||
|
@ -22,7 +22,7 @@ const automationActions = (store) => ({
|
||||||
// if previously selected find the new obj and select it
|
// if previously selected find the new obj and select it
|
||||||
if (selected) {
|
if (selected) {
|
||||||
selected = jsonResponses[0].filter(
|
selected = jsonResponses[0].filter(
|
||||||
(automation) => automation._id === selected._id
|
automation => automation._id === selected._id
|
||||||
)
|
)
|
||||||
state.selectedAutomation = new Automation(selected[0])
|
state.selectedAutomation = new Automation(selected[0])
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ const automationActions = (store) => ({
|
||||||
const CREATE_AUTOMATION_URL = `/api/automations`
|
const CREATE_AUTOMATION_URL = `/api/automations`
|
||||||
const response = await api.post(CREATE_AUTOMATION_URL, automation)
|
const response = await api.post(CREATE_AUTOMATION_URL, automation)
|
||||||
const json = await response.json()
|
const json = await response.json()
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
state.automations = [...state.automations, json.automation]
|
state.automations = [...state.automations, json.automation]
|
||||||
store.actions.select(json.automation)
|
store.actions.select(json.automation)
|
||||||
return state
|
return state
|
||||||
|
@ -50,9 +50,9 @@ const automationActions = (store) => ({
|
||||||
const UPDATE_AUTOMATION_URL = `/api/automations`
|
const UPDATE_AUTOMATION_URL = `/api/automations`
|
||||||
const response = await api.put(UPDATE_AUTOMATION_URL, automation)
|
const response = await api.put(UPDATE_AUTOMATION_URL, automation)
|
||||||
const json = await response.json()
|
const json = await response.json()
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
const existingIdx = state.automations.findIndex(
|
const existingIdx = state.automations.findIndex(
|
||||||
(existing) => existing._id === automation._id
|
existing => existing._id === automation._id
|
||||||
)
|
)
|
||||||
state.automations.splice(existingIdx, 1, json.automation)
|
state.automations.splice(existingIdx, 1, json.automation)
|
||||||
state.automations = state.automations
|
state.automations = state.automations
|
||||||
|
@ -65,9 +65,9 @@ const automationActions = (store) => ({
|
||||||
const DELETE_AUTOMATION_URL = `/api/automations/${_id}/${_rev}`
|
const DELETE_AUTOMATION_URL = `/api/automations/${_id}/${_rev}`
|
||||||
await api.delete(DELETE_AUTOMATION_URL)
|
await api.delete(DELETE_AUTOMATION_URL)
|
||||||
|
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
const existingIdx = state.automations.findIndex(
|
const existingIdx = state.automations.findIndex(
|
||||||
(existing) => existing._id === _id
|
existing => existing._id === _id
|
||||||
)
|
)
|
||||||
state.automations.splice(existingIdx, 1)
|
state.automations.splice(existingIdx, 1)
|
||||||
state.automations = state.automations
|
state.automations = state.automations
|
||||||
|
@ -81,15 +81,15 @@ const automationActions = (store) => ({
|
||||||
const TRIGGER_AUTOMATION_URL = `/api/automations/${_id}/trigger`
|
const TRIGGER_AUTOMATION_URL = `/api/automations/${_id}/trigger`
|
||||||
return await api.post(TRIGGER_AUTOMATION_URL)
|
return await api.post(TRIGGER_AUTOMATION_URL)
|
||||||
},
|
},
|
||||||
select: (automation) => {
|
select: automation => {
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
state.selectedAutomation = new Automation(cloneDeep(automation))
|
state.selectedAutomation = new Automation(cloneDeep(automation))
|
||||||
state.selectedBlock = null
|
state.selectedBlock = null
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
addBlockToAutomation: (block) => {
|
addBlockToAutomation: block => {
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
const newBlock = state.selectedAutomation.addBlock(cloneDeep(block))
|
const newBlock = state.selectedAutomation.addBlock(cloneDeep(block))
|
||||||
state.selectedBlock = newBlock
|
state.selectedBlock = newBlock
|
||||||
return state
|
return state
|
||||||
|
@ -98,10 +98,10 @@ const automationActions = (store) => ({
|
||||||
name: block.name,
|
name: block.name,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
deleteAutomationBlock: (block) => {
|
deleteAutomationBlock: block => {
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
const idx = state.selectedAutomation.automation.definition.steps.findIndex(
|
const idx = state.selectedAutomation.automation.definition.steps.findIndex(
|
||||||
(x) => x.id === block.id
|
x => x.id === block.id
|
||||||
)
|
)
|
||||||
state.selectedAutomation.deleteBlock(block.id)
|
state.selectedAutomation.deleteBlock(block.id)
|
||||||
|
|
||||||
|
|
|
@ -49,10 +49,10 @@ export const getFrontendStore = () => {
|
||||||
const store = writable({ ...INITIAL_FRONTEND_STATE })
|
const store = writable({ ...INITIAL_FRONTEND_STATE })
|
||||||
|
|
||||||
store.actions = {
|
store.actions = {
|
||||||
initialise: async (pkg) => {
|
initialise: async pkg => {
|
||||||
const { layouts, screens, application, clientLibPath } = pkg
|
const { layouts, screens, application, clientLibPath } = pkg
|
||||||
const components = await fetchComponentLibDefinitions(application._id)
|
const components = await fetchComponentLibDefinitions(application._id)
|
||||||
store.update((state) => ({
|
store.update(state => ({
|
||||||
...state,
|
...state,
|
||||||
libraries: application.componentLibraries,
|
libraries: application.componentLibraries,
|
||||||
components,
|
components,
|
||||||
|
@ -70,7 +70,7 @@ export const getFrontendStore = () => {
|
||||||
|
|
||||||
// Initialise backend stores
|
// Initialise backend stores
|
||||||
const [_integrations] = await Promise.all([
|
const [_integrations] = await Promise.all([
|
||||||
api.get("/api/integrations").then((r) => r.json()),
|
api.get("/api/integrations").then(r => r.json()),
|
||||||
])
|
])
|
||||||
datasources.init()
|
datasources.init()
|
||||||
integrations.set(_integrations)
|
integrations.set(_integrations)
|
||||||
|
@ -82,18 +82,18 @@ export const getFrontendStore = () => {
|
||||||
fetch: async () => {
|
fetch: async () => {
|
||||||
const response = await api.get("/api/routing")
|
const response = await api.get("/api/routing")
|
||||||
const json = await response.json()
|
const json = await response.json()
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
state.routes = json.routes
|
state.routes = json.routes
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
screens: {
|
screens: {
|
||||||
select: (screenId) => {
|
select: screenId => {
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
let screens = get(allScreens)
|
let screens = get(allScreens)
|
||||||
let screen =
|
let screen =
|
||||||
screens.find((screen) => screen._id === screenId) || screens[0]
|
screens.find(screen => screen._id === screenId) || screens[0]
|
||||||
if (!screen) return state
|
if (!screen) return state
|
||||||
|
|
||||||
// Update role to the screen's role setting so that it will always
|
// Update role to the screen's role setting so that it will always
|
||||||
|
@ -107,9 +107,9 @@ export const getFrontendStore = () => {
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
create: async (screen) => {
|
create: async screen => {
|
||||||
screen = await store.actions.screens.save(screen)
|
screen = await store.actions.screens.save(screen)
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
state.selectedScreenId = screen._id
|
state.selectedScreenId = screen._id
|
||||||
state.selectedComponentId = screen.props._id
|
state.selectedComponentId = screen.props._id
|
||||||
state.currentFrontEndType = FrontendTypes.SCREEN
|
state.currentFrontEndType = FrontendTypes.SCREEN
|
||||||
|
@ -118,15 +118,15 @@ export const getFrontendStore = () => {
|
||||||
})
|
})
|
||||||
return screen
|
return screen
|
||||||
},
|
},
|
||||||
save: async (screen) => {
|
save: async screen => {
|
||||||
const creatingNewScreen = screen._id === undefined
|
const creatingNewScreen = screen._id === undefined
|
||||||
const response = await api.post(`/api/screens`, screen)
|
const response = await api.post(`/api/screens`, screen)
|
||||||
screen = await response.json()
|
screen = await response.json()
|
||||||
await store.actions.routing.fetch()
|
await store.actions.routing.fetch()
|
||||||
|
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
const foundScreen = state.screens.findIndex(
|
const foundScreen = state.screens.findIndex(
|
||||||
(el) => el._id === screen._id
|
el => el._id === screen._id
|
||||||
)
|
)
|
||||||
if (foundScreen !== -1) {
|
if (foundScreen !== -1) {
|
||||||
state.screens.splice(foundScreen, 1)
|
state.screens.splice(foundScreen, 1)
|
||||||
|
@ -141,14 +141,14 @@ export const getFrontendStore = () => {
|
||||||
|
|
||||||
return screen
|
return screen
|
||||||
},
|
},
|
||||||
delete: async (screens) => {
|
delete: async screens => {
|
||||||
const screensToDelete = Array.isArray(screens) ? screens : [screens]
|
const screensToDelete = Array.isArray(screens) ? screens : [screens]
|
||||||
|
|
||||||
const screenDeletePromises = []
|
const screenDeletePromises = []
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
for (let screenToDelete of screensToDelete) {
|
for (let screenToDelete of screensToDelete) {
|
||||||
state.screens = state.screens.filter(
|
state.screens = state.screens.filter(
|
||||||
(screen) => screen._id !== screenToDelete._id
|
screen => screen._id !== screenToDelete._id
|
||||||
)
|
)
|
||||||
screenDeletePromises.push(
|
screenDeletePromises.push(
|
||||||
api.delete(
|
api.delete(
|
||||||
|
@ -177,8 +177,8 @@ export const getFrontendStore = () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
layouts: {
|
layouts: {
|
||||||
select: (layoutId) => {
|
select: layoutId => {
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
const layout =
|
const layout =
|
||||||
store.actions.layouts.find(layoutId) || get(store).layouts[0]
|
store.actions.layouts.find(layoutId) || get(store).layouts[0]
|
||||||
if (!layout) return
|
if (!layout) return
|
||||||
|
@ -189,15 +189,15 @@ export const getFrontendStore = () => {
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
save: async (layout) => {
|
save: async layout => {
|
||||||
const layoutToSave = cloneDeep(layout)
|
const layoutToSave = cloneDeep(layout)
|
||||||
const creatingNewLayout = layoutToSave._id === undefined
|
const creatingNewLayout = layoutToSave._id === undefined
|
||||||
const response = await api.post(`/api/layouts`, layoutToSave)
|
const response = await api.post(`/api/layouts`, layoutToSave)
|
||||||
const savedLayout = await response.json()
|
const savedLayout = await response.json()
|
||||||
|
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
const layoutIdx = state.layouts.findIndex(
|
const layoutIdx = state.layouts.findIndex(
|
||||||
(stateLayout) => stateLayout._id === savedLayout._id
|
stateLayout => stateLayout._id === savedLayout._id
|
||||||
)
|
)
|
||||||
if (layoutIdx >= 0) {
|
if (layoutIdx >= 0) {
|
||||||
// update existing layout
|
// update existing layout
|
||||||
|
@ -216,14 +216,14 @@ export const getFrontendStore = () => {
|
||||||
|
|
||||||
return savedLayout
|
return savedLayout
|
||||||
},
|
},
|
||||||
find: (layoutId) => {
|
find: layoutId => {
|
||||||
if (!layoutId) {
|
if (!layoutId) {
|
||||||
return get(mainLayout)
|
return get(mainLayout)
|
||||||
}
|
}
|
||||||
const storeContents = get(store)
|
const storeContents = get(store)
|
||||||
return storeContents.layouts.find((layout) => layout._id === layoutId)
|
return storeContents.layouts.find(layout => layout._id === layoutId)
|
||||||
},
|
},
|
||||||
delete: async (layoutToDelete) => {
|
delete: async layoutToDelete => {
|
||||||
const response = await api.delete(
|
const response = await api.delete(
|
||||||
`/api/layouts/${layoutToDelete._id}/${layoutToDelete._rev}`
|
`/api/layouts/${layoutToDelete._id}/${layoutToDelete._rev}`
|
||||||
)
|
)
|
||||||
|
@ -231,9 +231,9 @@ export const getFrontendStore = () => {
|
||||||
const json = await response.json()
|
const json = await response.json()
|
||||||
throw new Error(json.message)
|
throw new Error(json.message)
|
||||||
}
|
}
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
state.layouts = state.layouts.filter(
|
state.layouts = state.layouts.filter(
|
||||||
(layout) => layout._id !== layoutToDelete._id
|
layout => layout._id !== layoutToDelete._id
|
||||||
)
|
)
|
||||||
if (layoutToDelete._id === state.selectedLayoutId) {
|
if (layoutToDelete._id === state.selectedLayoutId) {
|
||||||
state.selectedLayoutId = get(mainLayout)._id
|
state.selectedLayoutId = get(mainLayout)._id
|
||||||
|
@ -243,7 +243,7 @@ export const getFrontendStore = () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
select: (component) => {
|
select: component => {
|
||||||
if (!component) {
|
if (!component) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -263,13 +263,13 @@ export const getFrontendStore = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise select the component
|
// Otherwise select the component
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
state.selectedComponentId = component._id
|
state.selectedComponentId = component._id
|
||||||
state.currentView = "component"
|
state.currentView = "component"
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
getDefinition: (componentName) => {
|
getDefinition: componentName => {
|
||||||
if (!componentName) {
|
if (!componentName) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -287,7 +287,7 @@ export const getFrontendStore = () => {
|
||||||
// Generate default props
|
// Generate default props
|
||||||
let props = { ...presetProps }
|
let props = { ...presetProps }
|
||||||
if (definition.settings) {
|
if (definition.settings) {
|
||||||
definition.settings.forEach((setting) => {
|
definition.settings.forEach(setting => {
|
||||||
if (setting.defaultValue !== undefined) {
|
if (setting.defaultValue !== undefined) {
|
||||||
props[setting.key] = setting.defaultValue
|
props[setting.key] = setting.defaultValue
|
||||||
}
|
}
|
||||||
|
@ -367,7 +367,7 @@ export const getFrontendStore = () => {
|
||||||
|
|
||||||
// Save components and update UI
|
// Save components and update UI
|
||||||
await store.actions.preview.saveSelected()
|
await store.actions.preview.saveSelected()
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
state.currentView = "component"
|
state.currentView = "component"
|
||||||
state.selectedComponentId = componentInstance._id
|
state.selectedComponentId = componentInstance._id
|
||||||
return state
|
return state
|
||||||
|
@ -380,7 +380,7 @@ export const getFrontendStore = () => {
|
||||||
|
|
||||||
return componentInstance
|
return componentInstance
|
||||||
},
|
},
|
||||||
delete: async (component) => {
|
delete: async component => {
|
||||||
if (!component) {
|
if (!component) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -391,7 +391,7 @@ export const getFrontendStore = () => {
|
||||||
const parent = findComponentParent(asset.props, component._id)
|
const parent = findComponentParent(asset.props, component._id)
|
||||||
if (parent) {
|
if (parent) {
|
||||||
parent._children = parent._children.filter(
|
parent._children = parent._children.filter(
|
||||||
(child) => child._id !== component._id
|
child => child._id !== component._id
|
||||||
)
|
)
|
||||||
store.actions.components.select(parent)
|
store.actions.components.select(parent)
|
||||||
}
|
}
|
||||||
|
@ -404,7 +404,7 @@ export const getFrontendStore = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update store with copied component
|
// Update store with copied component
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
state.componentToPaste = cloneDeep(component)
|
state.componentToPaste = cloneDeep(component)
|
||||||
state.componentToPaste.isCut = cut
|
state.componentToPaste.isCut = cut
|
||||||
return state
|
return state
|
||||||
|
@ -415,7 +415,7 @@ export const getFrontendStore = () => {
|
||||||
const parent = findComponentParent(selectedAsset.props, component._id)
|
const parent = findComponentParent(selectedAsset.props, component._id)
|
||||||
if (parent) {
|
if (parent) {
|
||||||
parent._children = parent._children.filter(
|
parent._children = parent._children.filter(
|
||||||
(child) => child._id !== component._id
|
child => child._id !== component._id
|
||||||
)
|
)
|
||||||
store.actions.components.select(parent)
|
store.actions.components.select(parent)
|
||||||
}
|
}
|
||||||
|
@ -423,7 +423,7 @@ export const getFrontendStore = () => {
|
||||||
},
|
},
|
||||||
paste: async (targetComponent, mode) => {
|
paste: async (targetComponent, mode) => {
|
||||||
let promises = []
|
let promises = []
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
// Stop if we have nothing to paste
|
// Stop if we have nothing to paste
|
||||||
if (!state.componentToPaste) {
|
if (!state.componentToPaste) {
|
||||||
return state
|
return state
|
||||||
|
@ -444,7 +444,7 @@ export const getFrontendStore = () => {
|
||||||
if (cut) {
|
if (cut) {
|
||||||
state.componentToPaste = null
|
state.componentToPaste = null
|
||||||
} else {
|
} else {
|
||||||
const randomizeIds = (component) => {
|
const randomizeIds = component => {
|
||||||
if (!component) {
|
if (!component) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -497,7 +497,7 @@ export const getFrontendStore = () => {
|
||||||
}
|
}
|
||||||
await store.actions.preview.saveSelected()
|
await store.actions.preview.saveSelected()
|
||||||
},
|
},
|
||||||
updateCustomStyle: async (style) => {
|
updateCustomStyle: async style => {
|
||||||
const selected = get(selectedComponent)
|
const selected = get(selectedComponent)
|
||||||
selected._styles.custom = style
|
selected._styles.custom = style
|
||||||
await store.actions.preview.saveSelected()
|
await store.actions.preview.saveSelected()
|
||||||
|
@ -507,7 +507,7 @@ export const getFrontendStore = () => {
|
||||||
selected._styles = { normal: {}, hover: {}, active: {} }
|
selected._styles = { normal: {}, hover: {}, active: {} }
|
||||||
await store.actions.preview.saveSelected()
|
await store.actions.preview.saveSelected()
|
||||||
},
|
},
|
||||||
updateTransition: async (transition) => {
|
updateTransition: async transition => {
|
||||||
const selected = get(selectedComponent)
|
const selected = get(selectedComponent)
|
||||||
if (transition == null || transition === "") {
|
if (transition == null || transition === "") {
|
||||||
selected._transition = ""
|
selected._transition = ""
|
||||||
|
@ -522,7 +522,7 @@ export const getFrontendStore = () => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
component[name] = value
|
component[name] = value
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
state.selectedComponentId = component._id
|
state.selectedComponentId = component._id
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
|
|
|
@ -17,20 +17,18 @@ export const getHostingStore = () => {
|
||||||
api.get("/api/hosting/"),
|
api.get("/api/hosting/"),
|
||||||
api.get("/api/hosting/urls"),
|
api.get("/api/hosting/urls"),
|
||||||
])
|
])
|
||||||
const [info, urls] = await Promise.all(
|
const [info, urls] = await Promise.all(responses.map(resp => resp.json()))
|
||||||
responses.map((resp) => resp.json())
|
store.update(state => {
|
||||||
)
|
|
||||||
store.update((state) => {
|
|
||||||
state.hostingInfo = info
|
state.hostingInfo = info
|
||||||
state.appUrl = urls.app
|
state.appUrl = urls.app
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
return info
|
return info
|
||||||
},
|
},
|
||||||
save: async (hostingInfo) => {
|
save: async hostingInfo => {
|
||||||
const response = await api.post("/api/hosting", hostingInfo)
|
const response = await api.post("/api/hosting", hostingInfo)
|
||||||
const revision = (await response.json()).rev
|
const revision = (await response.json()).rev
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
state.hostingInfo = {
|
state.hostingInfo = {
|
||||||
...hostingInfo,
|
...hostingInfo,
|
||||||
_rev: revision,
|
_rev: revision,
|
||||||
|
@ -40,12 +38,10 @@ export const getHostingStore = () => {
|
||||||
},
|
},
|
||||||
fetchDeployedApps: async () => {
|
fetchDeployedApps: async () => {
|
||||||
let deployments = await (await get("/api/hosting/apps")).json()
|
let deployments = await (await get("/api/hosting/apps")).json()
|
||||||
store.update((state) => {
|
store.update(state => {
|
||||||
state.deployedApps = deployments
|
state.deployedApps = deployments
|
||||||
state.deployedAppNames = Object.values(deployments).map(
|
state.deployedAppNames = Object.values(deployments).map(app => app.name)
|
||||||
(app) => app.name
|
state.deployedAppUrls = Object.values(deployments).map(app => app.url)
|
||||||
)
|
|
||||||
state.deployedAppUrls = Object.values(deployments).map((app) => app.url)
|
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
return deployments
|
return deployments
|
||||||
|
|
|
@ -12,13 +12,13 @@ export const localStorageStore = (localStorageKey, initialValue) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
// New store setter which updates the store and localstorage
|
// New store setter which updates the store and localstorage
|
||||||
const set = (value) => {
|
const set = value => {
|
||||||
store.set(value)
|
store.set(value)
|
||||||
localStorage.setItem(localStorageKey, JSON.stringify(value))
|
localStorage.setItem(localStorageKey, JSON.stringify(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
// New store updater which updates the store and localstorage
|
// New store updater which updates the store and localstorage
|
||||||
const update = (updaterFn) => set(updaterFn(get(store)))
|
const update = updaterFn => set(updaterFn(get(store)))
|
||||||
|
|
||||||
// Hydrates the store from localstorage
|
// Hydrates the store from localstorage
|
||||||
const hydrate = () => {
|
const hydrate = () => {
|
||||||
|
|
|
@ -6,7 +6,7 @@ export const notificationStore = writable({
|
||||||
})
|
})
|
||||||
|
|
||||||
export function send(message, type = "default") {
|
export function send(message, type = "default") {
|
||||||
notificationStore.update((state) => {
|
notificationStore.update(state => {
|
||||||
state.notifications = [
|
state.notifications = [
|
||||||
...state.notifications,
|
...state.notifications,
|
||||||
{ id: generate(), type, message },
|
{ id: generate(), type, message },
|
||||||
|
@ -16,8 +16,8 @@ export function send(message, type = "default") {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const notifier = {
|
export const notifier = {
|
||||||
danger: (msg) => send(msg, "danger"),
|
danger: msg => send(msg, "danger"),
|
||||||
warning: (msg) => send(msg, "warning"),
|
warning: msg => send(msg, "warning"),
|
||||||
info: (msg) => send(msg, "info"),
|
info: msg => send(msg, "info"),
|
||||||
success: (msg) => send(msg, "success"),
|
success: msg => send(msg, "success"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import rowDetailScreen from "./rowDetailScreen"
|
||||||
import rowListScreen from "./rowListScreen"
|
import rowListScreen from "./rowListScreen"
|
||||||
import createFromScratchScreen from "./createFromScratchScreen"
|
import createFromScratchScreen from "./createFromScratchScreen"
|
||||||
|
|
||||||
const allTemplates = (tables) => [
|
const allTemplates = tables => [
|
||||||
...newRowScreen(tables),
|
...newRowScreen(tables),
|
||||||
...rowDetailScreen(tables),
|
...rowDetailScreen(tables),
|
||||||
...rowListScreen(tables),
|
...rowListScreen(tables),
|
||||||
|
@ -18,7 +18,7 @@ const createTemplateOverride = (frontendState, create) => () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (frontendState, tables) => {
|
export default (frontendState, tables) => {
|
||||||
const enrichTemplate = (template) => ({
|
const enrichTemplate = template => ({
|
||||||
...template,
|
...template,
|
||||||
create: createTemplateOverride(frontendState, template.create),
|
create: createTemplateOverride(frontendState, template.create),
|
||||||
})
|
})
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
} from "./utils/commonComponents"
|
} from "./utils/commonComponents"
|
||||||
|
|
||||||
export default function (tables) {
|
export default function (tables) {
|
||||||
return tables.map((table) => {
|
return tables.map(table => {
|
||||||
return {
|
return {
|
||||||
name: `${table.name} - New`,
|
name: `${table.name} - New`,
|
||||||
create: () => createScreen(table),
|
create: () => createScreen(table),
|
||||||
|
@ -19,14 +19,14 @@ export default function (tables) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const newRowUrl = (table) => sanitizeUrl(`/${table.name}/new/row`)
|
export const newRowUrl = table => sanitizeUrl(`/${table.name}/new/row`)
|
||||||
export const NEW_ROW_TEMPLATE = "NEW_ROW_TEMPLATE"
|
export const NEW_ROW_TEMPLATE = "NEW_ROW_TEMPLATE"
|
||||||
|
|
||||||
function generateTitleContainer(table, formId) {
|
function generateTitleContainer(table, formId) {
|
||||||
return makeTitleContainer("New Row").addChild(makeSaveButton(table, formId))
|
return makeTitleContainer("New Row").addChild(makeSaveButton(table, formId))
|
||||||
}
|
}
|
||||||
|
|
||||||
const createScreen = (table) => {
|
const createScreen = table => {
|
||||||
const screen = new Screen()
|
const screen = new Screen()
|
||||||
.component("@budibase/standard-components/container")
|
.component("@budibase/standard-components/container")
|
||||||
.instanceName(`${table.name} - New`)
|
.instanceName(`${table.name} - New`)
|
||||||
|
@ -52,7 +52,7 @@ const createScreen = (table) => {
|
||||||
|
|
||||||
// Add all form fields from this schema to the field group
|
// Add all form fields from this schema to the field group
|
||||||
const datasource = { type: "table", tableId: table._id }
|
const datasource = { type: "table", tableId: table._id }
|
||||||
makeDatasourceFormComponents(datasource).forEach((component) => {
|
makeDatasourceFormComponents(datasource).forEach(component => {
|
||||||
fieldGroup.addChild(component)
|
fieldGroup.addChild(component)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {
|
||||||
} from "./utils/commonComponents"
|
} from "./utils/commonComponents"
|
||||||
|
|
||||||
export default function (tables) {
|
export default function (tables) {
|
||||||
return tables.map((table) => {
|
return tables.map(table => {
|
||||||
return {
|
return {
|
||||||
name: `${table.name} - Detail`,
|
name: `${table.name} - Detail`,
|
||||||
create: () => createScreen(table),
|
create: () => createScreen(table),
|
||||||
|
@ -23,7 +23,7 @@ export default function (tables) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ROW_DETAIL_TEMPLATE = "ROW_DETAIL_TEMPLATE"
|
export const ROW_DETAIL_TEMPLATE = "ROW_DETAIL_TEMPLATE"
|
||||||
export const rowDetailUrl = (table) => sanitizeUrl(`/${table.name}/:id`)
|
export const rowDetailUrl = table => sanitizeUrl(`/${table.name}/:id`)
|
||||||
|
|
||||||
function generateTitleContainer(table, title, formId, repeaterId) {
|
function generateTitleContainer(table, title, formId, repeaterId) {
|
||||||
// have to override style for this, its missing margin
|
// have to override style for this, its missing margin
|
||||||
|
@ -80,7 +80,7 @@ function generateTitleContainer(table, title, formId, repeaterId) {
|
||||||
return makeTitleContainer(title).addChild(deleteButton).addChild(saveButton)
|
return makeTitleContainer(title).addChild(deleteButton).addChild(saveButton)
|
||||||
}
|
}
|
||||||
|
|
||||||
const createScreen = (table) => {
|
const createScreen = table => {
|
||||||
const provider = new Component("@budibase/standard-components/dataprovider")
|
const provider = new Component("@budibase/standard-components/dataprovider")
|
||||||
.instanceName(`Data Provider`)
|
.instanceName(`Data Provider`)
|
||||||
.customProps({
|
.customProps({
|
||||||
|
@ -122,7 +122,7 @@ const createScreen = (table) => {
|
||||||
|
|
||||||
// Add all form fields from this schema to the field group
|
// Add all form fields from this schema to the field group
|
||||||
const datasource = { type: "table", tableId: table._id }
|
const datasource = { type: "table", tableId: table._id }
|
||||||
makeDatasourceFormComponents(datasource).forEach((component) => {
|
makeDatasourceFormComponents(datasource).forEach(component => {
|
||||||
fieldGroup.addChild(component)
|
fieldGroup.addChild(component)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { Component } from "./utils/Component"
|
||||||
import { makePropSafe } from "@budibase/string-templates"
|
import { makePropSafe } from "@budibase/string-templates"
|
||||||
|
|
||||||
export default function (tables) {
|
export default function (tables) {
|
||||||
return tables.map((table) => {
|
return tables.map(table => {
|
||||||
return {
|
return {
|
||||||
name: `${table.name} - List`,
|
name: `${table.name} - List`,
|
||||||
create: () => createScreen(table),
|
create: () => createScreen(table),
|
||||||
|
@ -15,7 +15,7 @@ export default function (tables) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ROW_LIST_TEMPLATE = "ROW_LIST_TEMPLATE"
|
export const ROW_LIST_TEMPLATE = "ROW_LIST_TEMPLATE"
|
||||||
export const rowListUrl = (table) => sanitizeUrl(`/${table.name}`)
|
export const rowListUrl = table => sanitizeUrl(`/${table.name}`)
|
||||||
|
|
||||||
function generateTitleContainer(table) {
|
function generateTitleContainer(table) {
|
||||||
const newButton = new Component("@budibase/standard-components/button")
|
const newButton = new Component("@budibase/standard-components/button")
|
||||||
|
@ -70,7 +70,7 @@ function generateTitleContainer(table) {
|
||||||
.addChild(newButton)
|
.addChild(newButton)
|
||||||
}
|
}
|
||||||
|
|
||||||
const createScreen = (table) => {
|
const createScreen = table => {
|
||||||
const provider = new Component("@budibase/standard-components/dataprovider")
|
const provider = new Component("@budibase/standard-components/dataprovider")
|
||||||
.instanceName(`Data Provider`)
|
.instanceName(`Data Provider`)
|
||||||
.customProps({
|
.customProps({
|
||||||
|
|
|
@ -178,7 +178,7 @@ export function makeDatasourceFormComponents(datasource) {
|
||||||
const { schema } = getSchemaForDatasource(datasource, true)
|
const { schema } = getSchemaForDatasource(datasource, true)
|
||||||
let components = []
|
let components = []
|
||||||
let fields = Object.keys(schema || {})
|
let fields = Object.keys(schema || {})
|
||||||
fields.forEach((field) => {
|
fields.forEach(field => {
|
||||||
const fieldSchema = schema[field]
|
const fieldSchema = schema[field]
|
||||||
// skip autocolumns
|
// skip autocolumns
|
||||||
if (fieldSchema.autocolumn) {
|
if (fieldSchema.autocolumn) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
export default function (url) {
|
export default function (url) {
|
||||||
return url
|
return url
|
||||||
.split("/")
|
.split("/")
|
||||||
.map((part) => {
|
.map(part => {
|
||||||
// if parameter, then use as is
|
// if parameter, then use as is
|
||||||
if (part.startsWith(":")) return part
|
if (part.startsWith(":")) return part
|
||||||
return encodeURIComponent(part.replace(/ /g, "-"))
|
return encodeURIComponent(part.replace(/ /g, "-"))
|
||||||
|
|
|
@ -9,14 +9,14 @@ export const getThemeStore = () => {
|
||||||
const store = localStorageStore("bb-theme", initialValue)
|
const store = localStorageStore("bb-theme", initialValue)
|
||||||
|
|
||||||
// Update theme class when store changes
|
// Update theme class when store changes
|
||||||
store.subscribe((state) => {
|
store.subscribe(state => {
|
||||||
// Handle any old local storage values - this can be removed after the update
|
// Handle any old local storage values - this can be removed after the update
|
||||||
if (state.darkMode !== undefined) {
|
if (state.darkMode !== undefined) {
|
||||||
store.set(initialValue)
|
store.set(initialValue)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
state.options.forEach((option) => {
|
state.options.forEach(option => {
|
||||||
themeElement.classList.toggle(
|
themeElement.classList.toggle(
|
||||||
`spectrum--${option}`,
|
`spectrum--${option}`,
|
||||||
option === state.theme
|
option === state.theme
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
* Recursively searches for a specific component ID
|
* Recursively searches for a specific component ID
|
||||||
*/
|
*/
|
||||||
export const findComponent = (rootComponent, id) => {
|
export const findComponent = (rootComponent, id) => {
|
||||||
return searchComponentTree(rootComponent, (comp) => comp._id === id)
|
return searchComponentTree(rootComponent, comp => comp._id === id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively searches for a specific component type
|
* Recursively searches for a specific component type
|
||||||
*/
|
*/
|
||||||
export const findComponentType = (rootComponent, type) => {
|
export const findComponentType = (rootComponent, type) => {
|
||||||
return searchComponentTree(rootComponent, (comp) => comp._component === type)
|
return searchComponentTree(rootComponent, comp => comp._component === type)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,7 +68,7 @@ export const findAllMatchingComponents = (rootComponent, selector) => {
|
||||||
}
|
}
|
||||||
let components = []
|
let components = []
|
||||||
if (rootComponent._children) {
|
if (rootComponent._children) {
|
||||||
rootComponent._children.forEach((child) => {
|
rootComponent._children.forEach(child => {
|
||||||
components = [
|
components = [
|
||||||
...components,
|
...components,
|
||||||
...findAllMatchingComponents(child, selector),
|
...findAllMatchingComponents(child, selector),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
export function uuid() {
|
export function uuid() {
|
||||||
// always want to make this start with a letter, as this makes it
|
// always want to make this start with a letter, as this makes it
|
||||||
// easier to use with template string bindings in the client
|
// easier to use with template string bindings in the client
|
||||||
return "cxxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
return "cxxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx".replace(/[xy]/g, c => {
|
||||||
const r = (Math.random() * 16) | 0,
|
const r = (Math.random() * 16) | 0,
|
||||||
v = c == "x" ? r : (r & 0x3) | 0x8
|
v = c == "x" ? r : (r & 0x3) | 0x8
|
||||||
return v.toString(16)
|
return v.toString(16)
|
||||||
|
|
|
@ -69,7 +69,8 @@
|
||||||
size="S"
|
size="S"
|
||||||
icon={tab.icon}
|
icon={tab.icon}
|
||||||
disabled={tab.disabled}
|
disabled={tab.disabled}
|
||||||
on:click={tab.disabled ? null : () => onChangeTab(idx)}>
|
on:click={tab.disabled ? null : () => onChangeTab(idx)}
|
||||||
|
>
|
||||||
{tab.label}
|
{tab.label}
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
</div>
|
</div>
|
||||||
|
@ -79,14 +80,16 @@
|
||||||
on:close={() => (selectedIndex = null)}
|
on:close={() => (selectedIndex = null)}
|
||||||
bind:this={popover}
|
bind:this={popover}
|
||||||
{anchor}
|
{anchor}
|
||||||
align="left">
|
align="left"
|
||||||
|
>
|
||||||
<DropdownContainer>
|
<DropdownContainer>
|
||||||
{#each blocks as [stepId, blockDefinition]}
|
{#each blocks as [stepId, blockDefinition]}
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
icon={blockDefinition.icon}
|
icon={blockDefinition.icon}
|
||||||
title={blockDefinition.name}
|
title={blockDefinition.name}
|
||||||
subtitle={blockDefinition.description}
|
subtitle={blockDefinition.description}
|
||||||
on:click={() => addBlockToAutomation(stepId, blockDefinition)} />
|
on:click={() => addBlockToAutomation(stepId, blockDefinition)}
|
||||||
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
</DropdownContainer>
|
</DropdownContainer>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|
|
@ -3,10 +3,12 @@
|
||||||
height="75"
|
height="75"
|
||||||
viewBox="0 0 9 75"
|
viewBox="0 0 9 75"
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
<path
|
<path
|
||||||
d="M5.0625 70H9L4.5 75L0 70H3.9375V65H5.0625V70Z"
|
d="M5.0625 70H9L4.5 75L0 70H3.9375V65H5.0625V70Z"
|
||||||
fill="var(--grey-5)" />
|
fill="var(--grey-5)"
|
||||||
|
/>
|
||||||
<rect x="4" width="1" height="65" fill="var(--grey-5)" />
|
<rect x="4" width="1" height="65" fill="var(--grey-5)" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 323 B After Width: | Height: | Size: 326 B |
|
@ -26,7 +26,8 @@
|
||||||
class="block"
|
class="block"
|
||||||
animate:flip={{ duration: 600 }}
|
animate:flip={{ duration: 600 }}
|
||||||
in:fade|local
|
in:fade|local
|
||||||
out:fly|local={{ x: 100 }}>
|
out:fly|local={{ x: 100 }}
|
||||||
|
>
|
||||||
<FlowItem {onSelect} {block} />
|
<FlowItem {onSelect} {block} />
|
||||||
{#if idx !== blocks.length - 1}
|
{#if idx !== blocks.length - 1}
|
||||||
<Arrow />
|
<Arrow />
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
$: allowDeleteTrigger = !steps.length
|
$: allowDeleteTrigger = !steps.length
|
||||||
|
|
||||||
function deleteStep() {
|
function deleteStep() {
|
||||||
console.log('Running')
|
console.log("Running")
|
||||||
automationStore.actions.deleteAutomationBlock(block)
|
automationStore.actions.deleteAutomationBlock(block)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -22,23 +22,24 @@
|
||||||
<div
|
<div
|
||||||
class={`block ${block.type} hoverable`}
|
class={`block ${block.type} hoverable`}
|
||||||
class:selected
|
class:selected
|
||||||
on:click={() => onSelect(block)}>
|
on:click={() => onSelect(block)}
|
||||||
|
>
|
||||||
<header>
|
<header>
|
||||||
{#if block.type === 'TRIGGER'}
|
{#if block.type === "TRIGGER"}
|
||||||
<Icon name="Light" />
|
<Icon name="Light" />
|
||||||
<span>When this happens...</span>
|
<span>When this happens...</span>
|
||||||
{:else if block.type === 'ACTION'}
|
{:else if block.type === "ACTION"}
|
||||||
<Icon name="FlashOn" />
|
<Icon name="FlashOn" />
|
||||||
<span>Do this...</span>
|
<span>Do this...</span>
|
||||||
{:else if block.type === 'LOGIC'}
|
{:else if block.type === "LOGIC"}
|
||||||
<Icon name="Branch2" />
|
<Icon name="Branch2" />
|
||||||
<span>Only continue if...</span>
|
<span>Only continue if...</span>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="label">
|
<div class="label">
|
||||||
{#if block.type === 'TRIGGER'}Trigger{:else}Step {blockIdx + 1}{/if}
|
{#if block.type === "TRIGGER"}Trigger{:else}Step {blockIdx + 1}{/if}
|
||||||
</div>
|
</div>
|
||||||
{#if block.type !== 'TRIGGER' || allowDeleteTrigger}
|
{#if block.type !== "TRIGGER" || allowDeleteTrigger}
|
||||||
<div on:click|stopPropagation={deleteStep}><Icon name="Close"/></div>
|
<div on:click|stopPropagation={deleteStep}><Icon name="Close" /></div>
|
||||||
{/if}
|
{/if}
|
||||||
</header>
|
</header>
|
||||||
<hr />
|
<hr />
|
||||||
|
|
|
@ -27,12 +27,14 @@
|
||||||
confirmText="Create"
|
confirmText="Create"
|
||||||
size="L"
|
size="L"
|
||||||
onConfirm={createAutomation}
|
onConfirm={createAutomation}
|
||||||
disabled={!valid}>
|
disabled={!valid}
|
||||||
|
>
|
||||||
<Input bind:value={name} label="Name" />
|
<Input bind:value={name} label="Name" />
|
||||||
<a
|
<a
|
||||||
slot="footer"
|
slot="footer"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
href="https://docs.budibase.com/automate/introduction-to-automate">
|
href="https://docs.budibase.com/automate/introduction-to-automate"
|
||||||
|
>
|
||||||
<Icon name="InfoOutline" />
|
<Icon name="InfoOutline" />
|
||||||
<span>Learn about automations</span>
|
<span>Learn about automations</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
<div class="section">
|
<div class="section">
|
||||||
{#each categories as [categoryName, bindings]}
|
{#each categories as [categoryName, bindings]}
|
||||||
<Heading size="XS">{categoryName}</Heading>
|
<Heading size="XS">{categoryName}</Heading>
|
||||||
{#each bindableProperties.filter((binding) =>
|
{#each bindableProperties.filter(binding =>
|
||||||
binding.label.match(searchRgx)
|
binding.label.match(searchRgx)
|
||||||
) as binding}
|
) as binding}
|
||||||
<div class="binding" on:click={() => addToText(binding)}>
|
<div class="binding" on:click={() => addToText(binding)}>
|
||||||
|
@ -76,7 +76,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<Heading size="XS">Helpers</Heading>
|
<Heading size="XS">Helpers</Heading>
|
||||||
{#each helpers.filter((helper) => helper.label.match(searchRgx) || helper.description.match(searchRgx)) as helper}
|
{#each helpers.filter(helper => helper.label.match(searchRgx) || helper.description.match(searchRgx)) as helper}
|
||||||
<div class="binding" on:click={() => addToText(helper)}>
|
<div class="binding" on:click={() => addToText(helper)}>
|
||||||
<span class="binding__label">{helper.label}</span>
|
<span class="binding__label">{helper.label}</span>
|
||||||
<br />
|
<br />
|
||||||
|
|
|
@ -54,40 +54,43 @@
|
||||||
{#each inputs as [key, value]}
|
{#each inputs as [key, value]}
|
||||||
<div class="block-field">
|
<div class="block-field">
|
||||||
<Label>{value.title}</Label>
|
<Label>{value.title}</Label>
|
||||||
{#if value.type === 'string' && value.enum}
|
{#if value.type === "string" && value.enum}
|
||||||
<Select
|
<Select
|
||||||
bind:value={block.inputs[key]}
|
bind:value={block.inputs[key]}
|
||||||
options={value.enum}
|
options={value.enum}
|
||||||
getOptionLabel={(x, idx) => (value.pretty ? value.pretty[idx] : x)} />
|
getOptionLabel={(x, idx) => (value.pretty ? value.pretty[idx] : x)}
|
||||||
{:else if value.customType === 'password'}
|
/>
|
||||||
|
{:else if value.customType === "password"}
|
||||||
<Input type="password" bind:value={block.inputs[key]} />
|
<Input type="password" bind:value={block.inputs[key]} />
|
||||||
{:else if value.customType === 'email'}
|
{:else if value.customType === "email"}
|
||||||
<DrawerBindableInput
|
<DrawerBindableInput
|
||||||
panel={AutomationBindingPanel}
|
panel={AutomationBindingPanel}
|
||||||
type={'email'}
|
type={"email"}
|
||||||
value={block.inputs[key]}
|
value={block.inputs[key]}
|
||||||
on:change={e => (block.inputs[key] = e.detail)}
|
on:change={e => (block.inputs[key] = e.detail)}
|
||||||
{bindings} />
|
{bindings}
|
||||||
{:else if value.customType === 'table'}
|
/>
|
||||||
|
{:else if value.customType === "table"}
|
||||||
<TableSelector bind:value={block.inputs[key]} />
|
<TableSelector bind:value={block.inputs[key]} />
|
||||||
{:else if value.customType === 'row'}
|
{:else if value.customType === "row"}
|
||||||
<RowSelector bind:value={block.inputs[key]} {bindings} />
|
<RowSelector bind:value={block.inputs[key]} {bindings} />
|
||||||
{:else if value.customType === 'webhookUrl'}
|
{:else if value.customType === "webhookUrl"}
|
||||||
<WebhookDisplay value={block.inputs[key]} />
|
<WebhookDisplay value={block.inputs[key]} />
|
||||||
{:else if value.customType === 'triggerSchema'}
|
{:else if value.customType === "triggerSchema"}
|
||||||
<SchemaSetup bind:value={block.inputs[key]} />
|
<SchemaSetup bind:value={block.inputs[key]} />
|
||||||
{:else if value.type === 'string' || value.type === 'number'}
|
{:else if value.type === "string" || value.type === "number"}
|
||||||
<DrawerBindableInput
|
<DrawerBindableInput
|
||||||
panel={AutomationBindingPanel}
|
panel={AutomationBindingPanel}
|
||||||
type={value.customType}
|
type={value.customType}
|
||||||
value={block.inputs[key]}
|
value={block.inputs[key]}
|
||||||
on:change={e => (block.inputs[key] = e.detail)}
|
on:change={e => (block.inputs[key] = e.detail)}
|
||||||
{bindings} />
|
{bindings}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{#if stepId === 'WEBHOOK'}
|
{#if stepId === "WEBHOOK"}
|
||||||
<Button secondary on:click={() => webhookModal.show()}>Set Up Webhook</Button>
|
<Button secondary on:click={() => webhookModal.show()}>Set Up Webhook</Button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,8 @@
|
||||||
bind:value={value.tableId}
|
bind:value={value.tableId}
|
||||||
options={$tables.list}
|
options={$tables.list}
|
||||||
getOptionLabel={table => table.name}
|
getOptionLabel={table => table.name}
|
||||||
getOptionValue={table => table._id} />
|
getOptionValue={table => table._id}
|
||||||
|
/>
|
||||||
|
|
||||||
{#if schemaFields.length}
|
{#if schemaFields.length}
|
||||||
<div class="schema-fields">
|
<div class="schema-fields">
|
||||||
|
@ -33,15 +34,17 @@
|
||||||
<Select
|
<Select
|
||||||
label={field}
|
label={field}
|
||||||
bind:value={value[field]}
|
bind:value={value[field]}
|
||||||
options={schema.constraints.inclusion} />
|
options={schema.constraints.inclusion}
|
||||||
{:else if schema.type === 'string' || schema.type === 'number'}
|
/>
|
||||||
|
{:else if schema.type === "string" || schema.type === "number"}
|
||||||
<DrawerBindableInput
|
<DrawerBindableInput
|
||||||
panel={AutomationBindingPanel}
|
panel={AutomationBindingPanel}
|
||||||
value={value[field]}
|
value={value[field]}
|
||||||
on:change={e => (value[field] = e.detail)}
|
on:change={e => (value[field] = e.detail)}
|
||||||
label={field}
|
label={field}
|
||||||
type="string"
|
type="string"
|
||||||
{bindings} />
|
{bindings}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
@ -62,14 +62,17 @@
|
||||||
value={field.name}
|
value={field.name}
|
||||||
secondary
|
secondary
|
||||||
placeholder="Enter field name"
|
placeholder="Enter field name"
|
||||||
on:change={fieldNameChanged(field.name)} />
|
on:change={fieldNameChanged(field.name)}
|
||||||
|
/>
|
||||||
<Select
|
<Select
|
||||||
value={field.type}
|
value={field.type}
|
||||||
on:change={e => (value[field.name] = e.target.value)}
|
on:change={e => (value[field.name] = e.target.value)}
|
||||||
options={typeOptions} />
|
options={typeOptions}
|
||||||
|
/>
|
||||||
<i
|
<i
|
||||||
class="remove-field ri-delete-bin-line"
|
class="remove-field ri-delete-bin-line"
|
||||||
on:click={() => removeField(field.name)} />
|
on:click={() => removeField(field.name)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -9,4 +9,5 @@
|
||||||
bind:value
|
bind:value
|
||||||
options={$tables.list}
|
options={$tables.list}
|
||||||
getOptionLabel={table => table.name}
|
getOptionLabel={table => table.name}
|
||||||
getOptionValue={table => table._id} />
|
getOptionValue={table => table._id}
|
||||||
|
/>
|
||||||
|
|
|
@ -53,12 +53,14 @@
|
||||||
{data}
|
{data}
|
||||||
allowEditing={true}
|
allowEditing={true}
|
||||||
bind:hideAutocolumns
|
bind:hideAutocolumns
|
||||||
{loading}>
|
{loading}
|
||||||
|
>
|
||||||
<CreateColumnButton />
|
<CreateColumnButton />
|
||||||
{#if schema && Object.keys(schema).length > 0}
|
{#if schema && Object.keys(schema).length > 0}
|
||||||
<CreateRowButton
|
<CreateRowButton
|
||||||
title={isUsersTable ? 'Create user' : 'Create row'}
|
title={isUsersTable ? "Create user" : "Create row"}
|
||||||
modalContentComponent={isUsersTable ? CreateEditUser : CreateEditRow} />
|
modalContentComponent={isUsersTable ? CreateEditUser : CreateEditRow}
|
||||||
|
/>
|
||||||
<CreateViewButton />
|
<CreateViewButton />
|
||||||
<ManageAccessButton resourceId={$tables.selected?._id} />
|
<ManageAccessButton resourceId={$tables.selected?._id} />
|
||||||
{#if isUsersTable}
|
{#if isUsersTable}
|
||||||
|
|
|
@ -13,21 +13,22 @@
|
||||||
$: label = capitalise(meta.name)
|
$: label = capitalise(meta.name)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if type === 'options'}
|
{#if type === "options"}
|
||||||
<Select
|
<Select
|
||||||
{label}
|
{label}
|
||||||
data-cy="{meta.name}-select"
|
data-cy="{meta.name}-select"
|
||||||
bind:value
|
bind:value
|
||||||
options={meta.constraints.inclusion} />
|
options={meta.constraints.inclusion}
|
||||||
{:else if type === 'datetime'}
|
/>
|
||||||
|
{:else if type === "datetime"}
|
||||||
<DatePicker {label} bind:value />
|
<DatePicker {label} bind:value />
|
||||||
{:else if type === 'attachment'}
|
{:else if type === "attachment"}
|
||||||
<Dropzone {label} bind:value />
|
<Dropzone {label} bind:value />
|
||||||
{:else if type === 'boolean'}
|
{:else if type === "boolean"}
|
||||||
<Toggle text={label} bind:checked={value} data-cy="{meta.name}-input" />
|
<Toggle text={label} bind:checked={value} data-cy="{meta.name}-input" />
|
||||||
{:else if type === 'link'}
|
{:else if type === "link"}
|
||||||
<LinkedRowSelector bind:linkedRows={value} schema={meta} />
|
<LinkedRowSelector bind:linkedRows={value} schema={meta} />
|
||||||
{:else if type === 'longform'}
|
{:else if type === "longform"}
|
||||||
<TextArea {label} bind:value />
|
<TextArea {label} bind:value />
|
||||||
{:else}
|
{:else}
|
||||||
<Input
|
<Input
|
||||||
|
@ -35,5 +36,6 @@
|
||||||
data-cy="{meta.name}-input"
|
data-cy="{meta.name}-input"
|
||||||
{type}
|
{type}
|
||||||
bind:value
|
bind:value
|
||||||
disabled={readonly} />
|
disabled={readonly}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
component: RoleCell,
|
component: RoleCell,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
UNEDITABLE_USER_FIELDS.forEach((field) => {
|
UNEDITABLE_USER_FIELDS.forEach(field => {
|
||||||
if (schema[field]) {
|
if (schema[field]) {
|
||||||
schema[field].editable = false
|
schema[field].editable = false
|
||||||
}
|
}
|
||||||
|
@ -68,19 +68,19 @@
|
||||||
rows: selectedRows,
|
rows: selectedRows,
|
||||||
type: "delete",
|
type: "delete",
|
||||||
})
|
})
|
||||||
data = data.filter((row) => !selectedRows.includes(row))
|
data = data.filter(row => !selectedRows.includes(row))
|
||||||
notifications.success(`Successfully deleted ${selectedRows.length} rows`)
|
notifications.success(`Successfully deleted ${selectedRows.length} rows`)
|
||||||
selectedRows = []
|
selectedRows = []
|
||||||
}
|
}
|
||||||
|
|
||||||
const editRow = (row) => {
|
const editRow = row => {
|
||||||
editableRow = row
|
editableRow = row
|
||||||
if (row) {
|
if (row) {
|
||||||
editRowModal.show()
|
editRowModal.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const editColumn = (field) => {
|
const editColumn = field => {
|
||||||
editableColumn = schema?.[field]
|
editableColumn = schema?.[field]
|
||||||
if (editableColumn) {
|
if (editableColumn) {
|
||||||
editColumnModal.show()
|
editColumnModal.show()
|
||||||
|
@ -118,9 +118,9 @@
|
||||||
allowEditRows={allowEditing}
|
allowEditRows={allowEditing}
|
||||||
allowEditColumns={allowEditing}
|
allowEditColumns={allowEditing}
|
||||||
showAutoColumns={!hideAutocolumns}
|
showAutoColumns={!hideAutocolumns}
|
||||||
on:editcolumn={(e) => editColumn(e.detail)}
|
on:editcolumn={e => editColumn(e.detail)}
|
||||||
on:editrow={(e) => editRow(e.detail)}
|
on:editrow={e => editRow(e.detail)}
|
||||||
on:clickrelationship={(e) => selectRelationship(e.detail)}
|
on:clickrelationship={e => selectRelationship(e.detail)}
|
||||||
/>
|
/>
|
||||||
{/key}
|
{/key}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,8 @@
|
||||||
{data}
|
{data}
|
||||||
{loading}
|
{loading}
|
||||||
allowEditing={!view?.calculation}
|
allowEditing={!view?.calculation}
|
||||||
bind:hideAutocolumns>
|
bind:hideAutocolumns
|
||||||
|
>
|
||||||
<FilterButton {view} />
|
<FilterButton {view} />
|
||||||
<CalculateButton {view} />
|
<CalculateButton {view} />
|
||||||
{#if view.calculation}
|
{#if view.calculation}
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
size="S"
|
size="S"
|
||||||
quiet
|
quiet
|
||||||
on:click={modal.show}
|
on:click={modal.show}
|
||||||
active={view.field && view.calculation}>
|
active={view.field && view.calculation}
|
||||||
|
>
|
||||||
Calculate
|
Calculate
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
<Modal bind:this={modal}>
|
<Modal bind:this={modal}>
|
||||||
|
|
|
@ -22,8 +22,9 @@
|
||||||
bind:this={modal}
|
bind:this={modal}
|
||||||
okText="Delete"
|
okText="Delete"
|
||||||
onOk={confirmDeletion}
|
onOk={confirmDeletion}
|
||||||
title="Confirm Deletion">
|
title="Confirm Deletion"
|
||||||
|
>
|
||||||
Are you sure you want to delete
|
Are you sure you want to delete
|
||||||
{selectedRows.length}
|
{selectedRows.length}
|
||||||
row{selectedRows.length > 1 ? 's' : ''}?
|
row{selectedRows.length > 1 ? "s" : ""}?
|
||||||
</ConfirmDialog>
|
</ConfirmDialog>
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
size="S"
|
size="S"
|
||||||
quiet
|
quiet
|
||||||
on:click={modal.show}
|
on:click={modal.show}
|
||||||
active={view.filters?.length}>
|
active={view.filters?.length}
|
||||||
|
>
|
||||||
Filter
|
Filter
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
<Modal bind:this={modal}>
|
<Modal bind:this={modal}>
|
||||||
|
|
|
@ -13,7 +13,8 @@
|
||||||
size="S"
|
size="S"
|
||||||
quiet
|
quiet
|
||||||
active={!!view.groupBy}
|
active={!!view.groupBy}
|
||||||
on:click={modal.show}>
|
on:click={modal.show}
|
||||||
|
>
|
||||||
Group By
|
Group By
|
||||||
</Button>
|
</Button>
|
||||||
<Modal bind:this={modal}>
|
<Modal bind:this={modal}>
|
||||||
|
|
|
@ -21,5 +21,6 @@
|
||||||
<ManageAccessModal
|
<ManageAccessModal
|
||||||
{resourceId}
|
{resourceId}
|
||||||
levels={$permissions}
|
levels={$permissions}
|
||||||
permissions={resourcePermissions} />
|
permissions={resourcePermissions}
|
||||||
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
@ -43,14 +43,16 @@
|
||||||
title="Calculate"
|
title="Calculate"
|
||||||
confirmText="Save"
|
confirmText="Save"
|
||||||
onConfirm={saveView}
|
onConfirm={saveView}
|
||||||
disabled={!view.field}>
|
disabled={!view.field}
|
||||||
|
>
|
||||||
<div class="input-group-row">
|
<div class="input-group-row">
|
||||||
<Label>The</Label>
|
<Label>The</Label>
|
||||||
<Select
|
<Select
|
||||||
bind:value={view.calculation}
|
bind:value={view.calculation}
|
||||||
options={CALCULATIONS}
|
options={CALCULATIONS}
|
||||||
getOptionLabel={x => x.name}
|
getOptionLabel={x => x.name}
|
||||||
getOptionValue={x => x.key} />
|
getOptionValue={x => x.key}
|
||||||
|
/>
|
||||||
{#if view.calculation}
|
{#if view.calculation}
|
||||||
<Label>Of</Label>
|
<Label>Of</Label>
|
||||||
<Select bind:value={view.field} options={fields} />
|
<Select bind:value={view.field} options={fields} />
|
||||||
|
|
|
@ -181,10 +181,11 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ModalContent
|
<ModalContent
|
||||||
title={originalName ? 'Edit Column' : 'Create Column'}
|
title={originalName ? "Edit Column" : "Create Column"}
|
||||||
confirmText="Save Column"
|
confirmText="Save Column"
|
||||||
onConfirm={saveColumn}
|
onConfirm={saveColumn}
|
||||||
disabled={invalid}>
|
disabled={invalid}
|
||||||
|
>
|
||||||
<Input label="Name" bind:value={field.name} disabled={uneditable} />
|
<Input label="Name" bind:value={field.name} disabled={uneditable} />
|
||||||
|
|
||||||
<Select
|
<Select
|
||||||
|
@ -192,9 +193,13 @@
|
||||||
label="Type"
|
label="Type"
|
||||||
bind:value={field.type}
|
bind:value={field.type}
|
||||||
on:change={handleTypeChange}
|
on:change={handleTypeChange}
|
||||||
options={[...Object.values(fieldDefinitions), { name: 'Auto Column', type: AUTO_COL }]}
|
options={[
|
||||||
|
...Object.values(fieldDefinitions),
|
||||||
|
{ name: "Auto Column", type: AUTO_COL },
|
||||||
|
]}
|
||||||
getOptionLabel={field => field.name}
|
getOptionLabel={field => field.name}
|
||||||
getOptionValue={field => field.type} />
|
getOptionValue={field => field.type}
|
||||||
|
/>
|
||||||
|
|
||||||
{#if canBeRequired || canBeDisplay}
|
{#if canBeRequired || canBeDisplay}
|
||||||
<div>
|
<div>
|
||||||
|
@ -204,14 +209,16 @@
|
||||||
on:change={onChangeRequired}
|
on:change={onChangeRequired}
|
||||||
disabled={primaryDisplay}
|
disabled={primaryDisplay}
|
||||||
thin
|
thin
|
||||||
text="Required" />
|
text="Required"
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{#if canBeDisplay}
|
{#if canBeDisplay}
|
||||||
<Toggle
|
<Toggle
|
||||||
bind:value={primaryDisplay}
|
bind:value={primaryDisplay}
|
||||||
on:change={onChangePrimaryDisplay}
|
on:change={onChangePrimaryDisplay}
|
||||||
thin
|
thin
|
||||||
text="Use as table display column" />
|
text="Use as table display column"
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -223,45 +230,53 @@
|
||||||
value={indexes[0] === field.name}
|
value={indexes[0] === field.name}
|
||||||
disabled={indexes[1] === field.name}
|
disabled={indexes[1] === field.name}
|
||||||
on:change={onChangePrimaryIndex}
|
on:change={onChangePrimaryIndex}
|
||||||
text="Primary" />
|
text="Primary"
|
||||||
|
/>
|
||||||
<Toggle
|
<Toggle
|
||||||
value={indexes[1] === field.name}
|
value={indexes[1] === field.name}
|
||||||
disabled={!indexes[0] || indexes[0] === field.name}
|
disabled={!indexes[0] || indexes[0] === field.name}
|
||||||
on:change={onChangeSecondaryIndex}
|
on:change={onChangeSecondaryIndex}
|
||||||
text="Secondary" />
|
text="Secondary"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if field.type === 'string'}
|
{#if field.type === "string"}
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
label="Max Length"
|
label="Max Length"
|
||||||
bind:value={field.constraints.length.maximum} />
|
bind:value={field.constraints.length.maximum}
|
||||||
{:else if field.type === 'options'}
|
/>
|
||||||
|
{:else if field.type === "options"}
|
||||||
<ValuesList
|
<ValuesList
|
||||||
label="Options (one per line)"
|
label="Options (one per line)"
|
||||||
bind:values={field.constraints.inclusion} />
|
bind:values={field.constraints.inclusion}
|
||||||
{:else if field.type === 'datetime'}
|
/>
|
||||||
|
{:else if field.type === "datetime"}
|
||||||
<DatePicker
|
<DatePicker
|
||||||
label="Earliest"
|
label="Earliest"
|
||||||
bind:value={field.constraints.datetime.earliest} />
|
bind:value={field.constraints.datetime.earliest}
|
||||||
|
/>
|
||||||
<DatePicker label="Latest" bind:value={field.constraints.datetime.latest} />
|
<DatePicker label="Latest" bind:value={field.constraints.datetime.latest} />
|
||||||
{:else if field.type === 'number'}
|
{:else if field.type === "number"}
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
label="Min Value"
|
label="Min Value"
|
||||||
bind:value={field.constraints.numericality.greaterThanOrEqualTo} />
|
bind:value={field.constraints.numericality.greaterThanOrEqualTo}
|
||||||
|
/>
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
label="Max Value"
|
label="Max Value"
|
||||||
bind:value={field.constraints.numericality.lessThanOrEqualTo} />
|
bind:value={field.constraints.numericality.lessThanOrEqualTo}
|
||||||
{:else if field.type === 'link'}
|
/>
|
||||||
|
{:else if field.type === "link"}
|
||||||
<Select
|
<Select
|
||||||
label="Table"
|
label="Table"
|
||||||
bind:value={field.tableId}
|
bind:value={field.tableId}
|
||||||
options={tableOptions}
|
options={tableOptions}
|
||||||
getOptionLabel={table => table.name}
|
getOptionLabel={table => table.name}
|
||||||
getOptionValue={table => table._id} />
|
getOptionValue={table => table._id}
|
||||||
|
/>
|
||||||
{#if relationshipOptions && relationshipOptions.length > 0}
|
{#if relationshipOptions && relationshipOptions.length > 0}
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
disabled={originalName}
|
disabled={originalName}
|
||||||
|
@ -269,7 +284,8 @@
|
||||||
bind:value={field.relationshipType}
|
bind:value={field.relationshipType}
|
||||||
options={relationshipOptions}
|
options={relationshipOptions}
|
||||||
getOptionLabel={option => option.name}
|
getOptionLabel={option => option.name}
|
||||||
getOptionValue={option => option.value} />
|
getOptionValue={option => option.value}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
<Input label={`Column name in other table`} bind:value={field.fieldName} />
|
<Input label={`Column name in other table`} bind:value={field.fieldName} />
|
||||||
{:else if field.type === AUTO_COL}
|
{:else if field.type === AUTO_COL}
|
||||||
|
@ -279,7 +295,8 @@
|
||||||
on:change={e => (field.subtype = e.detail)}
|
on:change={e => (field.subtype = e.detail)}
|
||||||
options={Object.entries(getAutoColumnInformation())}
|
options={Object.entries(getAutoColumnInformation())}
|
||||||
getOptionLabel={option => option[1].name}
|
getOptionLabel={option => option[1].name}
|
||||||
getOptionValue={option => option[0]} />
|
getOptionValue={option => option[0]}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div slot="footer">
|
<div slot="footer">
|
||||||
|
@ -294,4 +311,5 @@
|
||||||
okText="Delete Column"
|
okText="Delete Column"
|
||||||
onOk={deleteColumn}
|
onOk={deleteColumn}
|
||||||
onCancel={hideDeleteDialog}
|
onCancel={hideDeleteDialog}
|
||||||
title="Confirm Deletion" />
|
title="Confirm Deletion"
|
||||||
|
/>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue