Merge branch 'develop' into correct-nginx-cors-changes
This commit is contained in:
commit
00c0ee0efa
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "2.10.12-alpha.11",
|
||||
"version": "2.10.12-alpha.13",
|
||||
"npmClient": "yarn",
|
||||
"packages": [
|
||||
"packages/*"
|
||||
|
|
|
@ -14,13 +14,14 @@
|
|||
import GridManageAccessButton from "components/backend/DataTable/buttons/grid/GridManageAccessButton.svelte"
|
||||
import GridRelationshipButton from "components/backend/DataTable/buttons/grid/GridRelationshipButton.svelte"
|
||||
import GridEditColumnModal from "components/backend/DataTable/modals/grid/GridEditColumnModal.svelte"
|
||||
import GridUsersTableButton from "components/backend/DataTable/modals/grid/GridUsersTableButton.svelte"
|
||||
|
||||
const userSchemaOverrides = {
|
||||
firstName: { displayName: "First name", disabled: true },
|
||||
lastName: { displayName: "Last name", disabled: true },
|
||||
email: { displayName: "Email", disabled: true },
|
||||
roleId: { displayName: "Role", disabled: true },
|
||||
status: { displayName: "Status", disabled: true },
|
||||
firstName: { displayName: "First name" },
|
||||
lastName: { displayName: "Last name" },
|
||||
email: { displayName: "Email" },
|
||||
roleId: { displayName: "Role" },
|
||||
status: { displayName: "Status" },
|
||||
}
|
||||
|
||||
$: id = $tables.selected?._id
|
||||
|
@ -59,22 +60,22 @@
|
|||
datasource={gridDatasource}
|
||||
canAddRows={!isUsersTable}
|
||||
canDeleteRows={!isUsersTable}
|
||||
canEditRows={!isUsersTable}
|
||||
canEditColumns={!isUsersTable}
|
||||
schemaOverrides={isUsersTable ? userSchemaOverrides : null}
|
||||
showAvatars={false}
|
||||
on:updatedatasource={handleGridTableUpdate}
|
||||
>
|
||||
<svelte:fragment slot="filter">
|
||||
{#if isUsersTable}
|
||||
<GridUsersTableButton />
|
||||
{/if}
|
||||
<GridFilterButton />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="edit-column">
|
||||
<GridEditColumnModal />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="add-column">
|
||||
<GridAddColumnModal />
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="controls">
|
||||
<GridCreateViewButton />
|
||||
{#if !isUsersTable}
|
||||
<GridCreateViewButton />
|
||||
{/if}
|
||||
<GridManageAccessButton />
|
||||
{#if relationshipsEnabled}
|
||||
<GridRelationshipButton />
|
||||
|
@ -84,7 +85,6 @@
|
|||
{:else}
|
||||
<GridImportButton />
|
||||
{/if}
|
||||
|
||||
<GridExportButton />
|
||||
{#if isUsersTable}
|
||||
<GridEditUserModal />
|
||||
|
@ -92,6 +92,12 @@
|
|||
<GridCreateEditRowModal />
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="edit-column">
|
||||
<GridEditColumnModal />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="add-column">
|
||||
<GridAddColumnModal />
|
||||
</svelte:fragment>
|
||||
</Grid>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
<script>
|
||||
import { ActionButton, Popover, Heading, Body, Button } from "@budibase/bbui"
|
||||
import { store } from "builderStore"
|
||||
|
||||
let anchor
|
||||
let open = false
|
||||
|
||||
const openSidePanel = () => {
|
||||
store.update(state => ({
|
||||
...state,
|
||||
builderSidePanel: true,
|
||||
}))
|
||||
open = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<div bind:this={anchor}>
|
||||
<ActionButton on:click={() => (open = true)} icon="Help" quiet>
|
||||
Why can't I edit this table?
|
||||
</ActionButton>
|
||||
</div>
|
||||
|
||||
<Popover bind:open {anchor} align="left">
|
||||
<div class="content">
|
||||
<Heading size="XS">The app users table is read only</Heading>
|
||||
<Body size="S">
|
||||
You can continue to view the users that have access to your application.
|
||||
</Body>
|
||||
<Body size="S">
|
||||
Manage and invite more application users using the user side panel in the
|
||||
top right of your screen.
|
||||
</Body>
|
||||
<div class="button">
|
||||
<Button cta on:click={openSidePanel}>Open users panel</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Popover>
|
||||
|
||||
<style>
|
||||
.content {
|
||||
width: 300px;
|
||||
padding: var(--spacing-l);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-l);
|
||||
}
|
||||
.content :global(.spectrum-Heading) {
|
||||
font-weight: 400;
|
||||
}
|
||||
.button {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
|
@ -180,7 +180,7 @@
|
|||
<div class="hierarchy-items-container">
|
||||
<NavItem
|
||||
icon="UserGroup"
|
||||
text="Users"
|
||||
text="App users"
|
||||
selected={$isActive("./table/:tableId") &&
|
||||
$tables.selected?._id === TableNames.USERS}
|
||||
on:click={() => selectTable(TableNames.USERS)}
|
||||
|
|
|
@ -101,7 +101,7 @@
|
|||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
border-bottom: var(--border-light);
|
||||
padding: 0 24px;
|
||||
padding: 0 var(--spacing-l);
|
||||
gap: 24px;
|
||||
position: relative;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
<script>
|
||||
import { params, redirect } from "@roxi/routify"
|
||||
import { apps } from "stores/portal"
|
||||
|
||||
$: app = $apps.find(app => app.appId === $params.appId)
|
||||
$: {
|
||||
if (!app) {
|
||||
$redirect("../")
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if app}
|
||||
<slot />
|
||||
{/if}
|
|
@ -0,0 +1,79 @@
|
|||
<script>
|
||||
import { params, goto } from "@roxi/routify"
|
||||
import { apps, auth, sideBarCollapsed } from "stores/portal"
|
||||
import { ActionButton } from "@budibase/bbui"
|
||||
import { sdk } from "@budibase/shared-core"
|
||||
|
||||
$: app = $apps.find(app => app.appId === $params.appId)
|
||||
$: iframeUrl = getIframeURL(app)
|
||||
$: isBuilder = sdk.users.isBuilder($auth.user, app?.devId)
|
||||
|
||||
const getIframeURL = app => {
|
||||
if (app.status === "published") {
|
||||
return `/app${app.url}`
|
||||
}
|
||||
return `/${app.devId}`
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
{#if $sideBarCollapsed}
|
||||
<ActionButton
|
||||
quiet
|
||||
icon="Rail"
|
||||
on:click={() => sideBarCollapsed.set(false)}
|
||||
>
|
||||
Menu
|
||||
</ActionButton>
|
||||
{:else}
|
||||
<ActionButton
|
||||
quiet
|
||||
icon="RailRightOpen"
|
||||
on:click={() => sideBarCollapsed.set(true)}
|
||||
>
|
||||
Collapse
|
||||
</ActionButton>
|
||||
{/if}
|
||||
{#if isBuilder}
|
||||
<ActionButton
|
||||
quiet
|
||||
icon="Edit"
|
||||
on:click={() => $goto(`../../app/${app.devId}`)}
|
||||
>
|
||||
Edit
|
||||
</ActionButton>
|
||||
{/if}
|
||||
<ActionButton
|
||||
quiet
|
||||
icon="LinkOut"
|
||||
on:click={() => window.open(iframeUrl, "_blank")}
|
||||
>
|
||||
Fullscreen
|
||||
</ActionButton>
|
||||
</div>
|
||||
<iframe src={iframeUrl} title={app.name} />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
padding: 0 var(--spacing-l) var(--spacing-l) var(--spacing-l);
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: var(--spacing-xs);
|
||||
flex: 0 0 50px;
|
||||
}
|
||||
iframe {
|
||||
flex: 1 1 auto;
|
||||
border-radius: var(--spacing-s);
|
||||
border: 1px solid var(--spectrum-global-color-gray-300);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,140 @@
|
|||
<script>
|
||||
import { Icon, Body } from "@budibase/bbui"
|
||||
import { apps, sideBarCollapsed } from "stores/portal"
|
||||
import { params, goto } from "@roxi/routify"
|
||||
import { tick } from "svelte"
|
||||
import NavItem from "components/common/NavItem.svelte"
|
||||
|
||||
let searchInput
|
||||
let searchString
|
||||
let searching = false
|
||||
|
||||
$: filteredApps = $apps.filter(app => {
|
||||
return (
|
||||
!searchString ||
|
||||
app.name.toLowerCase().includes(searchString.toLowerCase())
|
||||
)
|
||||
})
|
||||
|
||||
const startSearching = async () => {
|
||||
searching = true
|
||||
searchString = ""
|
||||
await tick()
|
||||
searchInput.focus()
|
||||
}
|
||||
|
||||
const stopSearching = () => {
|
||||
searching = false
|
||||
searchString = ""
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="side-bar" class:collapsed={$sideBarCollapsed}>
|
||||
<div class="side-bar-controls">
|
||||
{#if searching}
|
||||
<input
|
||||
bind:this={searchInput}
|
||||
bind:value={searchString}
|
||||
placeholder="Search for apps"
|
||||
/>
|
||||
{:else}
|
||||
<Body size="S">Apps</Body>
|
||||
<Icon name="Search" size="S" hoverable on:click={startSearching} />
|
||||
{/if}
|
||||
<div class="rotational" class:rotated={searching}>
|
||||
<Icon
|
||||
name="Add"
|
||||
hoverable
|
||||
on:click={searching ? stopSearching : () => $goto("./create")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="side-bar-nav">
|
||||
<NavItem
|
||||
icon="WebPages"
|
||||
text="All apps"
|
||||
on:click={() => $goto("./")}
|
||||
selected={!$params.appId}
|
||||
/>
|
||||
{#each filteredApps as app}
|
||||
<NavItem
|
||||
text={app.name}
|
||||
icon={app.icon?.name || "Apps"}
|
||||
iconColor={app.icon?.color}
|
||||
selected={$params.appId === app.appId}
|
||||
on:click={() => $goto(`./${app.appId}`)}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.side-bar {
|
||||
flex: 0 0 260px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
border-right: var(--border-light);
|
||||
background: var(--spectrum-global-color-gray-100);
|
||||
overflow: hidden;
|
||||
transition: margin-left 300ms ease-out;
|
||||
}
|
||||
.side-bar.collapsed {
|
||||
margin-left: -262px;
|
||||
}
|
||||
@media (max-width: 640px) {
|
||||
.side-bar {
|
||||
margin-left: -262px;
|
||||
}
|
||||
}
|
||||
|
||||
.side-bar-controls {
|
||||
flex: 0 0 50px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: var(--spacing-l);
|
||||
padding: 0 var(--spacing-l);
|
||||
}
|
||||
.side-bar-controls :global(.spectrum-Body),
|
||||
.side-bar-controls input {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.side-bar-controls :global(.spectrum-Icon) {
|
||||
color: var(--spectrum-global-color-gray-700);
|
||||
}
|
||||
|
||||
input {
|
||||
outline: none;
|
||||
border: none;
|
||||
max-width: none;
|
||||
flex: 1 1 auto;
|
||||
color: var(--spectrum-global-color-gray-800);
|
||||
font-size: 14px;
|
||||
padding: 0;
|
||||
transition: border 130ms ease-out;
|
||||
font-family: var(--font-sans);
|
||||
background: inherit;
|
||||
}
|
||||
input::placeholder {
|
||||
color: var(--spectrum-global-color-gray-700);
|
||||
transition: color 130ms ease-out;
|
||||
}
|
||||
input:hover::placeholder {
|
||||
color: var(--spectrum-global-color-gray-800);
|
||||
}
|
||||
|
||||
.side-bar-nav {
|
||||
flex: 1 1 auto;
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
div.rotational {
|
||||
transition: transform 130ms ease-out;
|
||||
}
|
||||
div.rotational.rotated {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
</style>
|
|
@ -11,6 +11,7 @@
|
|||
import { onMount } from "svelte"
|
||||
import { redirect } from "@roxi/routify"
|
||||
import { sdk } from "@budibase/shared-core"
|
||||
import PortalSideBar from "./_components/PortalSideBar.svelte"
|
||||
|
||||
// Don't block loading if we've already hydrated state
|
||||
let loaded = $apps.length != null
|
||||
|
@ -44,5 +45,18 @@
|
|||
</script>
|
||||
|
||||
{#if loaded}
|
||||
<slot />
|
||||
<div class="page">
|
||||
<PortalSideBar />
|
||||
<slot />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.page {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { writable } from "svelte/store"
|
||||
|
||||
export { organisation } from "./organisation"
|
||||
export { users } from "./users"
|
||||
export { admin } from "./admin"
|
||||
|
@ -14,3 +16,5 @@ export { environment } from "./environment"
|
|||
export { menu } from "./menu"
|
||||
export { auditLogs } from "./auditLogs"
|
||||
export { features } from "./features"
|
||||
|
||||
export const sideBarCollapsed = writable(false)
|
||||
|
|
Loading…
Reference in New Issue