Merge branch 'master' into feature/filter-component
This commit is contained in:
commit
380562a1dd
|
@ -11,7 +11,7 @@
|
|||
export let hoverColor: string | undefined = undefined
|
||||
export let tooltip: string | undefined = undefined
|
||||
export let tooltipPosition: TooltipPosition = TooltipPosition.Bottom
|
||||
export let tooltipType = TooltipType.Default
|
||||
export let tooltipType: TooltipType = TooltipType.Default
|
||||
export let tooltipColor: string | undefined = undefined
|
||||
export let tooltipWrap: boolean = true
|
||||
export let newStyles: boolean = false
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
export let horizontal: boolean = false
|
||||
export let paddingX: "S" | "M" | "L" | "XL" | "XXL" = "M"
|
||||
export let paddingY: "S" | "M" | "L" | "XL" | "XXL" = "M"
|
||||
export let paddingY: "none" | "S" | "M" | "L" | "XL" | "XXL" = "M"
|
||||
export let noPadding: boolean = false
|
||||
export let gap: "XXS" | "XS" | "S" | "M" | "L" | "XL" = "M"
|
||||
export let noGap: boolean = false
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { ActionMenu } from "./types"
|
||||
import { ModalContext } from "./types"
|
||||
import { ActionMenu, ModalContext, ScrollContext } from "./types"
|
||||
|
||||
declare module "svelte" {
|
||||
export function getContext(key: "actionMenu"): ActionMenu | undefined
|
||||
export function getContext(key: "bbui-modal"): ModalContext
|
||||
export function getContext(key: "scroll"): ScrollContext
|
||||
}
|
||||
|
||||
export const Modal = "bbui-modal"
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
export * from "./actionMenu"
|
||||
export * from "./envDropdown"
|
||||
export * from "./modalContext"
|
||||
export * from "./scrollContext"
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
export interface ScrollContext {
|
||||
scrollTo: (bounds: DOMRect) => void
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
<script>
|
||||
<script lang="ts">
|
||||
import { tick } from "svelte"
|
||||
import { Icon, Body } from "@budibase/bbui"
|
||||
import { keyUtils } from "@/helpers/keyUtils"
|
||||
|
||||
export let title
|
||||
export let placeholder
|
||||
export let value
|
||||
export let onAdd
|
||||
export let search
|
||||
export let title: string
|
||||
export let placeholder: string
|
||||
export let value: string
|
||||
export let onAdd: () => void
|
||||
export let search: boolean
|
||||
|
||||
let searchInput
|
||||
let searchInput: HTMLInputElement
|
||||
|
||||
const openSearch = async () => {
|
||||
search = true
|
||||
|
@ -22,7 +22,7 @@
|
|||
value = ""
|
||||
}
|
||||
|
||||
const onKeyDown = e => {
|
||||
const onKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === "Escape") {
|
||||
closeSearch()
|
||||
}
|
||||
|
|
|
@ -1,46 +1,46 @@
|
|||
<script>
|
||||
<script lang="ts">
|
||||
import { Icon, TooltipType, TooltipPosition } from "@budibase/bbui"
|
||||
import { createEventDispatcher, getContext } from "svelte"
|
||||
import { helpers } from "@budibase/shared-core"
|
||||
import { UserAvatars } from "@budibase/frontend-core"
|
||||
import type { UIUser } from "@budibase/types"
|
||||
|
||||
export let icon
|
||||
export let iconTooltip
|
||||
export let withArrow = false
|
||||
export let withActions = true
|
||||
export let showActions = false
|
||||
export let indentLevel = 0
|
||||
export let text
|
||||
export let border = true
|
||||
export let selected = false
|
||||
export let opened = false
|
||||
export let draggable = false
|
||||
export let iconText
|
||||
export let iconColor
|
||||
export let scrollable = false
|
||||
export let highlighted = false
|
||||
export let rightAlignIcon = false
|
||||
export let id
|
||||
export let showTooltip = false
|
||||
export let selectedBy = null
|
||||
export let compact = false
|
||||
export let hovering = false
|
||||
export let disabled = false
|
||||
export let icon: string | null
|
||||
export let iconTooltip: string = ""
|
||||
export let withArrow: boolean = false
|
||||
export let withActions: boolean = true
|
||||
export let showActions: boolean = false
|
||||
export let indentLevel: number = 0
|
||||
export let text: string
|
||||
export let border: boolean = true
|
||||
export let selected: boolean = false
|
||||
export let opened: boolean = false
|
||||
export let draggable: boolean = false
|
||||
export let iconText: string = ""
|
||||
export let iconColor: string = ""
|
||||
export let scrollable: boolean = false
|
||||
export let highlighted: boolean = false
|
||||
export let rightAlignIcon: boolean = false
|
||||
export let id: string = ""
|
||||
export let showTooltip: boolean = false
|
||||
export let selectedBy: UIUser[] | null = null
|
||||
export let compact: boolean = false
|
||||
export let hovering: boolean = false
|
||||
export let disabled: boolean = false
|
||||
|
||||
const scrollApi = getContext("scroll")
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let contentRef
|
||||
let contentRef: HTMLDivElement
|
||||
|
||||
$: selected && contentRef && scrollToView()
|
||||
$: style = getStyle(indentLevel, selectedBy)
|
||||
$: style = getStyle(indentLevel)
|
||||
|
||||
const onClick = () => {
|
||||
scrollToView()
|
||||
dispatch("click")
|
||||
}
|
||||
|
||||
const onIconClick = e => {
|
||||
const onIconClick = (e: Event) => {
|
||||
e.stopPropagation()
|
||||
dispatch("iconClick")
|
||||
}
|
||||
|
@ -53,11 +53,8 @@
|
|||
scrollApi.scrollTo(bounds)
|
||||
}
|
||||
|
||||
const getStyle = (indentLevel, selectedBy) => {
|
||||
const getStyle = (indentLevel: number) => {
|
||||
let style = `padding-left:calc(${indentLevel * 14}px);`
|
||||
if (selectedBy) {
|
||||
style += `--selected-by-color:${helpers.getUserColor(selectedBy)};`
|
||||
}
|
||||
return style
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
<script>
|
||||
<script lang="ts">
|
||||
import { ModalContent, Input } from "@budibase/bbui"
|
||||
import sanitizeUrl from "@/helpers/sanitizeUrl"
|
||||
import { get } from "svelte/store"
|
||||
import { screenStore } from "@/stores/builder"
|
||||
|
||||
export let onConfirm
|
||||
export let onCancel
|
||||
export let route
|
||||
export let role
|
||||
export let onConfirm: (_data: { route: string }) => Promise<void>
|
||||
export let onCancel: (() => Promise<void>) | undefined = undefined
|
||||
export let route: string
|
||||
export let role: string | undefined
|
||||
export let confirmText = "Continue"
|
||||
|
||||
const appPrefix = "/app"
|
||||
let touched = false
|
||||
let error
|
||||
let modal
|
||||
let error: string | undefined
|
||||
let modal: ModalContent
|
||||
|
||||
$: appUrl = route
|
||||
? `${window.location.origin}${appPrefix}${route}`
|
||||
: `${window.location.origin}${appPrefix}`
|
||||
|
||||
const routeChanged = event => {
|
||||
const routeChanged = (event: { detail: string }) => {
|
||||
if (!event.detail.startsWith("/")) {
|
||||
route = "/" + event.detail
|
||||
}
|
||||
|
@ -28,11 +28,11 @@
|
|||
if (routeExists(route)) {
|
||||
error = "This URL is already taken for this access role"
|
||||
} else {
|
||||
error = null
|
||||
error = undefined
|
||||
}
|
||||
}
|
||||
|
||||
const routeExists = url => {
|
||||
const routeExists = (url: string) => {
|
||||
if (!role) {
|
||||
return false
|
||||
}
|
||||
|
@ -58,7 +58,7 @@
|
|||
onConfirm={confirmScreenDetails}
|
||||
{onCancel}
|
||||
cancelText={"Back"}
|
||||
disabled={!route || error || !touched}
|
||||
disabled={!route || !!error || !touched}
|
||||
>
|
||||
<form on:submit|preventDefault={() => modal.confirm()}>
|
||||
<Input
|
||||
|
|
|
@ -11,7 +11,10 @@
|
|||
$componentStore.selectedComponentId,
|
||||
"RefreshDatasource",
|
||||
{ includeSelf: nested }
|
||||
)
|
||||
).concat({
|
||||
readableBinding: "All data providers",
|
||||
runtimeBinding: "all",
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="root">
|
||||
|
|
|
@ -109,13 +109,12 @@
|
|||
/>
|
||||
{/each}
|
||||
</List>
|
||||
|
||||
{/if}
|
||||
<div>
|
||||
<Button secondary icon="Add" on:click={addOAuth2Configuration}
|
||||
>Add OAuth2</Button
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
</DetailPopover>
|
||||
|
||||
<style>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<script>
|
||||
<script lang="ts">
|
||||
import { Modal, Helpers, notifications, Icon } from "@budibase/bbui"
|
||||
import {
|
||||
navigationStore,
|
||||
|
@ -14,13 +14,14 @@
|
|||
import { makeComponentUnique } from "@/helpers/components"
|
||||
import { capitalise } from "@/helpers"
|
||||
import ConfirmDialog from "@/components/common/ConfirmDialog.svelte"
|
||||
import type { Screen } from "@budibase/types"
|
||||
|
||||
export let screen
|
||||
|
||||
let confirmDeleteDialog
|
||||
let screenDetailsModal
|
||||
let confirmDeleteDialog: ConfirmDialog
|
||||
let screenDetailsModal: Modal
|
||||
|
||||
const createDuplicateScreen = async ({ route }) => {
|
||||
const createDuplicateScreen = async ({ route }: { route: string }) => {
|
||||
// Create a dupe and ensure it is unique
|
||||
let duplicateScreen = Helpers.cloneDeep(screen)
|
||||
delete duplicateScreen._id
|
||||
|
@ -57,7 +58,7 @@
|
|||
|
||||
$: noPaste = !$componentStore.componentToPaste
|
||||
|
||||
const pasteComponent = mode => {
|
||||
const pasteComponent = (mode: "inside") => {
|
||||
try {
|
||||
componentStore.paste(screen.props, mode, screen)
|
||||
} catch (error) {
|
||||
|
@ -65,7 +66,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
const openContextMenu = (e, screen) => {
|
||||
const openContextMenu = (e: MouseEvent, screen: Screen) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
|
@ -96,7 +97,7 @@
|
|||
},
|
||||
]
|
||||
|
||||
contextMenuStore.open(screen._id, items, { x: e.clientX, y: e.clientY })
|
||||
contextMenuStore.open(screen._id!, items, { x: e.clientX, y: e.clientY })
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
<script>
|
||||
<script lang="ts">
|
||||
import { Layout } from "@budibase/bbui"
|
||||
import { sortedScreens } from "@/stores/builder"
|
||||
import ScreenNavItem from "./ScreenNavItem.svelte"
|
||||
import { goto } from "@roxi/routify"
|
||||
import { getVerticalResizeActions } from "@/components/common/resizable"
|
||||
import NavHeader from "@/components/common/NavHeader.svelte"
|
||||
import type { Screen } from "@budibase/types"
|
||||
|
||||
const [resizable, resizableHandle] = getVerticalResizeActions()
|
||||
|
||||
let searching = false
|
||||
let searchValue = ""
|
||||
let screensContainer
|
||||
let screensContainer: HTMLDivElement
|
||||
let scrolling = false
|
||||
|
||||
$: filteredScreens = getFilteredScreens($sortedScreens, searchValue)
|
||||
|
@ -25,13 +26,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
const getFilteredScreens = (screens, searchValue) => {
|
||||
const getFilteredScreens = (screens: Screen[], searchValue: string) => {
|
||||
return screens.filter(screen => {
|
||||
return !searchValue || screen.routing.route.includes(searchValue)
|
||||
})
|
||||
}
|
||||
|
||||
const handleScroll = e => {
|
||||
const handleScroll = (e: any) => {
|
||||
scrolling = e.target.scrollTop !== 0
|
||||
}
|
||||
</script>
|
||||
|
@ -62,7 +63,6 @@
|
|||
|
||||
<div
|
||||
role="separator"
|
||||
disabled={searching}
|
||||
class="divider"
|
||||
class:disabled={searching}
|
||||
use:resizableHandle
|
||||
|
|
|
@ -6,9 +6,12 @@ interface Position {
|
|||
}
|
||||
|
||||
interface MenuItem {
|
||||
label: string
|
||||
icon?: string
|
||||
action: () => void
|
||||
name: string
|
||||
keyBind: string | null
|
||||
visible: boolean
|
||||
disabled: boolean
|
||||
callback: () => void
|
||||
}
|
||||
|
||||
interface ContextMenuState {
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
UnsavedUser,
|
||||
} from "@budibase/types"
|
||||
import { BudiStore } from "../BudiStore"
|
||||
import { notifications } from "@budibase/bbui"
|
||||
|
||||
interface UserInfo {
|
||||
email: string
|
||||
|
@ -43,6 +44,7 @@ class UserStore extends BudiStore<UserState> {
|
|||
try {
|
||||
return await API.getUser(userId)
|
||||
} catch (err) {
|
||||
notifications.error("Error fetching user")
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
environmentStore,
|
||||
sidePanelStore,
|
||||
modalStore,
|
||||
dataSourceStore,
|
||||
} from "@/stores"
|
||||
import NotificationDisplay from "./overlay/NotificationDisplay.svelte"
|
||||
import ConfirmationDisplay from "./overlay/ConfirmationDisplay.svelte"
|
||||
|
@ -47,11 +48,18 @@
|
|||
import SnippetsProvider from "./context/SnippetsProvider.svelte"
|
||||
import EmbedProvider from "./context/EmbedProvider.svelte"
|
||||
import DNDSelectionIndicators from "./preview/DNDSelectionIndicators.svelte"
|
||||
import { ActionTypes } from "@/constants"
|
||||
|
||||
// Provide contexts
|
||||
const context = createContextStore()
|
||||
setContext("sdk", SDK)
|
||||
setContext("component", writable({ id: null, ancestors: [] }))
|
||||
setContext("context", createContextStore())
|
||||
setContext("context", context)
|
||||
|
||||
// Seed context with an action to refresh all datasources
|
||||
context.actions.provideAction("all", ActionTypes.RefreshDatasource, () => {
|
||||
dataSourceStore.actions.refreshAll()
|
||||
})
|
||||
|
||||
let dataLoaded = false
|
||||
let permissionError = false
|
||||
|
|
|
@ -42,13 +42,15 @@
|
|||
const goToPortal = () => {
|
||||
window.location.href = isBuilder ? "/builder/portal/apps" : "/builder/apps"
|
||||
}
|
||||
|
||||
$: user = $authStore as User
|
||||
</script>
|
||||
|
||||
{#if $authStore}
|
||||
<ActionMenu align={compact ? "right" : "left"}>
|
||||
<svelte:fragment slot="control">
|
||||
<div class="container">
|
||||
<UserAvatar user={$authStore} size="M" showTooltip={false} />
|
||||
<UserAvatar {user} size="M" showTooltip={false} />
|
||||
{#if !compact}
|
||||
<div class="text">
|
||||
<div class="name">
|
||||
|
|
|
@ -115,9 +115,18 @@ export const createDataSourceStore = () => {
|
|||
})
|
||||
}
|
||||
|
||||
const refreshAll = () => {
|
||||
get(store).forEach(instance => instance.refresh())
|
||||
}
|
||||
|
||||
return {
|
||||
subscribe: store.subscribe,
|
||||
actions: { registerDataSource, unregisterInstance, invalidateDataSource },
|
||||
actions: {
|
||||
registerDataSource,
|
||||
unregisterInstance,
|
||||
invalidateDataSource,
|
||||
refreshAll,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
<script>
|
||||
<script lang="ts">
|
||||
import { Avatar, AbsTooltip, TooltipPosition } from "@budibase/bbui"
|
||||
import { helpers } from "@budibase/shared-core"
|
||||
import type { User } from "@budibase/types"
|
||||
|
||||
export let user
|
||||
export let size = "S"
|
||||
export let tooltipPosition = TooltipPosition.Top
|
||||
export let showTooltip = true
|
||||
export let user: User
|
||||
export let size: "XS" | "S" | "M" = "S"
|
||||
export let tooltipPosition: TooltipPosition = TooltipPosition.Top
|
||||
export let showTooltip: boolean = true
|
||||
</script>
|
||||
|
||||
{#if user}
|
||||
<AbsTooltip
|
||||
text={showTooltip ? helpers.getUserLabel(user) : null}
|
||||
text={showTooltip ? helpers.getUserLabel(user) : ""}
|
||||
position={tooltipPosition}
|
||||
color={helpers.getUserColor(user)}
|
||||
>
|
||||
|
|
|
@ -1,27 +1,31 @@
|
|||
<script>
|
||||
<script lang="ts">
|
||||
import { UserAvatar } from "@budibase/frontend-core"
|
||||
import { TooltipPosition, Avatar } from "@budibase/bbui"
|
||||
import type { UIUser } from "@budibase/types"
|
||||
|
||||
export let users = []
|
||||
export let order = "ltr"
|
||||
export let size = "S"
|
||||
export let tooltipPosition = TooltipPosition.Top
|
||||
type OrderType = "ltr" | "rtl"
|
||||
|
||||
$: uniqueUsers = unique(users, order)
|
||||
export let users: UIUser[] = []
|
||||
export let order: OrderType = "ltr"
|
||||
export let size: "XS" | "S" = "S"
|
||||
export let tooltipPosition: TooltipPosition = TooltipPosition.Top
|
||||
|
||||
$: uniqueUsers = unique(users)
|
||||
$: avatars = getAvatars(uniqueUsers, order)
|
||||
|
||||
const unique = users => {
|
||||
let uniqueUsers = {}
|
||||
users?.forEach(user => {
|
||||
const unique = (users: UIUser[]) => {
|
||||
const uniqueUsers: Record<string, UIUser> = {}
|
||||
users.forEach(user => {
|
||||
uniqueUsers[user.email] = user
|
||||
})
|
||||
return Object.values(uniqueUsers)
|
||||
}
|
||||
|
||||
const getAvatars = (users, order) => {
|
||||
const avatars = users.slice(0, 3)
|
||||
type Overflow = { _id: "overflow"; label: string }
|
||||
const getAvatars = (users: UIUser[], order: OrderType) => {
|
||||
const avatars: (Overflow | UIUser)[] = users.slice(0, 3)
|
||||
if (users.length > 3) {
|
||||
const overflow = {
|
||||
const overflow: Overflow = {
|
||||
_id: "overflow",
|
||||
label: `+${users.length - 3}`,
|
||||
}
|
||||
|
@ -31,17 +35,22 @@
|
|||
avatars.unshift(overflow)
|
||||
}
|
||||
}
|
||||
|
||||
return avatars.map((user, idx) => ({
|
||||
...user,
|
||||
zIndex: order === "ltr" ? idx : uniqueUsers.length - idx,
|
||||
}))
|
||||
}
|
||||
|
||||
function isUser(value: Overflow | UIUser): value is UIUser {
|
||||
return value._id !== "overflow"
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="avatars">
|
||||
{#each avatars as user}
|
||||
<span style="z-index:{user.zIndex};">
|
||||
{#if user._id === "overflow"}
|
||||
{#if !isUser(user)}
|
||||
<Avatar
|
||||
{size}
|
||||
initials={user.label}
|
||||
|
|
Loading…
Reference in New Issue