Skip to content

Commit

Permalink
feat: duration field
Browse files Browse the repository at this point in the history
  • Loading branch information
nichenqin committed Sep 4, 2024
1 parent 08d1f82 commit 92948d5
Show file tree
Hide file tree
Showing 47 changed files with 680 additions and 29 deletions.
1 change: 1 addition & 0 deletions apps/frontend/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ enum FieldType {
createdBy
currency
date
duration
email
id
json
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<script lang="ts">
import { durationToMilliseconds, isDurationString, millisecondsToDuration } from "@undb/table"
export let value: number | undefined
export let onValueChange: ((value: number) => void) | undefined = undefined
let internalValue = value ? millisecondsToDuration(value) : ""
export let isValid = true
function onChange(event: Event) {
const valueString = (event.target as HTMLInputElement).value
if (!isDurationString(valueString)) {
isValid = false
return
}
isValid = true
internalValue = valueString
value = durationToMilliseconds(valueString)
onValueChange?.(value)
}
</script>

<input value={internalValue} on:change={onChange} {...$$restProps} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<script lang="ts">
import { cn } from "$lib/utils"
import DurationInput from "$lib/components/blocks/duration/duration-input.svelte"
export let readonly = false
export let value: number
</script>

<DurationInput
bind:value
disabled={readonly}
{...$$restProps}
class={cn(
"border-input placeholder:text-muted-foreground focus-visible:ring-ring flex h-9 w-full rounded-md border bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none focus-visible:ring-1 disabled:cursor-not-allowed disabled:opacity-50",
$$restProps.class,
)}
/>
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import type { NoneSystemField, NoneSystemFieldType } from "@undb/table"
import type { NoneSystemField, NoneSystemFieldType, RecordDO } from "@undb/table"
import StringControl from "./string-control.svelte"
import NumberControl from "./number-control.svelte"
import type { ComponentType } from "svelte"
Expand All @@ -17,6 +17,7 @@
import LongTextControl from "./long-text-control.svelte"
import CurrencyControl from "./currency-control.svelte"
import ButtonControl from "./button-control.svelte"
import DurationControl from "./duration-control.svelte"
export let readonly = false
export let field: NoneSystemField
Expand Down Expand Up @@ -53,6 +54,7 @@
json: JsonControl,
checkbox: CheckboxControl,
user: UserControl,
duration: DurationControl,
}
</script>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
FolderIcon,
DollarSignIcon,
MousePointerClickIcon,
TimerIcon,
} from "lucide-svelte"
export let type: FieldType
Expand Down Expand Up @@ -54,6 +55,7 @@
checkbox: SquareCheckIcon,
user: field?.type === "user" && field.isMultiple ? UsersIcon : UserIcon,
button: MousePointerClickIcon,
duration: TimerIcon,
}
</script>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<script lang="ts">
import { Checkbox } from "$lib/components/ui/checkbox"
import NumberInput from "$lib/components/ui/input/number-input.svelte"
import { Label } from "$lib/components/ui/label/index.js"
import { Separator } from "$lib/components/ui/separator"
import { DurationFieldConstraint, type IDurationFieldConstraint } from "@undb/table"
import * as Alert from "$lib/components/ui/alert/index.js"
export let constraint: IDurationFieldConstraint | undefined
export let display: boolean | undefined
export let defaultValue: number | undefined
export let disabled = false
$: c = constraint ? new DurationFieldConstraint(constraint) : undefined
$: isDefaultValueValid = c && defaultValue ? c.schema.safeParse(defaultValue).success : true
</script>

<div class="space-y-2">
<div class="space-y-1">
<Label for="defaultValue" class="text-xs font-normal">Default value</Label>
<NumberInput
{disabled}
id="defaultValue"
class="bg-background flex-1 text-xs"
placeholder="Default value..."
bind:value={defaultValue}
/>
</div>

{#if !isDefaultValueValid}
<Alert.Root class="border-yellow-500 bg-yellow-50">
<Alert.Title>Invalid default value</Alert.Title>
<Alert.Description>Your default value is invalid. Default value will not be saved.</Alert.Description>
</Alert.Root>
{/if}
{#if constraint}
<div class="grid grid-cols-2 gap-2">
<div class="space-y-1">
<Label for="min" class="text-xs font-normal">Min</Label>
<NumberInput
{disabled}
id="min"
min={0}
max={constraint.max}
step={1}
bind:value={constraint.min}
placeholder="Min value..."
class="bg-background text-xs"
/>
</div>
<div class="space-y-1">
<Label for="max" class="text-xs font-normal">Max</Label>
<NumberInput
{disabled}
id="max"
min={constraint.min || 0}
step={1}
bind:value={constraint.max}
placeholder="Max value..."
class="bg-background text-xs"
/>
</div>
</div>

<div class="pt-2">
<Separator />
</div>
<div class="flex items-center space-x-2">
<Checkbox id="required" {disabled} bind:checked={constraint.required} />
<Label for="required" class="text-xs font-normal">Mark as required field.</Label>
</div>

<div class="flex items-center space-x-2">
<Checkbox id="display" {disabled} bind:checked={display} />
<Label for="display" class="text-xs font-normal">Mark as display field.</Label>
</div>
{/if}
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import LongTextFieldOption from "./long-text-field-option.svelte"
import CurrencyFieldOption from "./currency-field-option.svelte"
import ButtonFieldOption from "./button-field-option.svelte"
import DurationFieldOption from "./duration-field-option.svelte"
export let constraint: IFieldConstraint | undefined
export let option: any | undefined
Expand All @@ -43,6 +44,7 @@
checkbox: CheckboxFieldOption,
json: JsonFieldOption,
date: DateFieldOption,
duration: DurationFieldOption,
}
export let type: NoneSystemFieldType
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script lang="ts">
import { millisecondsToDuration } from "@undb/table"
export let value: number | undefined = undefined
</script>

<span class={$$restProps.class}>{value ? millisecondsToDuration(value) : ""}</span>
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import UrlField from "./url-field.svelte"
import LongTextField from "./long-text-field.svelte"
import CurrencyField from "./currency-field.svelte"
import DurationField from "./duration-field.svelte"
export let type: FieldType
export let value: any
Expand Down Expand Up @@ -47,6 +48,7 @@
json: JsonField,
checkbox: CheckboxField,
user: UserField,
duration: DurationField,
}
</script>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
type ICreatedByFieldConditionOp,
type ICurrencyFieldConditionOp,
type IDateFieldConditionOp,
type IDurationFieldConditionOp,
type IEmailFieldConditionOp,
type IIdFieldConditionOp,
type IJsonFieldConditionOp,
Expand Down Expand Up @@ -185,6 +186,13 @@
lte: NumberInput,
}
const duration: Record<IDurationFieldConditionOp, ComponentType | null> = {
eq: NumberInput,
neq: NumberInput,
is_empty: null,
is_not_empty: null,
}
const id: Record<IIdFieldConditionOp, ComponentType | null> = {
eq: IdFilterInput,
neq: IdFilterInput,
Expand Down Expand Up @@ -268,6 +276,7 @@
json,
url,
longText,
duration,
}
</script>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<script lang="ts">
import { trpc } from "$lib/trpc/client"
import { cn } from "$lib/utils"
import { createMutation } from "@tanstack/svelte-query"
import { DurationField, millisecondsToDuration } from "@undb/table"
import { toast } from "svelte-sonner"
import { debounce, isNumber } from "radash"
import { gridViewStore } from "../grid-view.store"
import DurationInput from "$lib/components/blocks/duration/duration-input.svelte"
export let tableId: string
export let field: DurationField
export let value: number
export let isEditing: boolean
export let recordId: string
export let onValueChange: (value: number) => void
const updateCell = createMutation({
mutationKey: ["record", tableId, field.id.value, recordId],
mutationFn: trpc.record.update.mutate,
onSuccess(data, variables, context) {
gridViewStore.exitEditing()
},
onError(error: Error) {
toast.error(error.message)
},
})
const onChange = (value: number) => {
onValueChange(value)
$updateCell.mutate({
tableId,
id: recordId,
values: { [field.id.value]: value },
})
}
</script>

{#if isEditing}
<DurationInput
onValueChange={debounce({ delay: 300 }, onChange)}
max={field.max}
min={field.min}
class={cn($$restProps.class, "focus-visible:ring-ring w-full rounded-none border-none outline-none focus:bg-white")}
{value}
/>
{:else}
<div class={$$restProps.class}>
{#if isNumber(value)}
{millisecondsToDuration(value)}
{/if}
</div>
{/if}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import LongTextCell from "./editable-cell/long-text-cell.svelte"
import CurrencyCell from "./editable-cell/currency-cell.svelte"
import ButtonCell from "./editable-cell/button-cell.svelte"
import DurationCell from "./editable-cell/duration-cell.svelte"
const table = getTable()
Expand Down Expand Up @@ -62,6 +63,7 @@
checkbox: CheckboxCell,
attachment: AttachmentCell,
user: UserCell,
duration: DurationCell,
}
</script>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
<Command.Root shouldFilter={false}>
<Command.Input bind:value={search} placeholder="Search option..." />
<Command.Empty>No Option found.</Command.Empty>
<Command.Group>
<Command.Group class="max-h-[300px] overflow-y-auto">
{#each filteredOptions as option}
<Command.Item
value={option.id}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
<Command.Root shouldFilter={false}>
<Command.Input bind:value={search} placeholder="Search option..." />
<Command.Empty>No option found.</Command.Empty>
<Command.Group>
<Command.Group class="max-h-[300px] overflow-y-auto">
{#each filteredOptions as option}
<Command.Item
value={option.id}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
let open = false
</script>

<Popover.Root openFocus bind:open>
<Popover.Root openFocus bind:open portal="body">
<Popover.Trigger {disabled}>
<ColorItem {value} class="flex items-center justify-center">
<ChevronDownIcon class={cn("h-4 w-4", value ? "text-white" : "text-black")} />
Expand Down
19 changes: 19 additions & 0 deletions packages/base/src/fixtures/__snapshots__/base.fixture.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,22 @@ Base {
},
}
`;

exports[`base fixture test create test base success 1`] = `
Base {
"id": BaseId {
"props": {
"value": "basttrlpxe2",
},
},
"name": BaseName {
"props": {
"value": undefined,
},
},
"option": BaseOption {
"props": {},
},
"spaceId": undefined,
}
`;
1 change: 1 addition & 0 deletions packages/graphql/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ export class Graphql {
json
checkbox
user
duration
}
type Field {
Expand Down
1 change: 1 addition & 0 deletions packages/i18n/src/i18n/en/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ const fieldTypes: Record<FieldType, string> = {
checkbox: "Checkbox",
user: "User",
currency: "Currency",
duration: "Duration",
button: "Button",
}

Expand Down
8 changes: 8 additions & 0 deletions packages/i18n/src/i18n/i18n-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,10 @@ type RootTranslation = {
* C​u​r​r​e​n​c​y
*/
currency: string
/**
* D​u​r​a​t​i​o​n
*/
duration: string
/**
* B​u​t​t​o​n
*/
Expand Down Expand Up @@ -614,6 +618,10 @@ export type TranslationFunctions = {
* Currency
*/
currency: () => LocalizedString
/**
* Duration
*/
duration: () => LocalizedString
/**
* Button
*/
Expand Down
Loading

0 comments on commit 92948d5

Please sign in to comment.