Skip to content

Commit

Permalink
feat: persontage field
Browse files Browse the repository at this point in the history
  • Loading branch information
nichenqin committed Sep 4, 2024
1 parent c8edecc commit c8df205
Show file tree
Hide file tree
Showing 41 changed files with 521 additions and 12 deletions.
1 change: 1 addition & 0 deletions apps/frontend/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ enum FieldType {
json
longText
number
percentage
rating
reference
rollup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
{/if}
</div>
</Form.Label>
<div class="flex-1">
<div class="h-9 flex-1">
<FieldControl
{...attrs}
bind:value={$formData[field.id.value]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import CurrencyControl from "./currency-control.svelte"
import ButtonControl from "./button-control.svelte"
import DurationControl from "./duration-control.svelte"
import PercentageControl from "./percentage-control.svelte"
export let readonly = false
export let field: NoneSystemField
Expand Down Expand Up @@ -55,6 +56,7 @@
checkbox: CheckboxControl,
user: UserControl,
duration: DurationControl,
percentage: PercentageControl,
}
</script>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<script lang="ts">
import { Slider } from "$lib/components/ui/slider"
import * as Tooltip from "$lib/components/ui/tooltip"
export let readonly = false
export let value: number | undefined
function onChange(nums: number[]) {
value = nums[0] / 100
}
</script>

<Tooltip.Root>
<Tooltip.Trigger class="w-full">
<div class="flex h-full items-center">
<Slider
disabled={readonly}
value={[(value ?? 0) * 100]}
onValueChange={onChange}
max={100}
step={1}
{...$$restProps}
/>
</div>
</Tooltip.Trigger>
<Tooltip.Content>
<p>{value}</p>
</Tooltip.Content>
</Tooltip.Root>
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
DollarSignIcon,
MousePointerClickIcon,
TimerIcon,
PercentIcon,
} from "lucide-svelte"
export let type: FieldType
Expand Down Expand Up @@ -56,6 +57,7 @@
user: field?.type === "user" && field.isMultiple ? UsersIcon : UserIcon,
button: MousePointerClickIcon,
duration: TimerIcon,
percentage: PercentIcon,
}
</script>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import CurrencyFieldOption from "./currency-field-option.svelte"
import ButtonFieldOption from "./button-field-option.svelte"
import DurationFieldOption from "./duration-field-option.svelte"
import PercentageFieldOption from "./percentage-field-option.svelte"
export let constraint: IFieldConstraint | undefined
export let option: any | undefined
Expand Down Expand Up @@ -45,6 +46,7 @@
json: JsonFieldOption,
date: DateFieldOption,
duration: DurationFieldOption,
percentage: PercentageFieldOption,
}
export let type: NoneSystemFieldType
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 { PercentageFieldConstraint, type IPercentageFieldConstraint } from "@undb/table"
import * as Alert from "$lib/components/ui/alert/index.js"
export let constraint: IPercentageFieldConstraint | undefined
export let display: boolean | undefined
export let defaultValue: number | undefined
export let disabled = false
$: c = constraint ? new PercentageFieldConstraint(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 @@ -15,6 +15,7 @@
type ILongTextFieldConditionOp,
type INumberFieldConditionOp,
type IOpType,
type IPercentageFieldConditionOp,
type IRatingFieldConditionOp,
type ISelectFieldConditionOp,
type IStringFieldConditionOp,
Expand Down Expand Up @@ -257,6 +258,13 @@
is_not_empty: null,
}
const percentage: Record<IPercentageFieldConditionOp, ComponentType | null> = {
eq: NumberInput,
neq: NumberInput,
is_empty: null,
is_not_empty: null,
}
$: filterFieldInput = {
string,
number,
Expand All @@ -277,6 +285,7 @@
url,
longText,
duration,
percentage,
}
</script>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<script lang="ts">
import { trpc } from "$lib/trpc/client"
import { cn } from "$lib/utils"
import { createMutation } from "@tanstack/svelte-query"
import { NumberField } from "@undb/table"
import { toast } from "svelte-sonner"
import { debounce, isNumber } from "radash"
import { gridViewStore } from "../grid-view.store"
import { Slider } from "$lib/components/ui/slider"
import * as Tooltip from "$lib/components/ui/tooltip"
export let tableId: string
export let field: NumberField
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) {
el?.blur()
gridViewStore.exitEditing()
},
onError(error: Error) {
toast.error(error.message)
},
})
let el: HTMLInputElement
$: if (isEditing) {
if (el) {
el.focus()
}
}
const onChange = (nums: number[]) => {
const value = nums[0] / 100
onValueChange(value)
$updateCell.mutate({
tableId,
id: recordId,
values: { [field.id.value]: value },
})
}
</script>

<Tooltip.Root>
<Tooltip.Trigger class="w-full">
<div class={$$restProps.class}>
{#if isEditing}
<Slider value={[(value ?? 0) * 100]} onValueChange={debounce({ delay: 300 }, onChange)} />
{:else if isNumber(value) || value === undefined || value === null}
<Slider disabled value={[value * 100]} />
{/if}
</div>
</Tooltip.Trigger>
<Tooltip.Content>
<p>{value}</p>
</Tooltip.Content>
</Tooltip.Root>
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import CurrencyCell from "./editable-cell/currency-cell.svelte"
import ButtonCell from "./editable-cell/button-cell.svelte"
import DurationCell from "./editable-cell/duration-cell.svelte"
import PercentageCell from "./editable-cell/percentage-cell.svelte"
const table = getTable()
Expand Down Expand Up @@ -64,6 +65,7 @@
attachment: AttachmentCell,
user: UserCell,
duration: DurationCell,
percentage: PercentageCell,
}
</script>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@
{/if}
</div>
</Form.Label>
<div class="flex-1 overflow-hidden">
<div class="h-9 flex-1 overflow-hidden">
{#if field.isSystem || !field.isMutable}
<FieldValue
{field}
Expand Down
1 change: 1 addition & 0 deletions packages/graphql/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ export class Graphql {
checkbox
user
duration
percentage
}
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 @@ -67,6 +67,7 @@ const fieldTypes: Record<FieldType, string> = {
currency: "Currency",
duration: "Duration",
button: "Button",
percentage: "Percentage",
}

const rollupFns: Record<IRollupFn, string> = {
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 @@ -261,6 +261,10 @@ type RootTranslation = {
* B​u​t​t​o​n
*/
button: string
/**
* P​e​r​c​e​n​t​a​g​e
*/
percentage: string
}
rollupFns: {
/**
Expand Down Expand Up @@ -626,6 +630,10 @@ export type TranslationFunctions = {
* Button
*/
button: () => LocalizedString
/**
* Percentage
*/
percentage: () => LocalizedString
}
rollupFns: {
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
ID_TYPE,
PercentageField,
type AttachmentField,
type AutoIncrementField,
type ButtonField,
Expand Down Expand Up @@ -84,6 +85,7 @@ export class RecordQueryCreatorVisitor implements IFieldVisitor {
longText(field: LongTextField): void {}
button(field: ButtonField): void {}
duration(field: DurationField): void {}
percentage(field: PercentageField): void {}
user(field: UserField): void {
if (field.isMultiple) {
const usersTable = getTableName(users)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
ID_TYPE,
JsonContains,
LongTextEqual,
PercentageEqual,
UrlEqual,
type AttachmentEmpty,
type AttachmentEqual,
Expand Down Expand Up @@ -65,6 +66,7 @@ export class RecordQuerySpecCreatorVisitor implements IRecordVisitor {
return this.#creator || this.qb
}

percentageEqual(s: PercentageEqual): void {}
longTextEqual(s: LongTextEqual): void {}
stringEqual(spec: StringEqual): void {}
stringContains(spec: StringContains): void {}
Expand Down
4 changes: 4 additions & 0 deletions packages/persistence/src/record/record-reference-visitor.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
ID_TYPE,
PercentageField,
type AttachmentField,
type AutoIncrementField,
type ButtonField,
Expand Down Expand Up @@ -88,6 +89,9 @@ export class RecordReferenceVisitor implements IFieldVisitor {
reference(field: ReferenceField): void {
this.qb = this.qb.leftJoin(field.id.value, `${this.table.id.value}.${ID_TYPE}`, `${field.id.value}.${ID_TYPE}`)
}
percentage(field: PercentageField): void {
throw new Error("Method not implemented.")
}
attachment(field: AttachmentField): void {
throw new Error("Method not implemented.")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
ButtonField,
DurationField,
ID_TYPE,
PercentageField,
type AttachmentField,
type AutoIncrementField,
type CheckboxField,
Expand Down Expand Up @@ -137,6 +138,9 @@ export class RecordSelectFieldVisitor implements IFieldVisitor {
duration(field: DurationField): void {
this.addSelect(this.getField(field.id.value))
}
percentage(field: PercentageField): void {
this.addSelect(this.getField(field.id.value))
}
reference(field: ReferenceField): void {
const select = `${field.id.value}.${field.id.value} as ${field.id.value}`
this.addSelect(select)
Expand Down
Loading

0 comments on commit c8df205

Please sign in to comment.