filtering apps with user groups, added clear button in pickerdropdown component
This commit is contained in:
parent
2399dbceb9
commit
d6483e8d92
|
@ -10,6 +10,7 @@
|
||||||
import Detail from "../../Typography/Detail.svelte"
|
import Detail from "../../Typography/Detail.svelte"
|
||||||
|
|
||||||
export let primaryLabel = ""
|
export let primaryLabel = ""
|
||||||
|
export let primaryValue = null
|
||||||
export let id = null
|
export let id = null
|
||||||
export let placeholder = "Choose an option or type"
|
export let placeholder = "Choose an option or type"
|
||||||
export let disabled = false
|
export let disabled = false
|
||||||
|
@ -73,6 +74,11 @@
|
||||||
primaryOpen = false
|
primaryOpen = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onClearPrimary = () => {
|
||||||
|
dispatch("pickprimary", null)
|
||||||
|
primaryOpen = false
|
||||||
|
}
|
||||||
|
|
||||||
const onPickSecondary = newValue => {
|
const onPickSecondary = newValue => {
|
||||||
dispatch("picksecondary", newValue)
|
dispatch("picksecondary", newValue)
|
||||||
secondaryOpen = false
|
secondaryOpen = false
|
||||||
|
@ -123,7 +129,7 @@
|
||||||
class:is-invalid={!!error}
|
class:is-invalid={!!error}
|
||||||
class:is-disabled={disabled}
|
class:is-disabled={disabled}
|
||||||
class:is-focused={focus}
|
class:is-focused={focus}
|
||||||
style="width: 70%"
|
class:is-full-width={!secondaryOptions.length}
|
||||||
>
|
>
|
||||||
{#if iconData}
|
{#if iconData}
|
||||||
<svg
|
<svg
|
||||||
|
@ -153,6 +159,21 @@
|
||||||
class="spectrum-Textfield-input spectrum-InputGroup-input"
|
class="spectrum-Textfield-input spectrum-InputGroup-input"
|
||||||
class:labelPadding={iconData}
|
class:labelPadding={iconData}
|
||||||
/>
|
/>
|
||||||
|
{#if primaryValue}
|
||||||
|
<button
|
||||||
|
on:click={() => onClearPrimary()}
|
||||||
|
type="reset"
|
||||||
|
class="spectrum-ClearButton spectrum-Search-clearButton"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="spectrum-Icon spectrum-UIIcon-Cross75"
|
||||||
|
focusable="false"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<use xlink:href="#spectrum-css-icon-Cross75" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{#if primaryOpen}
|
{#if primaryOpen}
|
||||||
<div
|
<div
|
||||||
|
@ -160,7 +181,7 @@
|
||||||
transition:fly|local={{ y: -20, duration: 200 }}
|
transition:fly|local={{ 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"
|
||||||
class:auto-width={autoWidth}
|
class:auto-width={autoWidth}
|
||||||
style="width: 70%"
|
class:is-full-width={!secondaryOptions.length}
|
||||||
>
|
>
|
||||||
<ul class="spectrum-Menu" role="listbox">
|
<ul class="spectrum-Menu" role="listbox">
|
||||||
{#if placeholderOption}
|
{#if placeholderOption}
|
||||||
|
@ -250,78 +271,82 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div style="width: 30%">
|
{#if secondaryOptions.length}
|
||||||
<button
|
<div style="width: 30%">
|
||||||
{id}
|
<button
|
||||||
class="spectrum-Picker spectrum-Picker--sizeM override-borders"
|
{id}
|
||||||
{disabled}
|
class="spectrum-Picker spectrum-Picker--sizeM override-borders"
|
||||||
class:is-open={secondaryOpen}
|
{disabled}
|
||||||
aria-haspopup="listbox"
|
class:is-open={secondaryOpen}
|
||||||
on:mousedown={onClickSecondary}
|
aria-haspopup="listbox"
|
||||||
>
|
on:mousedown={onClickSecondary}
|
||||||
{#if secondaryFieldIcon}
|
|
||||||
<span class="option-left">
|
|
||||||
<Icon name={secondaryFieldIcon} />
|
|
||||||
</span>
|
|
||||||
{:else if secondaryFieldColour}
|
|
||||||
<span class="option-left">
|
|
||||||
<StatusLight color={secondaryFieldColour} />
|
|
||||||
</span>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<span class:auto-width={autoWidth} class="spectrum-Picker-label">
|
|
||||||
{secondaryFieldText}
|
|
||||||
</span>
|
|
||||||
<svg
|
|
||||||
class="spectrum-Icon spectrum-UIIcon-ChevronDown100 spectrum-Picker-menuIcon"
|
|
||||||
focusable="false"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
>
|
||||||
<use xlink:href="#spectrum-css-icon-Chevron100" />
|
{#if secondaryFieldIcon}
|
||||||
</svg>
|
<span class="option-left">
|
||||||
</button>
|
<Icon name={secondaryFieldIcon} />
|
||||||
{#if secondaryOpen}
|
</span>
|
||||||
<div
|
{:else if secondaryFieldColour}
|
||||||
use:clickOutside={() => (secondaryOpen = false)}
|
<span class="option-left">
|
||||||
transition:fly|local={{ y: -20, duration: 200 }}
|
<StatusLight color={secondaryFieldColour} />
|
||||||
class="spectrum-Popover spectrum-Popover--bottom spectrum-Picker-popover is-open"
|
</span>
|
||||||
style="width: 30%"
|
{/if}
|
||||||
>
|
|
||||||
<ul class="spectrum-Menu" role="listbox">
|
|
||||||
{#each secondaryOptions as option, idx}
|
|
||||||
<li
|
|
||||||
class="spectrum-Menu-item"
|
|
||||||
class:is-selected={isOptionSelected(
|
|
||||||
getSecondaryOptionValue(option, idx)
|
|
||||||
)}
|
|
||||||
role="option"
|
|
||||||
aria-selected="true"
|
|
||||||
tabindex="0"
|
|
||||||
on:click={() =>
|
|
||||||
onPickSecondary(getSecondaryOptionValue(option, idx))}
|
|
||||||
>
|
|
||||||
{#if getSecondaryOptionColour(option, idx)}
|
|
||||||
<span class="option-left">
|
|
||||||
<StatusLight color={getSecondaryOptionColour(option, idx)} />
|
|
||||||
</span>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<span class="spectrum-Menu-itemLabel">
|
<span class:auto-width={autoWidth} class="spectrum-Picker-label">
|
||||||
{getSecondaryOptionLabel(option, idx)}
|
{secondaryFieldText}
|
||||||
</span>
|
</span>
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon"
|
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" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
{#if secondaryOpen}
|
||||||
|
<div
|
||||||
|
use:clickOutside={() => (secondaryOpen = false)}
|
||||||
|
transition:fly|local={{ y: -20, duration: 200 }}
|
||||||
|
class="spectrum-Popover spectrum-Popover--bottom spectrum-Picker-popover is-open"
|
||||||
|
style="width: 30%"
|
||||||
|
>
|
||||||
|
<ul class="spectrum-Menu" role="listbox">
|
||||||
|
{#each secondaryOptions as option, idx}
|
||||||
|
<li
|
||||||
|
class="spectrum-Menu-item"
|
||||||
|
class:is-selected={isOptionSelected(
|
||||||
|
getSecondaryOptionValue(option, idx)
|
||||||
|
)}
|
||||||
|
role="option"
|
||||||
|
aria-selected="true"
|
||||||
|
tabindex="0"
|
||||||
|
on:click={() =>
|
||||||
|
onPickSecondary(getSecondaryOptionValue(option, idx))}
|
||||||
>
|
>
|
||||||
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
{#if getSecondaryOptionColour(option, idx)}
|
||||||
</svg>
|
<span class="option-left">
|
||||||
</li>
|
<StatusLight
|
||||||
{/each}
|
color={getSecondaryOptionColour(option, idx)}
|
||||||
</ul>
|
/>
|
||||||
</div>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
|
||||||
|
<span class="spectrum-Menu-itemLabel">
|
||||||
|
{getSecondaryOptionLabel(option, idx)}
|
||||||
|
</span>
|
||||||
|
<svg
|
||||||
|
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon"
|
||||||
|
focusable="false"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
||||||
|
</svg>
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -381,4 +406,25 @@
|
||||||
.labelPadding {
|
.labelPadding {
|
||||||
padding-left: calc(1em + 10px + 8px);
|
padding-left: calc(1em + 10px + 8px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.spectrum-Textfield.spectrum-InputGroup-textfield {
|
||||||
|
width: 70%;
|
||||||
|
}
|
||||||
|
.spectrum-Textfield.spectrum-InputGroup-textfield.is-full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.spectrum-Textfield.spectrum-InputGroup-textfield.is-full-width input {
|
||||||
|
border-right-width: thin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spectrum-Popover.spectrum-Popover--bottom.spectrum-Picker-popover.is-open {
|
||||||
|
width: 70%;
|
||||||
|
}
|
||||||
|
.spectrum-Popover.spectrum-Popover--bottom.spectrum-Picker-popover.is-open.is-full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spectrum-Search-clearButton {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -71,9 +71,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const onPickPrimary = e => {
|
const onPickPrimary = e => {
|
||||||
primaryLabel = e.detail.label
|
primaryLabel = e?.detail?.label || null
|
||||||
primaryValue = e.detail.value
|
primaryValue = e?.detail?.value || null
|
||||||
dispatch("pickprimary", e.detail.value)
|
dispatch("pickprimary", e?.detail?.value || {})
|
||||||
}
|
}
|
||||||
|
|
||||||
const onPickSecondary = e => {
|
const onPickSecondary = e => {
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
<script>
|
||||||
|
import { PickerDropdown, notifications } from "@budibase/bbui"
|
||||||
|
import { groups } from "stores/portal"
|
||||||
|
import { onMount, createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
$: optionSections = {
|
||||||
|
groups: {
|
||||||
|
data: $groups,
|
||||||
|
getLabel: group => group.name,
|
||||||
|
getValue: group => group._id,
|
||||||
|
getIcon: group => group.icon,
|
||||||
|
getColour: group => group.color,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
$: appData = [{ id: "", role: "" }]
|
||||||
|
|
||||||
|
$: onChange = selected => {
|
||||||
|
const { detail } = selected
|
||||||
|
if (!detail) return
|
||||||
|
|
||||||
|
const groupSelected = $groups.find(x => x._id === detail)
|
||||||
|
const appIds = groupSelected?.apps.map(x => x.appId) || null
|
||||||
|
dispatch("change", appIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
try {
|
||||||
|
await groups.actions.init()
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<PickerDropdown
|
||||||
|
autocomplete
|
||||||
|
primaryOptions={optionSections}
|
||||||
|
placeholder={"Filter by access"}
|
||||||
|
on:pickprimary={onChange}
|
||||||
|
/>
|
|
@ -20,12 +20,13 @@
|
||||||
import { store, automationStore } from "builderStore"
|
import { store, automationStore } from "builderStore"
|
||||||
import { API } from "api"
|
import { API } from "api"
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { apps, auth, admin, templates } from "stores/portal"
|
import { apps, auth, admin, templates, groups } from "stores/portal"
|
||||||
import download from "downloadjs"
|
import download from "downloadjs"
|
||||||
import { goto } from "@roxi/routify"
|
import { goto } from "@roxi/routify"
|
||||||
import AppRow from "components/start/AppRow.svelte"
|
import AppRow from "components/start/AppRow.svelte"
|
||||||
import { AppStatus } from "constants"
|
import { AppStatus } from "constants"
|
||||||
import Logo from "assets/bb-space-man.svg"
|
import Logo from "assets/bb-space-man.svg"
|
||||||
|
import AccessFilter from "./_components/AcessFilter.svelte"
|
||||||
|
|
||||||
let sortBy = "name"
|
let sortBy = "name"
|
||||||
let template
|
let template
|
||||||
|
@ -39,6 +40,7 @@
|
||||||
let cloud = $admin.cloud
|
let cloud = $admin.cloud
|
||||||
let creatingFromTemplate = false
|
let creatingFromTemplate = false
|
||||||
let automationErrors
|
let automationErrors
|
||||||
|
let accessFilterList = null
|
||||||
|
|
||||||
const resolveWelcomeMessage = (auth, apps) => {
|
const resolveWelcomeMessage = (auth, apps) => {
|
||||||
const userWelcome = auth?.user?.firstName
|
const userWelcome = auth?.user?.firstName
|
||||||
|
@ -56,8 +58,10 @@
|
||||||
: "Start from scratch"
|
: "Start from scratch"
|
||||||
|
|
||||||
$: enrichedApps = enrichApps($apps, $auth.user, sortBy)
|
$: enrichedApps = enrichApps($apps, $auth.user, sortBy)
|
||||||
$: filteredApps = enrichedApps.filter(app =>
|
$: filteredApps = enrichedApps.filter(
|
||||||
app?.name?.toLowerCase().includes(searchTerm.toLowerCase())
|
app =>
|
||||||
|
app?.name?.toLowerCase().includes(searchTerm.toLowerCase()) &&
|
||||||
|
(accessFilterList !== null ? accessFilterList.includes(app?.appId) : true)
|
||||||
)
|
)
|
||||||
|
|
||||||
$: lockedApps = filteredApps.filter(app => app?.lockedYou || app?.lockedOther)
|
$: lockedApps = filteredApps.filter(app => app?.lockedYou || app?.lockedOther)
|
||||||
|
@ -202,6 +206,10 @@
|
||||||
$goto(`../../app/${app.devId}`)
|
$goto(`../../app/${app.devId}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const accessFilterAction = accessFilter => {
|
||||||
|
accessFilterList = accessFilter.detail
|
||||||
|
}
|
||||||
|
|
||||||
function createAppFromTemplateUrl(templateKey) {
|
function createAppFromTemplateUrl(templateKey) {
|
||||||
// validate the template key just to make sure
|
// validate the template key just to make sure
|
||||||
const templateParts = templateKey.split("/")
|
const templateParts = templateKey.split("/")
|
||||||
|
@ -347,6 +355,9 @@
|
||||||
</Button>
|
</Button>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="filter">
|
<div class="filter">
|
||||||
|
{#if $groups.length}
|
||||||
|
<AccessFilter on:change={accessFilterAction} />
|
||||||
|
{/if}
|
||||||
<Select
|
<Select
|
||||||
quiet
|
quiet
|
||||||
autoWidth
|
autoWidth
|
||||||
|
|
Loading…
Reference in New Issue