Skip to content

Commit

Permalink
Merge pull request #1970 from undb-io/release/v1.0.0-48
Browse files Browse the repository at this point in the history
Release version v1.0.0-48
  • Loading branch information
nichenqin authored Aug 31, 2024
2 parents cb8dd9a + ae428d7 commit e981449
Show file tree
Hide file tree
Showing 22 changed files with 391 additions and 77 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
# Changelog


## v1.0.0-48


### 🩹 Fixes

- Update field ux ([9eda222](https://github.com/undb-io/undb/commit/9eda222))

### ❤️ Contributors

- Nichenqin ([@nichenqin](http://github.com/nichenqin))

## v1.0.0-47

## v1.0.0-46
Expand Down
27 changes: 25 additions & 2 deletions apps/backend/src/modules/openapi/record.openapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import {
CreateRecordsCommand,
DeleteRecordCommand,
DuplicateRecordCommand,
TriggerRecordButtonCommand,
UpdateRecordCommand,
} from "@undb/commands"
import { CommandBus, QueryBus } from "@undb/cqrs"
import { inject, singleton } from "@undb/di"
import { type ICommandBus, type IQueryBus, type PaginatedDTO } from "@undb/domain"
import { Option, type ICommandBus, type IQueryBus, type PaginatedDTO } from "@undb/domain"
import { injectQueryBuilder, type IQueryBuilder } from "@undb/persistence"
import { GetReadableRecordByIdQuery, GetReadableRecordsQuery } from "@undb/queries"
import { type IRecordReadableValueDTO } from "@undb/table"
import { RecordDO, type IRecordReadableValueDTO } from "@undb/table"
import Elysia, { t } from "elysia"
import { withTransaction } from "../../db"

Expand Down Expand Up @@ -226,6 +227,28 @@ export class RecordOpenApi {
},
},
)
.post(
"/records/:recordId/trigger/:field",
async (ctx) => {
const { baseName, tableName, recordId, field } = ctx.params
return withTransaction(this.qb)(async () => {
const result = (await this.commandBus.execute(
new TriggerRecordButtonCommand({ baseName, tableName, recordId, field }),
)) as Option<RecordDO>
return {
mutated: result.isSome(),
}
})
},
{
params: t.Object({ baseName: t.String(), tableName: t.String(), recordId: t.String(), field: t.String() }),
detail: {
tags: ["Record", "Button"],
summary: "Trigger record button",
description: "Trigger record button",
},
},
)
.post(
"/records/duplicate",
async (ctx) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
<script lang="ts">
import FieldPicker from "../field-picker/field-picker.svelte"
import { FieldIdVo, getIsMutableFieldType, type IButtonFieldOption } from "@undb/table"
import {
FieldIdVo,
getIsFilterableFieldType,
getIsMutableFieldType,
type IButtonFieldOption,
type MaybeConditionGroup,
parseValidViewFilter,
toMaybeConditionGroup,
} from "@undb/table"
import { getTable } from "$lib/store/table.store"
import FieldControl from "../field-control/field-control.svelte"
import { Input } from "$lib/components/ui/input"
import { Label } from "$lib/components/ui/label"
import { Checkbox } from "$lib/components/ui/checkbox"
import { Button } from "$lib/components/ui/button"
import Separator from "$lib/components/ui/separator/separator.svelte"
import { writable } from "svelte/store"
import type { ZodUndefined } from "@undb/zod"
import FiltersEditor from "../filters-editor/filters-editor.svelte"
import { onMount } from "svelte"
const table = getTable()
$: visibleFields = $table.getOrderedVisibleFields()
export let disabled: boolean | undefined
export let option: IButtonFieldOption = {
label: undefined,
disabled: undefined,
action: {
type: "update",
values: [
Expand All @@ -25,6 +40,17 @@
confirm: true,
},
}
const value = writable<MaybeConditionGroup<ZodUndefined> | undefined>()
$: validValue = $value ? parseValidViewFilter($table.schema, $value) : undefined
$: if (validValue) {
option.disabled = validValue
}
onMount(() => {
if (option.disabled) {
value.set(toMaybeConditionGroup(option.disabled))
}
})
$: selectedFields = option.action.values.map((v) => v.field)
$: selectableFields = $table.schema.fields.filter(
Expand All @@ -36,39 +62,52 @@
<Label for="label">Label</Label>
<Input class="w-full" placeholder="Button" id="label" bind:value={option.label} />

<p class="text-xs font-semibold">Update Value when Click Button</p>
{#each option.action.values as value, index}
{@const field = value.field ? $table.schema.getFieldById(new FieldIdVo(value.field)).unwrap() : undefined}
<FieldPicker
class="w-full"
bind:value={value.field}
{disabled}
filter={(f) =>
getIsMutableFieldType(f.type) && f.type !== "attachment" && !option.action.values.some((v) => v.field === f.id)}
/>
{#if field}
<FieldControl
class="text-xs"
placeholder="Value to update..."
bind:value={value.value}
{field}
tableId={$table.id.value}
<div class="space-y-2 rounded-sm border pt-2">
<Label class="pl-4 text-xs font-semibold" for="disabled">Disabled When...</Label>
<FiltersEditor
bind:value={$value}
table={$table}
filter={(field) => visibleFields.some((f) => f.id.value === field.id) && getIsFilterableFieldType(field.type)}
></FiltersEditor>
</div>

<div class="space-y-2 rounded-md border px-4 py-3">
<p class="text-xs font-semibold">Update Value when Click Button</p>
{#each option.action.values as value, index}
{@const field = value.field ? $table.schema.getFieldById(new FieldIdVo(value.field)).unwrap() : undefined}
<FieldPicker
class="w-full"
bind:value={value.field}
{disabled}
filter={(f) =>
getIsMutableFieldType(f.type) &&
f.type !== "attachment" &&
!option.action.values.some((v) => v.field === f.id)}
/>
{#if field}
<FieldControl
class="text-xs"
placeholder="Value to update..."
bind:value={value.value}
{field}
tableId={$table.id.value}
/>
{/if}
{#if index !== option.action.values.length - 1}
<Separator />
{/if}
{/each}
{#if selectableFields.length > 0 && option.action.values.every((v) => v.field)}
<Button
class="text-muted-foreground w-full justify-start text-xs"
on:click={() => {
option.action.values = [...option.action.values, { field: undefined, value: undefined }]
}}
variant="link"
size="sm">+ Add another field to update</Button
>
{/if}
{#if index !== option.action.values.length - 1}
<Separator />
{/if}
{/each}
{#if selectableFields.length > 0 && option.action.values.every((v) => v.field)}
<Button
class="text-muted-foreground w-full text-xs"
on:click={() => {
option.action.values = [...option.action.values, { field: undefined, value: undefined }]
}}
variant="link"
size="sm">+ Add another field to update</Button
>
{/if}
</div>

<div class="flex items-center gap-2">
<Checkbox id="confirm" bind:checked={option.action.confirm} />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
<script lang="ts">
import { trpc } from "$lib/trpc/client"
import { createMutation } from "@tanstack/svelte-query"
import { ButtonField } from "@undb/table"
import { ButtonField, FieldIdVo, RecordDO } from "@undb/table"
import { toast } from "svelte-sonner"
import { gridViewStore } from "../grid-view.store"
import { Button } from "$lib/components/ui/button"
import { LoaderCircleIcon } from "lucide-svelte"
import { recordsStore } from "$lib/store/records.store"
import { getTable } from "$lib/store/table.store"
import { objectify } from "radash"
import * as AlertDialog from "$lib/components/ui/alert-dialog"
import FieldPicker from "../../field-picker/field-picker.svelte"
import FieldControl from "../../field-control/field-control.svelte"
export let tableId: string
export let field: ButtonField
export let recordId: string
export let record: RecordDO | undefined
const table = getTable()
const updateCell = createMutation({
mutationKey: ["record", tableId, field.id.value, recordId],
mutationFn: trpc.record.update.mutate,
const trigger = createMutation({
mutationKey: ["record", tableId, field.id.value, recordId, "trigger"],
mutationFn: trpc.record.trigger.mutate,
async onSuccess(data, variables, context) {
gridViewStore.exitEditing()
await recordsStore.invalidateRecord($table, recordId)
Expand All @@ -29,29 +33,66 @@
})
function handleClick() {
const option = field.option.into(undefined)
if (!option) return
const action = option.action
if (!action.values.length) return
if (field.shouldConfirm) {
confirm = true
} else {
handleUpdate()
}
}
$updateCell.mutate({
function handleUpdate() {
$trigger.mutate({
tableId,
id: recordId,
values: objectify(
action.values,
(v) => v.field!,
(v) => v.value ?? null,
),
recordId,
field: field.id.value,
})
}
$: disabled = record ? field.getIsDisabled($table, record) : false
let confirm = false
</script>

<div class={$$restProps.class}>
<Button disabled={$updateCell.isPending} on:click={handleClick} size="xs" variant="outline">
{#if $updateCell.isPending}
<Button disabled={$trigger.isPending || disabled} on:click={handleClick} size="xs" variant="outline">
{#if $trigger.isPending}
<LoaderCircleIcon className="h-3 w-3 animate-spin" />
{:else}
{field.label ?? "Button"}
{/if}
</Button>
</div>

<AlertDialog.Root bind:open={confirm}>
<AlertDialog.Content>
<AlertDialog.Header>
<AlertDialog.Title>Confirm to update</AlertDialog.Title>
<AlertDialog.Description>The following fields will be updated when you click the button.</AlertDialog.Description>
</AlertDialog.Header>

{#if field.option.isSome()}
{#each field.option.unwrap().action.values as value}
{@const field = value.field ? $table.schema.getFieldById(new FieldIdVo(value.field)).unwrap() : undefined}
<div class="flex items-center gap-2">
<FieldPicker value={value.field} disabled />
{#if field}
<FieldControl
class="text-xs"
placeholder="Value to update..."
value={value.value}
{field}
disabled
readonly
tableId={$table.id.value}
/>
{/if}
</div>
{/each}
{/if}

<AlertDialog.Footer>
<AlertDialog.Cancel on:click={() => (confirm = false)}>Cancel</AlertDialog.Cancel>
<AlertDialog.Action on:click={handleUpdate}>Continue</AlertDialog.Action>
</AlertDialog.Footer>
</AlertDialog.Content>
</AlertDialog.Root>
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
<script lang="ts">
import type { Field, FieldType } from "@undb/table"
import type { Field, FieldType, RecordDO } from "@undb/table"
import type { ComponentType } from "svelte"
import StringCell from "./editable-cell/string-cell.svelte"
import NumberCell from "./editable-cell/number-cell.svelte"
import IdField from "../field-value/id-field.svelte"
import DateField from "../field-value/date-field.svelte"
import NumberField from "../field-value/number-field.svelte"
import { cn } from "$lib/utils"
import RollupField from "../field-value/rollup-field.svelte"
import { isEditingCell, isSelectedCell } from "./grid-view.store"
import SelectCell from "./editable-cell/select-cell.svelte"
import { getTable } from "$lib/store/table.store"
Expand All @@ -34,6 +33,7 @@
export let index: number
export let field: Field
export let recordId: string
export let record: RecordDO | undefined
export let readonly: boolean
$: isEditing = $isEditingCell(recordId, field.id.value)
Expand Down Expand Up @@ -74,6 +74,7 @@
{isEditing}
{isSelected}
{recordId}
{record}
readonly={field.isSystem || readonly}
tableId={$table.id.value}
class={cn(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@
recordId: item.row.original.id,
displayValue,
readonly,
record,
})
},
footer: createRender(GridViewFooter, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,15 @@
onSubmit(input) {
validateForm({ update: true })
},
onUpdate(event) {
async onUpdate(event) {
if (!event.form.valid) {
console.log(event.form.errors, event.form.data)
return
}
const data = event.form.data
const field = FieldFactory.fromJSON(data).toJSON()
$updateFieldMutation.mutate({
await $updateFieldMutation.mutateAsync({
tableId: $table.id.value,
field,
})
Expand Down Expand Up @@ -125,11 +125,10 @@
{#if $updateFieldMutation.isPending}
<LoaderCircleIcon class="mr-2 h-5 w-5 animate-spin" />
{:else}
<PencilIcon class="mr-2 h-5 w-5" />
<PencilIcon class="mr-2 h-4 w-4" />
{/if}
Update Field
</Button
>
</Button>
</div>
</form>

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "undb",
"version": "1.0.0-47",
"version": "1.0.0-48",
"private": true,
"scripts": {
"build": "NODE_ENV=production bun --bun turbo build",
Expand Down
Loading

0 comments on commit e981449

Please sign in to comment.