Merge branch 'develop' into correct-nginx-cors-changes
This commit is contained in:
commit
00c0ee0efa
10 changed files with 330 additions and 18 deletions
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": "2.10.12-alpha.11",
|
"version": "2.10.12-alpha.13",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"packages": [
|
"packages": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
|
|
|
@ -14,13 +14,14 @@
|
||||||
import GridManageAccessButton from "components/backend/DataTable/buttons/grid/GridManageAccessButton.svelte"
|
import GridManageAccessButton from "components/backend/DataTable/buttons/grid/GridManageAccessButton.svelte"
|
||||||
import GridRelationshipButton from "components/backend/DataTable/buttons/grid/GridRelationshipButton.svelte"
|
import GridRelationshipButton from "components/backend/DataTable/buttons/grid/GridRelationshipButton.svelte"
|
||||||
import GridEditColumnModal from "components/backend/DataTable/modals/grid/GridEditColumnModal.svelte"
|
import GridEditColumnModal from "components/backend/DataTable/modals/grid/GridEditColumnModal.svelte"
|
||||||
|
import GridUsersTableButton from "components/backend/DataTable/modals/grid/GridUsersTableButton.svelte"
|
||||||
|
|
||||||
const userSchemaOverrides = {
|
const userSchemaOverrides = {
|
||||||
firstName: { displayName: "First name", disabled: true },
|
firstName: { displayName: "First name" },
|
||||||
lastName: { displayName: "Last name", disabled: true },
|
lastName: { displayName: "Last name" },
|
||||||
email: { displayName: "Email", disabled: true },
|
email: { displayName: "Email" },
|
||||||
roleId: { displayName: "Role", disabled: true },
|
roleId: { displayName: "Role" },
|
||||||
status: { displayName: "Status", disabled: true },
|
status: { displayName: "Status" },
|
||||||
}
|
}
|
||||||
|
|
||||||
$: id = $tables.selected?._id
|
$: id = $tables.selected?._id
|
||||||
|
@ -59,22 +60,22 @@
|
||||||
datasource={gridDatasource}
|
datasource={gridDatasource}
|
||||||
canAddRows={!isUsersTable}
|
canAddRows={!isUsersTable}
|
||||||
canDeleteRows={!isUsersTable}
|
canDeleteRows={!isUsersTable}
|
||||||
|
canEditRows={!isUsersTable}
|
||||||
|
canEditColumns={!isUsersTable}
|
||||||
schemaOverrides={isUsersTable ? userSchemaOverrides : null}
|
schemaOverrides={isUsersTable ? userSchemaOverrides : null}
|
||||||
showAvatars={false}
|
showAvatars={false}
|
||||||
on:updatedatasource={handleGridTableUpdate}
|
on:updatedatasource={handleGridTableUpdate}
|
||||||
>
|
>
|
||||||
<svelte:fragment slot="filter">
|
<svelte:fragment slot="filter">
|
||||||
|
{#if isUsersTable}
|
||||||
|
<GridUsersTableButton />
|
||||||
|
{/if}
|
||||||
<GridFilterButton />
|
<GridFilterButton />
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<svelte:fragment slot="edit-column">
|
|
||||||
<GridEditColumnModal />
|
|
||||||
</svelte:fragment>
|
|
||||||
<svelte:fragment slot="add-column">
|
|
||||||
<GridAddColumnModal />
|
|
||||||
</svelte:fragment>
|
|
||||||
|
|
||||||
<svelte:fragment slot="controls">
|
<svelte:fragment slot="controls">
|
||||||
<GridCreateViewButton />
|
{#if !isUsersTable}
|
||||||
|
<GridCreateViewButton />
|
||||||
|
{/if}
|
||||||
<GridManageAccessButton />
|
<GridManageAccessButton />
|
||||||
{#if relationshipsEnabled}
|
{#if relationshipsEnabled}
|
||||||
<GridRelationshipButton />
|
<GridRelationshipButton />
|
||||||
|
@ -84,7 +85,6 @@
|
||||||
{:else}
|
{:else}
|
||||||
<GridImportButton />
|
<GridImportButton />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<GridExportButton />
|
<GridExportButton />
|
||||||
{#if isUsersTable}
|
{#if isUsersTable}
|
||||||
<GridEditUserModal />
|
<GridEditUserModal />
|
||||||
|
@ -92,6 +92,12 @@
|
||||||
<GridCreateEditRowModal />
|
<GridCreateEditRowModal />
|
||||||
{/if}
|
{/if}
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
|
<svelte:fragment slot="edit-column">
|
||||||
|
<GridEditColumnModal />
|
||||||
|
</svelte:fragment>
|
||||||
|
<svelte:fragment slot="add-column">
|
||||||
|
<GridAddColumnModal />
|
||||||
|
</svelte:fragment>
|
||||||
</Grid>
|
</Grid>
|
||||||
</div>
|
</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">
|
<div class="hierarchy-items-container">
|
||||||
<NavItem
|
<NavItem
|
||||||
icon="UserGroup"
|
icon="UserGroup"
|
||||||
text="Users"
|
text="App users"
|
||||||
selected={$isActive("./table/:tableId") &&
|
selected={$isActive("./table/:tableId") &&
|
||||||
$tables.selected?._id === TableNames.USERS}
|
$tables.selected?._id === TableNames.USERS}
|
||||||
on:click={() => selectTable(TableNames.USERS)}
|
on:click={() => selectTable(TableNames.USERS)}
|
||||||
|
|
|
@ -101,7 +101,7 @@
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-bottom: var(--border-light);
|
border-bottom: var(--border-light);
|
||||||
padding: 0 24px;
|
padding: 0 var(--spacing-l);
|
||||||
gap: 24px;
|
gap: 24px;
|
||||||
position: relative;
|
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 { onMount } from "svelte"
|
||||||
import { redirect } from "@roxi/routify"
|
import { redirect } from "@roxi/routify"
|
||||||
import { sdk } from "@budibase/shared-core"
|
import { sdk } from "@budibase/shared-core"
|
||||||
|
import PortalSideBar from "./_components/PortalSideBar.svelte"
|
||||||
|
|
||||||
// Don't block loading if we've already hydrated state
|
// Don't block loading if we've already hydrated state
|
||||||
let loaded = $apps.length != null
|
let loaded = $apps.length != null
|
||||||
|
@ -44,5 +45,18 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if loaded}
|
{#if loaded}
|
||||||
<slot />
|
<div class="page">
|
||||||
|
<PortalSideBar />
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
{/if}
|
{/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 { organisation } from "./organisation"
|
||||||
export { users } from "./users"
|
export { users } from "./users"
|
||||||
export { admin } from "./admin"
|
export { admin } from "./admin"
|
||||||
|
@ -14,3 +16,5 @@ export { environment } from "./environment"
|
||||||
export { menu } from "./menu"
|
export { menu } from "./menu"
|
||||||
export { auditLogs } from "./auditLogs"
|
export { auditLogs } from "./auditLogs"
|
||||||
export { features } from "./features"
|
export { features } from "./features"
|
||||||
|
|
||||||
|
export const sideBarCollapsed = writable(false)
|
||||||
|
|
Loading…
Reference in a new issue