Allow expanding rows using existing edit row modal
This commit is contained in:
parent
5640b2fa89
commit
7570c52879
8 changed files with 109 additions and 71 deletions
|
@ -23,9 +23,9 @@
|
||||||
async function saveRow() {
|
async function saveRow() {
|
||||||
errors = []
|
errors = []
|
||||||
try {
|
try {
|
||||||
await API.saveRow({ ...row, tableId: table._id })
|
const res = await API.saveRow({ ...row, tableId: table._id })
|
||||||
notifications.success("Row saved successfully")
|
notifications.success("Row saved successfully")
|
||||||
dispatch("updaterows")
|
dispatch("updaterows", res._id)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.handled) {
|
if (error.handled) {
|
||||||
const response = error.json
|
const response = error.json
|
||||||
|
|
|
@ -2,13 +2,27 @@
|
||||||
import CreateEditRow from "../../modals/CreateEditRow.svelte"
|
import CreateEditRow from "../../modals/CreateEditRow.svelte"
|
||||||
import { getContext, onMount } from "svelte"
|
import { getContext, onMount } from "svelte"
|
||||||
import { Modal } from "@budibase/bbui"
|
import { Modal } from "@budibase/bbui"
|
||||||
|
import { cloneDeep } from "lodash/fp"
|
||||||
|
|
||||||
const { subscribe } = getContext("sheet")
|
const { subscribe, rows } = getContext("sheet")
|
||||||
|
|
||||||
let modal
|
let modal
|
||||||
onMount(() => subscribe("add-row", modal.show))
|
let row
|
||||||
|
|
||||||
|
onMount(() =>
|
||||||
|
subscribe("add-row", () => {
|
||||||
|
row = {}
|
||||||
|
modal.show()
|
||||||
|
})
|
||||||
|
)
|
||||||
|
onMount(() =>
|
||||||
|
subscribe("edit-row", rowToEdit => {
|
||||||
|
row = cloneDeep(rowToEdit)
|
||||||
|
modal.show()
|
||||||
|
})
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Modal bind:this={modal}>
|
<Modal bind:this={modal}>
|
||||||
<CreateEditRow />
|
<CreateEditRow {row} on:updaterows={e => rows.actions.refreshRow(e.detail)} />
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
import { clickOutside } from "@budibase/bbui"
|
import { clickOutside } from "@budibase/bbui"
|
||||||
import AddRowButton from "../controls/AddRowButton.svelte"
|
import AddRowButton from "../controls/AddRowButton.svelte"
|
||||||
import SheetControls from "./SheetControls.svelte"
|
import SheetControls from "./SheetControls.svelte"
|
||||||
import SidePanel from "./SidePanel.svelte"
|
|
||||||
|
|
||||||
export let API
|
export let API
|
||||||
export let tableId
|
export let tableId
|
||||||
|
@ -35,19 +34,21 @@
|
||||||
export let allowSelectRows = true
|
export let allowSelectRows = true
|
||||||
export let allowAddColumns = true
|
export let allowAddColumns = true
|
||||||
export let allowEditColumns = true
|
export let allowEditColumns = true
|
||||||
|
export let allowExpandRows = true
|
||||||
|
|
||||||
// Sheet constants
|
// Sheet constants
|
||||||
const cellHeight = 36
|
const cellHeight = 36
|
||||||
const gutterWidth = 80
|
const gutterWidth = 72
|
||||||
const rand = Math.random()
|
const rand = Math.random()
|
||||||
|
|
||||||
// State stores
|
// State stores
|
||||||
|
const tableIdStore = writable(tableId)
|
||||||
const config = writable({
|
const config = writable({
|
||||||
tableId,
|
|
||||||
allowAddRows,
|
allowAddRows,
|
||||||
allowSelectRows,
|
allowSelectRows,
|
||||||
allowAddColumns,
|
allowAddColumns,
|
||||||
allowEditColumns,
|
allowEditColumns,
|
||||||
|
allowExpandRows,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Build up spreadsheet context
|
// Build up spreadsheet context
|
||||||
|
@ -58,6 +59,7 @@
|
||||||
cellHeight,
|
cellHeight,
|
||||||
gutterWidth,
|
gutterWidth,
|
||||||
config,
|
config,
|
||||||
|
tableId: tableIdStore,
|
||||||
}
|
}
|
||||||
context = { ...context, ...createEventManagers() }
|
context = { ...context, ...createEventManagers() }
|
||||||
context = { ...context, ...createBoundsStores(context) }
|
context = { ...context, ...createBoundsStores(context) }
|
||||||
|
@ -76,13 +78,14 @@
|
||||||
// Reference some stores for local use
|
// Reference some stores for local use
|
||||||
const { isResizing, isReordering, ui, loaded } = context
|
const { isResizing, isReordering, ui, loaded } = context
|
||||||
|
|
||||||
// Keep config store up to date
|
// Keep stores up to date
|
||||||
|
$: tableIdStore.set(tableId)
|
||||||
$: config.set({
|
$: config.set({
|
||||||
tableId,
|
|
||||||
allowAddRows,
|
allowAddRows,
|
||||||
allowSelectRows,
|
allowSelectRows,
|
||||||
allowAddColumns,
|
allowAddColumns,
|
||||||
allowEditColumns,
|
allowEditColumns,
|
||||||
|
allowExpandRows,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Set context for children to consume
|
// Set context for children to consume
|
||||||
|
@ -127,7 +130,6 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<SidePanel />
|
|
||||||
<KeyboardManager />
|
<KeyboardManager />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
<script>
|
|
||||||
import { getContext } from "svelte"
|
|
||||||
|
|
||||||
const { sidePanelRowId } = getContext("sheet")
|
|
||||||
|
|
||||||
$: visible = $sidePanelRowId != null
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="side-panel" class:visible>some content</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.side-panel {
|
|
||||||
width: 320px;
|
|
||||||
transform: translateX(100%);
|
|
||||||
transition: transform 130ms ease-out;
|
|
||||||
}
|
|
||||||
.side-panel.visible {
|
|
||||||
transform: translateX(0);
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext } from "svelte"
|
import { getContext } from "svelte"
|
||||||
import { Checkbox } from "@budibase/bbui"
|
import { Checkbox, Icon } from "@budibase/bbui"
|
||||||
import SheetCell from "../cells/SheetCell.svelte"
|
import SheetCell from "../cells/SheetCell.svelte"
|
||||||
import DataCell from "../cells/DataCell.svelte"
|
import DataCell from "../cells/DataCell.svelte"
|
||||||
import SheetScrollWrapper from "./SheetScrollWrapper.svelte"
|
import SheetScrollWrapper from "./SheetScrollWrapper.svelte"
|
||||||
|
@ -19,6 +19,7 @@
|
||||||
selectedCellMap,
|
selectedCellMap,
|
||||||
selectedCellRow,
|
selectedCellRow,
|
||||||
gutterWidth,
|
gutterWidth,
|
||||||
|
dispatch,
|
||||||
} = getContext("sheet")
|
} = getContext("sheet")
|
||||||
|
|
||||||
$: scrollLeft = $scroll.left
|
$: scrollLeft = $scroll.left
|
||||||
|
@ -59,17 +60,24 @@
|
||||||
class:scrolled={scrollLeft > 0}
|
class:scrolled={scrollLeft > 0}
|
||||||
>
|
>
|
||||||
<div class="header row">
|
<div class="header row">
|
||||||
<SheetCell
|
<SheetCell width={gutterWidth}>
|
||||||
width={gutterWidth}
|
<div class="gutter">
|
||||||
on:click={$config.allowSelectRows && selectAll}
|
<div class="checkbox visible">
|
||||||
center
|
{#if $config.allowSelectRows}
|
||||||
>
|
<div on:click={$config.allowSelectRows && selectAll}>
|
||||||
{#if $config.allowSelectRows}
|
<Checkbox
|
||||||
<Checkbox
|
value={rowCount && selectedRowCount === rowCount}
|
||||||
value={rowCount && selectedRowCount === rowCount}
|
disabled={!$renderedRows.length}
|
||||||
disabled={!$renderedRows.length}
|
/>
|
||||||
/>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
</div>
|
||||||
|
{#if $config.allowExpandRows}
|
||||||
|
<div class="expand">
|
||||||
|
<Icon name="Maximize" size="S" />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
</SheetCell>
|
</SheetCell>
|
||||||
|
|
||||||
{#if $stickyColumn}
|
{#if $stickyColumn}
|
||||||
|
@ -89,25 +97,41 @@
|
||||||
on:mouseleave={() => ($hoveredRowId = null)}
|
on:mouseleave={() => ($hoveredRowId = null)}
|
||||||
>
|
>
|
||||||
<SheetCell
|
<SheetCell
|
||||||
|
width={gutterWidth}
|
||||||
rowSelected={rowSelected || containsSelectedRow}
|
rowSelected={rowSelected || containsSelectedRow}
|
||||||
{rowHovered}
|
{rowHovered}
|
||||||
width={gutterWidth}
|
|
||||||
center
|
|
||||||
>
|
>
|
||||||
<div
|
<div class="gutter">
|
||||||
on:click={() => selectRow(row._id)}
|
<div
|
||||||
class="checkbox"
|
on:click={() => selectRow(row._id)}
|
||||||
class:visible={$config.allowSelectRows &&
|
class="checkbox"
|
||||||
(rowSelected || rowHovered)}
|
class:visible={$config.allowSelectRows &&
|
||||||
>
|
(rowSelected || rowHovered || containsSelectedRow)}
|
||||||
<Checkbox value={rowSelected} />
|
>
|
||||||
</div>
|
<Checkbox value={rowSelected} />
|
||||||
<div
|
</div>
|
||||||
class="number"
|
<div
|
||||||
class:visible={!$config.allowSelectRows ||
|
class="number"
|
||||||
!(rowSelected || rowHovered)}
|
class:visible={!$config.allowSelectRows ||
|
||||||
>
|
!(rowSelected || rowHovered || containsSelectedRow)}
|
||||||
{row.__idx + 1}
|
>
|
||||||
|
{row.__idx + 1}
|
||||||
|
</div>
|
||||||
|
{#if $config.allowExpandRows}
|
||||||
|
<div
|
||||||
|
class="expand"
|
||||||
|
class:visible={containsSelectedRow || rowHovered}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
name="Maximize"
|
||||||
|
hoverable
|
||||||
|
size="S"
|
||||||
|
on:click={() => {
|
||||||
|
dispatch("edit-row", row)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</SheetCell>
|
</SheetCell>
|
||||||
|
|
||||||
|
@ -172,20 +196,35 @@
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Styles for label cell */
|
/* Styles for gutter */
|
||||||
|
.gutter {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
display: grid;
|
||||||
|
align-items: center;
|
||||||
|
padding: var(--cell-padding);
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
gap: var(--cell-spacing);
|
||||||
|
}
|
||||||
.checkbox,
|
.checkbox,
|
||||||
.number {
|
.number {
|
||||||
padding: 0 var(--cell-padding);
|
|
||||||
}
|
|
||||||
.checkbox {
|
|
||||||
display: none;
|
display: none;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
.number {
|
.number {
|
||||||
display: none;
|
|
||||||
color: var(--spectrum-global-color-gray-500);
|
color: var(--spectrum-global-color-gray-500);
|
||||||
}
|
}
|
||||||
.checkbox.visible,
|
.checkbox.visible,
|
||||||
.number.visible {
|
.number.visible {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
.expand {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.expand.visible {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: all;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import { derived, get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
import { io } from "socket.io-client"
|
import { io } from "socket.io-client"
|
||||||
|
|
||||||
export const createWebsocket = context => {
|
export const createWebsocket = context => {
|
||||||
const { rows, config, users, userId, selectedCellId } = context
|
const { rows, tableId, users, userId, selectedCellId } = context
|
||||||
const tableId = derived(config, $config => $config.tableId)
|
|
||||||
|
|
||||||
// Determine connection info
|
// Determine connection info
|
||||||
const tls = location.protocol === "https:"
|
const tls = location.protocol === "https:"
|
||||||
|
|
|
@ -3,8 +3,7 @@ import { fetchData } from "../../../fetch/fetchData"
|
||||||
import { notifications } from "@budibase/bbui"
|
import { notifications } from "@budibase/bbui"
|
||||||
|
|
||||||
export const createRowsStore = context => {
|
export const createRowsStore = context => {
|
||||||
const { config, API, scroll } = context
|
const { tableId, API, scroll } = context
|
||||||
const tableId = derived(config, $config => $config.tableId)
|
|
||||||
const rows = writable([])
|
const rows = writable([])
|
||||||
const table = writable(null)
|
const table = writable(null)
|
||||||
const filter = writable([])
|
const filter = writable([])
|
||||||
|
@ -115,6 +114,12 @@ export const createRowsStore = context => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Gets a row by ID
|
||||||
|
const getRow = id => {
|
||||||
|
const index = get(rowLookupMap)[id]
|
||||||
|
return index >= 0 ? get(enrichedRows)[index] : null
|
||||||
|
}
|
||||||
|
|
||||||
// Adds a new empty row
|
// Adds a new empty row
|
||||||
const addRow = async (row, idx) => {
|
const addRow = async (row, idx) => {
|
||||||
try {
|
try {
|
||||||
|
@ -281,6 +286,7 @@ export const createRowsStore = context => {
|
||||||
subscribe: enrichedRows.subscribe,
|
subscribe: enrichedRows.subscribe,
|
||||||
actions: {
|
actions: {
|
||||||
addRow,
|
addRow,
|
||||||
|
getRow,
|
||||||
updateRow,
|
updateRow,
|
||||||
deleteRows,
|
deleteRows,
|
||||||
hasRow,
|
hasRow,
|
||||||
|
|
|
@ -6,7 +6,6 @@ export const createUIStores = context => {
|
||||||
const selectedRows = writable({})
|
const selectedRows = writable({})
|
||||||
const hoveredRowId = writable(null)
|
const hoveredRowId = writable(null)
|
||||||
const selectedCellAPI = writable(null)
|
const selectedCellAPI = writable(null)
|
||||||
const sidePanelRowId = writable(null)
|
|
||||||
|
|
||||||
// Derive the row that contains the selected cell.
|
// Derive the row that contains the selected cell.
|
||||||
const selectedCellRow = derived(
|
const selectedCellRow = derived(
|
||||||
|
@ -93,7 +92,6 @@ export const createUIStores = context => {
|
||||||
hoveredRowId,
|
hoveredRowId,
|
||||||
selectedCellRow,
|
selectedCellRow,
|
||||||
selectedCellAPI,
|
selectedCellAPI,
|
||||||
sidePanelRowId,
|
|
||||||
ui: {
|
ui: {
|
||||||
actions: {
|
actions: {
|
||||||
blur,
|
blur,
|
||||||
|
|
Loading…
Reference in a new issue