Add initial new UI for views
This commit is contained in:
parent
0109fce51d
commit
fa80d99139
|
@ -57,7 +57,6 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="wrapper">
|
|
||||||
<Grid
|
<Grid
|
||||||
{API}
|
{API}
|
||||||
{darkMode}
|
{darkMode}
|
||||||
|
@ -107,14 +106,3 @@
|
||||||
<GridAddColumnModal />
|
<GridAddColumnModal />
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</Grid>
|
</Grid>
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.wrapper {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
margin: -28px -40px -40px -40px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
background: var(--background);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="wrapper">
|
|
||||||
<Grid
|
<Grid
|
||||||
{API}
|
{API}
|
||||||
{datasource}
|
{datasource}
|
||||||
|
@ -38,15 +37,3 @@
|
||||||
<GridManageAccessButton />
|
<GridManageAccessButton />
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</Grid>
|
</Grid>
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.wrapper {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
margin: -28px -40px -40px -40px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
background: var(--background);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -104,7 +104,7 @@
|
||||||
</InlineAlert>
|
</InlineAlert>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<p class="fourthWarning">Please enter the app name below to confirm.</p>
|
<p class="fourthWarning">Please enter the table name below to confirm.</p>
|
||||||
<Input bind:value={deleteTableName} placeholder={table.name} />
|
<Input bind:value={deleteTableName} placeholder={table.name} />
|
||||||
</div>
|
</div>
|
||||||
</ConfirmDialog>
|
</ConfirmDialog>
|
||||||
|
|
|
@ -20,14 +20,6 @@
|
||||||
|
|
||||||
const getContextMenuItems = () => {
|
const getContextMenuItems = () => {
|
||||||
return [
|
return [
|
||||||
{
|
|
||||||
icon: "Delete",
|
|
||||||
name: "Delete",
|
|
||||||
keyBind: null,
|
|
||||||
visible: true,
|
|
||||||
disabled: false,
|
|
||||||
callback: deleteConfirmationModal.show,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
icon: "Edit",
|
icon: "Edit",
|
||||||
name: "Edit",
|
name: "Edit",
|
||||||
|
@ -36,6 +28,14 @@
|
||||||
disabled: false,
|
disabled: false,
|
||||||
callback: editModal.show,
|
callback: editModal.show,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
icon: "Delete",
|
||||||
|
name: "Delete",
|
||||||
|
keyBind: null,
|
||||||
|
visible: true,
|
||||||
|
disabled: false,
|
||||||
|
callback: deleteConfirmationModal.show,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { goto } from "@roxi/routify"
|
|
||||||
import TableNavItem from "./TableNavItem/TableNavItem.svelte"
|
import TableNavItem from "./TableNavItem/TableNavItem.svelte"
|
||||||
import ViewNavItem from "./ViewNavItem/ViewNavItem.svelte"
|
|
||||||
|
|
||||||
export let tables
|
export let tables
|
||||||
export let selectTable
|
export let selectTable
|
||||||
|
@ -16,18 +14,5 @@
|
||||||
<div class="hierarchy-items-container">
|
<div class="hierarchy-items-container">
|
||||||
{#each sortedTables as table, idx}
|
{#each sortedTables as table, idx}
|
||||||
<TableNavItem {table} {idx} on:click={() => selectTable(table._id)} />
|
<TableNavItem {table} {idx} on:click={() => selectTable(table._id)} />
|
||||||
{#each [...Object.entries(table.views || {})].sort() as [name, view], idx (idx)}
|
|
||||||
<ViewNavItem
|
|
||||||
{view}
|
|
||||||
{name}
|
|
||||||
on:click={() => {
|
|
||||||
if (view.version === 2) {
|
|
||||||
$goto(`./view/v2/${encodeURIComponent(view.id)}`)
|
|
||||||
} else {
|
|
||||||
$goto(`./view/v1/${encodeURIComponent(name)}`)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{/each}
|
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
<script>
|
|
||||||
import {
|
|
||||||
contextMenuStore,
|
|
||||||
views,
|
|
||||||
viewsV2,
|
|
||||||
userSelectedResourceMap,
|
|
||||||
} from "stores/builder"
|
|
||||||
import NavItem from "components/common/NavItem.svelte"
|
|
||||||
import { isActive } from "@roxi/routify"
|
|
||||||
import { Icon } from "@budibase/bbui"
|
|
||||||
import EditViewModal from "./EditViewModal.svelte"
|
|
||||||
import DeleteConfirmationModal from "./DeleteConfirmationModal.svelte"
|
|
||||||
|
|
||||||
export let view
|
|
||||||
export let name
|
|
||||||
|
|
||||||
let editModal
|
|
||||||
let deleteConfirmationModal
|
|
||||||
|
|
||||||
const getContextMenuItems = () => {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
icon: "Delete",
|
|
||||||
name: "Delete",
|
|
||||||
keyBind: null,
|
|
||||||
visible: true,
|
|
||||||
disabled: false,
|
|
||||||
callback: deleteConfirmationModal.show,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: "Edit",
|
|
||||||
name: "Edit",
|
|
||||||
keyBind: null,
|
|
||||||
visible: true,
|
|
||||||
disabled: false,
|
|
||||||
callback: editModal.show,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
const openContextMenu = e => {
|
|
||||||
e.preventDefault()
|
|
||||||
e.stopPropagation()
|
|
||||||
|
|
||||||
const items = getContextMenuItems()
|
|
||||||
contextMenuStore.open(view.id, items, { x: e.clientX, y: e.clientY })
|
|
||||||
}
|
|
||||||
|
|
||||||
const isViewActive = (view, isActive, views, viewsV2) => {
|
|
||||||
return (
|
|
||||||
(isActive("./view/v1") && views.selected?.name === view.name) ||
|
|
||||||
(isActive("./view/v2") && viewsV2.selected?.id === view.id)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<NavItem
|
|
||||||
on:contextmenu={openContextMenu}
|
|
||||||
indentLevel={2}
|
|
||||||
icon="Remove"
|
|
||||||
text={name}
|
|
||||||
selected={isViewActive(view, $isActive, $views, $viewsV2)}
|
|
||||||
hovering={view.id === $contextMenuStore.id}
|
|
||||||
on:click
|
|
||||||
selectedBy={$userSelectedResourceMap[name] ||
|
|
||||||
$userSelectedResourceMap[view.id]}
|
|
||||||
>
|
|
||||||
<Icon on:click={openContextMenu} s hoverable name="MoreSmallList" />
|
|
||||||
</NavItem>
|
|
||||||
<EditViewModal {view} bind:this={editModal} />
|
|
||||||
<DeleteConfirmationModal {view} bind:this={deleteConfirmationModal} />
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
<script>
|
||||||
|
import { viewsV2, builderStore } from "stores/builder"
|
||||||
|
import { syncURLToState } from "helpers/urlStateSync"
|
||||||
|
import * as routify from "@roxi/routify"
|
||||||
|
import { onDestroy } from "svelte"
|
||||||
|
|
||||||
|
$: id = $viewsV2.selectedViewId
|
||||||
|
$: builderStore.selectResource(id)
|
||||||
|
|
||||||
|
const stopSyncing = syncURLToState({
|
||||||
|
urlParam: "viewId",
|
||||||
|
stateKey: "selectedViewId",
|
||||||
|
validate: id => $viewsV2.list?.some(view => view.id === id),
|
||||||
|
update: viewsV2.select,
|
||||||
|
fallbackUrl: "../",
|
||||||
|
store: viewsV2,
|
||||||
|
routify,
|
||||||
|
decode: decodeURIComponent,
|
||||||
|
})
|
||||||
|
|
||||||
|
onDestroy(stopSyncing)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<slot />
|
|
@ -0,0 +1,5 @@
|
||||||
|
<script>
|
||||||
|
import ViewV2DataTable from "components/backend/DataTable/ViewV2DataTable.svelte"
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ViewV2DataTable />
|
|
@ -0,0 +1,200 @@
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
tables,
|
||||||
|
datasources,
|
||||||
|
userSelectedResourceMap,
|
||||||
|
contextMenuStore,
|
||||||
|
} from "stores/builder"
|
||||||
|
import IntegrationIcon from "components/backend/DatasourceNavigator/IntegrationIcon.svelte"
|
||||||
|
import { Icon } from "@budibase/bbui"
|
||||||
|
import { params, url } from "@roxi/routify"
|
||||||
|
import EditViewModal from "./EditViewModal.svelte"
|
||||||
|
import DeleteViewModal from "./DeleteViewModal.svelte"
|
||||||
|
import EditTableModal from "components/backend/TableNavigator/TableNavItem/EditModal.svelte"
|
||||||
|
import DeleteTableModal from "components/backend/TableNavigator/TableNavItem/DeleteConfirmationModal.svelte"
|
||||||
|
import { UserAvatars } from "@budibase/frontend-core"
|
||||||
|
import { tick } from "svelte"
|
||||||
|
import { DB_TYPE_EXTERNAL } from "constants/backend"
|
||||||
|
import { TableNames } from "constants"
|
||||||
|
|
||||||
|
// Editing table
|
||||||
|
let editTableModal
|
||||||
|
let deleteTableModal
|
||||||
|
|
||||||
|
// Editing views
|
||||||
|
let editableView
|
||||||
|
let editViewModal
|
||||||
|
let deleteViewModal
|
||||||
|
|
||||||
|
$: tableId = $params.tableId
|
||||||
|
$: table = $tables.list.find(x => x._id === tableId)
|
||||||
|
$: datasource = $datasources.list.find(x => x._id === table?.sourceId)
|
||||||
|
$: tableSelectedBy = $userSelectedResourceMap[table?._id]
|
||||||
|
$: tableEditable = table?._id !== TableNames.USERS
|
||||||
|
$: activeId = $params.viewId ?? $params.tableId
|
||||||
|
$: views = Object.values(table?.views || {})
|
||||||
|
.filter(x => x.version === 2)
|
||||||
|
.slice()
|
||||||
|
.sort(alphabetical)
|
||||||
|
|
||||||
|
const openTableContextMenu = e => {
|
||||||
|
if (!tableEditable) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
contextMenuStore.open(
|
||||||
|
table._id,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
icon: "Edit",
|
||||||
|
name: "Edit",
|
||||||
|
keyBind: null,
|
||||||
|
visible: table?.sourceType !== DB_TYPE_EXTERNAL,
|
||||||
|
disabled: false,
|
||||||
|
callback: editTableModal?.show,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "Delete",
|
||||||
|
name: "Delete",
|
||||||
|
keyBind: null,
|
||||||
|
visible: true,
|
||||||
|
disabled: false,
|
||||||
|
callback: deleteTableModal?.show,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{
|
||||||
|
x: e.clientX,
|
||||||
|
y: e.clientY,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const openViewContextMenu = async (e, view) => {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
editableView = view
|
||||||
|
await tick()
|
||||||
|
contextMenuStore.open(
|
||||||
|
view.id,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
icon: "Edit",
|
||||||
|
name: "Edit",
|
||||||
|
keyBind: null,
|
||||||
|
visible: true,
|
||||||
|
disabled: false,
|
||||||
|
callback: editViewModal?.show,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "Delete",
|
||||||
|
name: "Delete",
|
||||||
|
keyBind: null,
|
||||||
|
visible: true,
|
||||||
|
disabled: false,
|
||||||
|
callback: deleteViewModal?.show,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{
|
||||||
|
x: e.clientX,
|
||||||
|
y: e.clientY,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const alphabetical = (a, b) => {
|
||||||
|
return a.name < b.name ? -1 : 1
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="view-nav-bar">
|
||||||
|
<IntegrationIcon
|
||||||
|
integrationType={datasource.source}
|
||||||
|
schema={datasource.schema}
|
||||||
|
size="24"
|
||||||
|
/>
|
||||||
|
<a
|
||||||
|
href={$url(`../${tableId}`)}
|
||||||
|
class="nav-bar-item"
|
||||||
|
class:active={tableId === activeId}
|
||||||
|
on:contextmenu={openTableContextMenu}
|
||||||
|
>
|
||||||
|
<div class="title">
|
||||||
|
{table.name}
|
||||||
|
</div>
|
||||||
|
{#if tableSelectedBy}
|
||||||
|
<UserAvatars size="XS" users={tableSelectedBy} />
|
||||||
|
{/if}
|
||||||
|
{#if tableEditable}
|
||||||
|
<Icon on:click={openTableContextMenu} s hoverable name="MoreSmallList" />
|
||||||
|
{/if}
|
||||||
|
</a>
|
||||||
|
{#each views as view (view.id)}
|
||||||
|
{@const selectedBy = $userSelectedResourceMap[view.id]}
|
||||||
|
<a
|
||||||
|
href={$url(`../${tableId}/${encodeURIComponent(view.id)}`)}
|
||||||
|
class="nav-bar-item"
|
||||||
|
class:active={view.id === activeId}
|
||||||
|
on:contextmenu={e => openViewContextMenu(e, view)}
|
||||||
|
>
|
||||||
|
<div class="title">
|
||||||
|
{view.name}
|
||||||
|
</div>
|
||||||
|
{#if selectedBy}
|
||||||
|
<UserAvatars size="XS" users={selectedBy} />
|
||||||
|
{/if}
|
||||||
|
<Icon
|
||||||
|
on:click={e => openViewContextMenu(e, view)}
|
||||||
|
s
|
||||||
|
hoverable
|
||||||
|
name="MoreSmallList"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if table}
|
||||||
|
<EditTableModal {table} bind:this={editTableModal} />
|
||||||
|
<DeleteTableModal {table} bind:this={deleteTableModal} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if editableView}
|
||||||
|
<EditViewModal view={editableView} bind:this={editViewModal} />
|
||||||
|
<DeleteViewModal view={editableView} bind:this={deleteViewModal} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.view-nav-bar {
|
||||||
|
height: 50px;
|
||||||
|
border-bottom: var(--border-light);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 var(--spacing-xl);
|
||||||
|
gap: var(--spacing-m);
|
||||||
|
}
|
||||||
|
.nav-bar-item {
|
||||||
|
padding: 6px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--spacing-m);
|
||||||
|
transition: background 130ms ease-out, color 130ms ease-out;
|
||||||
|
color: var(--spectrum-global-color-gray-700);
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.nav-bar-item.active,
|
||||||
|
.nav-bar-item:hover {
|
||||||
|
color: var(--spectrum-global-color-gray-900);
|
||||||
|
background: var(--spectrum-global-color-gray-300);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.nav-bar-item:not(.active) :global(.icon) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -3,6 +3,7 @@
|
||||||
import { tables, builderStore } from "stores/builder"
|
import { tables, builderStore } from "stores/builder"
|
||||||
import * as routify from "@roxi/routify"
|
import * as routify from "@roxi/routify"
|
||||||
import { onDestroy } from "svelte"
|
import { onDestroy } from "svelte"
|
||||||
|
import ViewNavBar from "./_components/ViewNavBar.svelte"
|
||||||
|
|
||||||
$: tableId = $tables.selectedTableId
|
$: tableId = $tables.selectedTableId
|
||||||
$: builderStore.selectResource(tableId)
|
$: builderStore.selectResource(tableId)
|
||||||
|
@ -20,4 +21,17 @@
|
||||||
onDestroy(stopSyncing)
|
onDestroy(stopSyncing)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<div class="wrapper">
|
||||||
|
<ViewNavBar />
|
||||||
<slot />
|
<slot />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.wrapper {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
margin: -28px -40px -40px -40px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: var(--background);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
<script>
|
||||||
|
import { onMount } from "svelte"
|
||||||
|
import { views, viewsV2 } from "stores/builder"
|
||||||
|
import { redirect } from "@roxi/routify"
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
if ($viewsV2.selected) {
|
||||||
|
$redirect(`./v2/${$viewsV2.selected.id}`)
|
||||||
|
} else if ($viewsV2.list?.length) {
|
||||||
|
$redirect(`./v2/${$viewsV2.list[0].id}`)
|
||||||
|
} else if ($views.selected) {
|
||||||
|
$redirect(`./${encodeURIComponent($views.selected?.name)}`)
|
||||||
|
} else if ($views.list?.length) {
|
||||||
|
$redirect(`./${encodeURIComponent($views.list[0].name)}`)
|
||||||
|
} else {
|
||||||
|
$redirect("../")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
|
@ -0,0 +1,24 @@
|
||||||
|
<script>
|
||||||
|
import { views, builderStore } from "stores/builder"
|
||||||
|
import { syncURLToState } from "helpers/urlStateSync"
|
||||||
|
import * as routify from "@roxi/routify"
|
||||||
|
import { onDestroy } from "svelte"
|
||||||
|
|
||||||
|
$: name = $views.selectedViewName
|
||||||
|
$: builderStore.selectResource(name)
|
||||||
|
|
||||||
|
const stopSyncing = syncURLToState({
|
||||||
|
urlParam: "viewName",
|
||||||
|
stateKey: "selectedViewName",
|
||||||
|
validate: name => $views.list?.some(view => view.name === name),
|
||||||
|
update: views.select,
|
||||||
|
fallbackUrl: "../../",
|
||||||
|
store: views,
|
||||||
|
routify,
|
||||||
|
decode: decodeURIComponent,
|
||||||
|
})
|
||||||
|
|
||||||
|
onDestroy(stopSyncing)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<slot />
|
|
@ -0,0 +1,18 @@
|
||||||
|
<script>
|
||||||
|
import ViewDataTable from "components/backend/DataTable/ViewDataTable.svelte"
|
||||||
|
import { views } from "stores/builder"
|
||||||
|
|
||||||
|
$: selectedView = $views.selected
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if selectedView}
|
||||||
|
<ViewDataTable view={selectedView} />
|
||||||
|
{:else}<i>Create your first table to start building</i>{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
i {
|
||||||
|
font-size: var(--font-size-m);
|
||||||
|
color: var(--grey-4);
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<script>
|
||||||
|
import { redirect } from "@roxi/routify"
|
||||||
|
|
||||||
|
$redirect("../")
|
||||||
|
</script>
|
Loading…
Reference in New Issue