group by complete

This commit is contained in:
Martin McKeaveney 2020-08-18 16:05:15 +01:00
parent 28b4b6fcb9
commit d08db301af
11 changed files with 155 additions and 54 deletions

View File

@ -93,10 +93,8 @@ export const getBackendUiStore = () => {
// delete the original if renaming
delete state.draftModel.schema[originalName]
state.draftModel.schema = {
...state.draftModel.schema,
[field.name]: cloneDeep(field),
}
state.draftModel.schema[field.name] = cloneDeep(field)
store.actions.models.save(state.draftModel)
return state
})
@ -126,8 +124,15 @@ export const getBackendUiStore = () => {
},
save: async view => {
await api.post(`/api/views`, view)
store.update(state => {
state.selectedModel.views[view.name] = view
const viewModel = state.models.find(model => model._id === view.modelId)
// TODO: Cleaner?
if (!viewModel.views) viewModel.views = {}
if (view.originalName) delete viewModel.views[view.originalName]
viewModel.views[view.name] = view
state.models = state.models
state.selectedView = view
return state
})

View File

@ -17,47 +17,62 @@
import ColumnHeaderPopover from "./popovers/ColumnHeader.svelte"
import EditRowPopover from "./popovers/EditRow.svelte"
import CalculationPopover from "./popovers/Calculate.svelte"
import GroupByPopover from "./popovers/GroupBy.svelte"
const COLUMNS = [
let COLUMNS = [
{
name: "Group",
key: "key",
},
{
name: "sum",
key: "value.sum",
},
{
name: "min",
key: "value.min",
key: "value.min"
},
{
name: "max",
key: "value.max",
key: "value.max"
},
{
name: "sumsqr",
key: "value.sumsqr",
key: "value.sumsqr"
},
{
name: "count",
key: "value.count",
key: "value.count"
},
{
name: "avg",
key: "value.avg",
},
key: "value.avg"
}
]
export let view = {}
let data = []
$: selectedView = $backendUiStore.selectedView
$: !selectedView.name.startsWith("all_") && fetchViewData(selectedView)
$: viewName = view.name
$: !viewName.startsWith("all_") && fetchViewData(viewName)
async function fetchViewData() {
const QUERY_VIEW_URL = `/api/views/${$backendUiStore.selectedView.name}?stats=true`
async function fetchViewData(viewName) {
let QUERY_VIEW_URL = `/api/views/${viewName}?stats=true`
if (view.groupBy) {
QUERY_VIEW_URL += `&group=${view.groupBy}`
}
const response = await api.get(QUERY_VIEW_URL)
data = await response.json()
}
</script>
<Table title={decodeURI(selectedView.name)} columns={COLUMNS} {data}>
<CalculationPopover view={selectedView} />
</Table>
<Table
title={decodeURI(view.name)}
columns={COLUMNS}
{data}
>
<CalculationPopover {view} />
<GroupByPopover {view} />
</Table>

View File

@ -4,7 +4,7 @@
import { store, backendUiStore } from "builderStore"
import * as api from "../api"
export let view
export let viewName
export let onClosed
</script>
@ -24,7 +24,7 @@
<ActionButton
alert
on:click={async () => {
await backendUiStore.actions.views.delete(view)
await backendUiStore.actions.views.delete(viewName)
notifier.danger('View deleted')
onClosed()
}}>

View File

@ -0,0 +1,80 @@
<script>
import { Popover, Button, Icon, Input, Select } from "@budibase/bbui"
import { backendUiStore } from "builderStore"
import { notifier } from "builderStore/store/notifications"
import CreateEditRecord from "../modals/CreateEditRecord.svelte"
const CALCULATIONS = [
{
name: "Statistics",
key: "stats",
},
]
export let view = {}
let anchor
let dropdown
$: viewModel = $backendUiStore.models.find(
({ _id }) => _id === $backendUiStore.selectedView.modelId
)
$: fields =
viewModel && Object.keys(viewModel.schema)
function saveView() {
backendUiStore.actions.views.save(view)
notifier.success(`View ${view.name} saved.`)
dropdown.hide()
}
</script>
<div bind:this={anchor}>
<Button text small on:click={dropdown.show}>
<Icon name="calculate" />
Group By
</Button>
</div>
<Popover bind:this={dropdown} {anchor} align="left">
<h5>Group By</h5>
<div class="input-group-row">
<p>Group By</p>
<Select secondary thin bind:value={view.groupBy}>
<option value={false}>None</option>
{#each fields as field}
<option value={field}>{field}</option>
{/each}
</Select>
</div>
<div class="button-group">
<Button secondary on:click={dropdown.hide}>Cancel</Button>
<Button primary on:click={saveView}>Save</Button>
</div>
</Popover>
<style>
h5 {
margin-bottom: var(--spacing-l);
font-weight: 500;
}
.button-group {
margin-top: var(--spacing-l);
display: flex;
justify-content: flex-end;
gap: var(--spacing-s);
}
.input-group-row {
display: grid;
grid-template-columns: 50px 1fr 20px 1fr;
gap: var(--spacing-s);
margin-bottom: var(--spacing-l);
align-items: center;
}
p {
margin: 0;
font-size: var(--font-size-xs);
}
</style>

View File

@ -28,7 +28,7 @@
open(
DeleteTableModal,
{
onClosed: hideEditor,
onClosed: close,
table,
},
{ styleContent: { padding: "0" } }

View File

@ -1,6 +1,7 @@
<script>
import { getContext } from "svelte"
import { backendUiStore } from "builderStore"
import { notifier } from "builderStore/store/notifications"
import { DropdownMenu, Button, Icon, Input, Select } from "@budibase/bbui"
import { FIELDS } from "constants/backend"
import DeleteViewModal from "components/database/DataTable/modals/DeleteView.svelte"
@ -13,6 +14,7 @@
let dropdown
let editing
let originalName = view.name
function showEditor() {
editing = true
@ -29,14 +31,18 @@
DeleteViewModal,
{
onClosed: close,
view,
viewName: view.name,
},
{ styleContent: { padding: "0" } }
)
}
function save() {
backendUiStore.actions.views.save(view)
backendUiStore.actions.views.save({
originalName,
...view
})
notifier.success("Renamed View Successfully.")
hideEditor()
}
</script>
@ -48,7 +54,7 @@
{#if editing}
<h5>Edit View</h5>
<div class="container">
<Input placeholder="Table Name" thin bind:value={view} />
<Input placeholder="Table Name" thin bind:value={view.name} />
</div>
<footer>
<div class="button-margin-3">

View File

@ -12,7 +12,8 @@
const { open, close } = getContext("simple-modal")
$: selectedView = $backendUiStore.selectedView && $backendUiStore.selectedView.name
$: selectedView =
$backendUiStore.selectedView && $backendUiStore.selectedView.name
function selectModel(model) {
backendUiStore.actions.models.select(model)
@ -40,17 +41,18 @@
on:click={() => selectModel(model)}>
<EditTablePopover table={model} />
</ListItem>
{#each Object.keys(model.views || {}) as view}
{#each Object.keys(model.views || {}) as viewName}
<ListItem
indented
selected={selectedView === view}
title={view}
selected={selectedView === viewName}
title={viewName}
icon="ri-eye-line"
on:click={() => selectView({
name: view,
...model.views[view]
})}>
<EditViewPopover {view} />
name: viewName,
...model.views[viewName],
})}>
<EditViewPopover
view={{ name: viewName, ...model.views[viewName] }} />
</ListItem>
{/each}
{/each}

View File

@ -13,7 +13,7 @@
</script>
{#if $backendUiStore.selectedDatabase._id && selectedView}
<ViewDataTable />
<ViewDataTable view={selectedView} />
{:else}
<i>create your first table to start building</i>
{/if}

View File

@ -80,10 +80,10 @@ exports.save = async function(ctx) {
exports.fetchView = async function(ctx) {
const db = new CouchDB(ctx.user.instanceId)
const { stats, groupBy } = ctx.query
const { stats, group } = ctx.query
const response = await db.query(`database/${ctx.params.viewName}`, {
include_docs: !stats,
group: !!groupBy
group
})
if (stats) {

View File

@ -2,22 +2,6 @@ const CouchDB = require("../../../db")
const statsViewTemplate = require("./viewBuilder");
const controller = {
query: async ctx => {
const db = new CouchDB(ctx.user.instanceId)
const { meta } = ctx.request.body
const response = await db.query(`database/${ctx.params.viewName}`, {
group: !!meta.groupBy
})
for (row of response.rows) {
row.value = {
...row.value,
avg: row.value.sum / row.value.count
}
}
ctx.body = response.rows
},
fetch: async ctx => {
const db = new CouchDB(ctx.user.instanceId)
const designDoc = await db.get("_design/database")
@ -41,7 +25,7 @@ const controller = {
},
save: async ctx => {
const db = new CouchDB(ctx.user.instanceId)
const newView = ctx.request.body
const { originalName, ...newView } = ctx.request.body
const designDoc = await db.get("_design/database")
@ -52,6 +36,11 @@ const controller = {
[newView.name]: view,
}
// view has been renamed
if (originalName) {
delete designDoc.views[originalName]
}
await db.put(designDoc)
@ -61,6 +50,11 @@ const controller = {
...(model.views ? model.views : {}),
[newView.name]: view.meta
}
if (originalName) {
delete model.views[originalName]
}
await db.put(model)
ctx.body = view

View File

@ -13,7 +13,6 @@ router
recordController.fetchView
)
.get("/api/views", authorized(BUILDER), viewController.fetch)
// .post("/api/views/query/:viewName", authorized(BUILDER), viewController.query)
.delete("/api/views/:viewName", authorized(BUILDER), viewController.destroy)
.post("/api/views", authorized(BUILDER), viewController.save)