Skip to content

Commit

Permalink
wip: post input -d
Browse files Browse the repository at this point in the history
  • Loading branch information
arpowers committed Sep 12, 2024
1 parent 00ba8fe commit 9cd8a5f
Show file tree
Hide file tree
Showing 38 changed files with 458 additions and 100 deletions.
4 changes: 2 additions & 2 deletions @fiction/admin/settings/ElAccountHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { dayjs, gravatarUrlSync, useService, vue } from '@fiction/core/index.js'
import ElModal from '@fiction/ui/ElModal.vue'
import { InputOption } from '@fiction/ui/index.js'
import ElForm from '@fiction/ui/inputs/ElForm.vue'
import FormEngine from '@fiction/ui/inputs/FormEngine.vue'
import type { Card } from '@fiction/site/card'
import ToolForm from '../tools/ToolForm.vue'
import ElHeader from './ElHeader.vue'
import type { FictionAdmin } from '..'
Expand Down Expand Up @@ -116,7 +116,7 @@ vue.onMounted(() => {
<div class="px-6 ">
<ElModal v-if="mode === 'changeEmail'" :vis="mode === 'changeEmail'" modal-class="max-w-lg" @update:vis="mode = 'current'">
<ElForm @submit="codeSent ? requestChangeEmail() : requestCode()">
<ToolForm v-model="form" ui-size="lg" :card :options="toolFormOptions" :disable-group-hide="true" />
<FormEngine v-model="form" ui-size="lg" :card :options="toolFormOptions" :disable-group-hide="true" />
</ElForm>
</ElModal>

Expand Down
4 changes: 2 additions & 2 deletions @fiction/admin/settings/ElOrgHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { gravatarUrlSync } from '@fiction/core/index.js'
import ElAvatar from '@fiction/ui/common/ElAvatar.vue'
import ElModal from '@fiction/ui/ElModal.vue'
import ElForm from '@fiction/ui/inputs/ElForm.vue'
import FormEngine from '@fiction/ui/inputs/FormEngine.vue'
import ElIndexGrid from '@fiction/ui/lists/ElIndexGrid.vue'
import type { ActionItem, IndexItem, Organization } from '@fiction/core/index.js'
import type { Card } from '@fiction/site/card'
import type { InputOption } from '@fiction/ui'
import ToolForm from '../tools/ToolForm.vue'
import ElHeader from './ElHeader.vue'
import { newOrgOptions } from './index.js'
Expand Down Expand Up @@ -104,7 +104,7 @@ vue.onMounted(() => {
<div class="px-6">
<ElModal v-if="mode === 'new'" :vis="mode === 'new'" modal-class="max-w-lg" @update:vis="mode = 'current'">
<ElForm @submit="createNewOrganization()">
<ToolForm v-model="newOrgForm" ui-size="lg" :card :options="toolFormOptions" :disable-group-hide="true" />
<FormEngine v-model="newOrgForm" ui-size="lg" :card :options="toolFormOptions" :disable-group-hide="true" />
</ElForm>
</ElModal>
<div v-else-if="mode === 'change'" class="p-12">
Expand Down
4 changes: 2 additions & 2 deletions @fiction/admin/settings/SettingsTool.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
import { getNavComponentType, toLabel, toSlug, useService, vue } from '@fiction/core'
import ElPanel from '@fiction/ui/ElPanel.vue'
import ElForm from '@fiction/ui/inputs/ElForm.vue'
import FormEngine from '@fiction/ui/inputs/FormEngine.vue'
import type { NavItem } from '@fiction/core'
import type { Card } from '@fiction/site/card'
import type { InputOption } from '@fiction/ui'
import ToolForm from '../tools/ToolForm.vue'
import type { SettingsTool } from '..'
const props = defineProps({
Expand Down Expand Up @@ -100,7 +100,7 @@ async function navigate(v: NavItem) {
<div class="px-6 py-4 mb-6 font-semibold text-lg dark:text-theme-600 text-theme-300">
{{ currentPanel.title.value }}
</div>
<ToolForm
<FormEngine
v-model="currentPanel.val.value"
:data-settings-tool="currentPanel.slug"
ui-size="lg"
Expand Down
4 changes: 2 additions & 2 deletions @fiction/admin/tools/ToolForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { getNested, localRef, setNested, vue } from '@fiction/core'
import TransitionSlide from '@fiction/ui/anim/TransitionSlide.vue'
import ElActions from '@fiction/ui/buttons/ElActions.vue'
import ElInput from '@fiction/ui/inputs/ElInput.vue'
import ElToolSep from '@fiction/ui/inputs/ElToolSep.vue'
import type { ActionItem } from '@fiction/core'
import type { Card } from '@fiction/site/card'
import type { InputOption } from '@fiction/ui'
import type { UiElementSize } from '@fiction/ui/utils'
import ElToolSep from './ElToolSep.vue'
const props = defineProps({
options: { type: Array as vue.PropType<InputOption[]>, required: true },
Expand Down Expand Up @@ -92,7 +92,7 @@ const cls = vue.computed(() => {
:input-props="inputProps"
:options="opt.options.value || []"
:model-value="modelValue"
:depth="1"
:depth="depth + 1"
:base-path="basePath"
:card
@update:model-value="emit('update:modelValue', $event)"
Expand Down
2 changes: 1 addition & 1 deletion @fiction/cards/capture/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const demoUserConfig = {
const options: InputOption[] = [
new InputOption({ key: 'presentationMode', label: 'Presentation Mode', input: 'InputSelect', list: ['inline', 'onScroll', 'onLoad'], description: 'Show the card inline with content as a popup on load, or when scrolling.' }),
standardOption.headers(),
new InputOption({ key: 'media', label: 'Image', input: 'InputMediaDisplay' }),
new InputOption({ key: 'media', label: 'Image', input: 'InputMedia' }),
new InputOption({ key: 'dismissText', label: 'Dismiss Text', input: 'InputText', placeholder: 'No thanks', description: 'Dismisses modal in load and modal modes' }),
new InputOption({ key: 'buttonText', label: 'Button Text', input: 'InputText', placeholder: 'Subscribe', description: 'Text on the subscribe button' }),
new InputOption({ key: 'thanksText', label: 'Thanks Text', input: 'InputText', placeholder: 'Thanks for subscribing!', description: 'Text on the thank you message' }),
Expand Down
6 changes: 3 additions & 3 deletions @fiction/cards/footer/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { standardOption } from '@fiction/cards/inputSets'
import { vue } from '@fiction/core'
import { CardTemplate } from '@fiction/site/card'
import { InputOption } from '@fiction/ui'
import { z } from 'zod'
import { standardOption } from '../inputSets'
import { mediaSchema } from '../schemaSets'

const templateId = 'footer'
Expand Down Expand Up @@ -55,7 +55,7 @@ const schema = z.object({
export type UserConfig = z.infer<typeof schema>

const options: InputOption[] = [
new InputOption({ key: 'logo', label: 'Logo', input: 'InputMediaDisplay' }),
new InputOption({ key: 'logo', label: 'Logo', input: 'InputLogo' }),
new InputOption({ key: 'layout', label: 'Layout', input: 'InputSelect', list: layoutKeys }),
new InputOption({ key: 'tagline', label: 'Tagline', input: 'InputText', description: 'A catchy phrase or description of what you do.' }),
standardOption.navItems({ key: 'nav', maxDepth: 2, itemNames: ['Column', 'Nav Item', 'Sub Nav Item'] }),
Expand All @@ -71,7 +71,7 @@ const options: InputOption[] = [
new InputOption({ key: 'badges', label: 'Badges', description: 'Add certifications or other graphics to build your authority', input: 'InputList', props: { itemName: 'Badge' }, options: [
new InputOption({ key: 'name', label: 'Name', input: 'InputText' }),
new InputOption({ key: 'href', label: 'URL', input: 'InputText' }),
new InputOption({ key: 'media', label: 'Media', input: 'InputMediaDisplay' }),
new InputOption({ key: 'media', label: 'Media', input: 'InputMedia' }),
new InputOption({ key: 'target', label: 'Target', input: 'InputSelect', list: ['_blank', '_self'] }),
] }),
] }),
Expand Down
2 changes: 1 addition & 1 deletion @fiction/cards/hero/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const options: InputOption[] = [
standardOption.media({ key: 'splash', label: 'Splash Image' }),
new InputOption({ key: 'caption', input: 'InputText', label: 'Splash Caption' }),
new InputOption({ key: 'overlays', input: 'InputList', label: 'Overlays', options: [
new InputOption({ key: 'media', label: 'Image', input: 'InputMediaDisplay', props: { formats: { url: true } } }),
new InputOption({ key: 'media', label: 'Image', input: 'InputMedia', props: { formats: { url: true } } }),
new InputOption({ key: 'opacity', label: 'Opacity', input: 'InputNumber' }),
new InputOption({ key: 'position', label: 'Position', input: 'InputSelect', list: ['top', 'bottom', 'left', 'right', 'center', 'bottomRight', 'topRight', 'bottomLeft', 'topLeft'] as const }),
new InputOption({ key: 'widthPercent', label: 'Width Percent', input: 'InputRange', props: { min: 10, max: 100 } }),
Expand Down
2 changes: 1 addition & 1 deletion @fiction/cards/inputSets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { InputOptionSettings } from '@fiction/ui/index.js'
type OptArgs<T extends string = string> = (Partial<InputOptionSettings<T>> & Record<string, unknown>) | undefined

export const standardOption = {
media: (_: OptArgs = {}) => new InputOption({ key: 'media', label: 'Image', input: 'InputMediaDisplay', props: { formats: _?.formats }, ..._ }),
media: (_: OptArgs = {}) => new InputOption({ key: 'media', label: 'Image', input: 'InputMedia', props: { formats: _?.formats }, ..._ }),
name: (_: OptArgs = {}) => new InputOption({ key: 'name', label: 'Text', input: 'InputText', ..._ }),
desc: (_: OptArgs = {}) => new InputOption({ key: 'desc', label: 'Description', input: 'InputTextarea', ..._ }),
icon: (_: OptArgs = {}) => new InputOption({ key: 'icon', label: 'Icon', input: 'InputSelect', ..._ }),
Expand Down
2 changes: 1 addition & 1 deletion @fiction/cards/logos/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const options: InputOption[] = [
new InputOption({ key: 'items', label: 'Items', input: 'InputList', options: [
new InputOption({ key: 'name', label: 'Name', input: 'InputText' }),
new InputOption({ key: 'href', label: 'Link', input: 'InputText' }),
new InputOption({ key: 'media', label: 'Image URL', input: 'InputMediaDisplay' }),
new InputOption({ key: 'media', label: 'Image URL', input: 'InputMedia' }),
] }),
]

Expand Down
4 changes: 2 additions & 2 deletions @fiction/cards/magazine/ElMagazine.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ async function loadGlobal() {
}
async function loadInline() {
const ps = uc.value.posts?.items || []
const ps = uc.value.posts?.posts || []
postIndex.value = ps.map(p => new Post({ fictionPosts, ...p }))
if (routeSlug.value) {
Expand All @@ -63,7 +63,7 @@ async function loadInline() {
}
async function load() {
if (uc.value.posts?.mode === 'inline') {
if (uc.value.posts?.format === 'local') {
await loadInline()
}
else {
Expand Down
8 changes: 4 additions & 4 deletions @fiction/cards/magazine/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,22 @@ const schema = z.object({
export type UserConfig = z.infer<typeof schema> & SiteUserConfig

const options: InputOption[] = [
new InputOption({ key: 'scheme.reverse', label: 'Reverse Color Scheme', input: 'InputCheckbox' }),
new InputOption({ key: 'posts', label: 'Posts', input: 'InputPosts' }),
]

async function getDefaultUserConfig(): Promise<UserConfig> {
return {
standard: { spacing: { verticalSpacing: 'none' } },
posts: { mode: 'global', limit: 12 },
posts: { format: 'global', limit: 12 },
}
}

async function getDemoUserConfig(args: { site?: Site }): Promise<UserConfig> {
const c: UserConfig = {
standard: { spacing: { verticalSpacing: 'sm' } },
posts: {
mode: 'inline',
items: [
format: 'local',
posts: [
{
title: 'Revolutionizing UX: My Journey at Tech Giant',
subTitle: 'From Concept to Launch',
Expand Down
2 changes: 1 addition & 1 deletion @fiction/cards/nav/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { standardOption } from '@fiction/cards/inputSets'
import { MediaTypographySchema, vue } from '@fiction/core'
import { CardTemplate } from '@fiction/site/card'
import { InputOption } from '@fiction/ui'
import { z } from 'zod'
import { standardOption } from '../inputSets'
import { mediaSchema } from '../schemaSets'

const templateId = 'nav'
Expand Down
2 changes: 1 addition & 1 deletion @fiction/cards/people/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const options: InputOption[] = [
new InputOption({ key: 'name', input: 'InputText', label: 'Name' }),
new InputOption({ key: 'title', input: 'InputText', label: 'Title' }),
new InputOption({ key: 'desc', input: 'InputText', label: 'Description' }),
new InputOption({ key: 'media', input: 'InputMediaDisplay', label: 'Media', props: { formats: { url: true } } }),
new InputOption({ key: 'media', input: 'InputMedia', label: 'Media', props: { formats: { url: true } } }),
new InputOption({ key: 'social', input: 'InputList', label: 'Social', options: [
new InputOption({ key: 'name', input: 'InputText', label: 'Name' }),
new InputOption({ key: 'href', input: 'InputText', label: 'Link' }),
Expand Down
4 changes: 2 additions & 2 deletions @fiction/cards/quote/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,10 @@ export const templates = [
new InputOption({ key: 'text', label: 'Quote Text', input: 'InputText' }),
new InputOption({ key: 'author.name', label: 'Author', input: 'InputText' }),
new InputOption({ key: 'author.title', label: 'Title', input: 'InputText' }),
new InputOption({ key: 'author.image', label: 'Author Image', input: 'InputMediaDisplay' }),
new InputOption({ key: 'author.image', label: 'Author Image', input: 'InputMedia' }),
new InputOption({ key: 'author.href', label: 'Author Link', input: 'InputUrl' }),
new InputOption({ key: 'org.name', label: 'Organization', input: 'InputText' }),
new InputOption({ key: 'org.image', label: 'Organization Image', input: 'InputMediaDisplay' }),
new InputOption({ key: 'org.image', label: 'Organization Image', input: 'InputMedia' }),
new InputOption({ key: 'org.href', label: 'Organization Link', input: 'InputUrl' }),
],
}),
Expand Down
2 changes: 1 addition & 1 deletion @fiction/cards/story/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const options: InputOption[] = [
new InputOption({ key: 'items', label: 'Tour Items', input: 'InputList', props: { itemName: 'paragraph' }, options: [
new InputOption({ key: 'title', label: 'Title', input: 'InputText' }),
new InputOption({ key: 'content', label: 'Content', input: 'InputText' }),
new InputOption({ key: 'media', label: 'Media', input: 'InputMediaDisplay' }),
new InputOption({ key: 'media', label: 'Media', input: 'InputMedia' }),
new InputOption({ key: 'actions', label: 'Actions', input: 'InputList', options: [
new InputOption({ key: 'name', label: 'Button Label', input: 'InputText' }),
new InputOption({ key: 'href', label: 'Button Link', input: 'InputText' }),
Expand Down
4 changes: 1 addition & 3 deletions @fiction/cards/test/tpl.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ describe('verify template settings config', async () => {
"hasDemo": false,
"isPublic": false,
"templateId": "wrap",
"unusedSchema": {
"fixedHeader": "boolean",
},
"unusedSchema": {},
},
{
"hasDemo": false,
Expand Down
2 changes: 1 addition & 1 deletion @fiction/cards/trek/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const options: InputOption[] = [
new InputOption({ key: 'items', label: 'Tour Items', input: 'InputList', props: { itemName: 'Tour Item' }, options: [
new InputOption({ key: 'title', label: 'Title', input: 'InputText' }),
new InputOption({ key: 'content', label: 'Content', input: 'InputText' }),
new InputOption({ key: 'media', label: 'Media', input: 'InputMediaDisplay' }),
new InputOption({ key: 'media', label: 'Media', input: 'InputMedia' }),
new InputOption({ key: 'actions', label: 'Actions', input: 'InputList', options: [
new InputOption({ key: 'name', label: 'Button Label', input: 'InputText' }),
new InputOption({ key: 'href', label: 'Button Link', input: 'InputText' }),
Expand Down
2 changes: 1 addition & 1 deletion @fiction/core/plugin-email/templates/EmailStandard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ const markdownStyles = {
<ESection class="mt-12 mb-8 text-left">
<ESection class="inline-block">
<EColumn v-for="(item, i) in actions" :key="i" :class="i === 0 ? '' : 'pl-4'">
<EButton :href="item.href" :class="getButtonClass(item)" class="hover:opacity-80 font-bold select-none" :style="{ whiteSpace: 'nowrap' }" v-html="item.name" />
<EButton :href="item.href" :class="getButtonClass(item)" class="rounded-full hover:opacity-80 font-bold select-none" :style="{ whiteSpace: 'nowrap' }" v-html="item.name" />
</EColumn>
</ESection>
</ESection>
Expand Down
19 changes: 17 additions & 2 deletions @fiction/core/schemas/schemas.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { z } from 'zod'
import type { IconId } from '@fiction/ui/lib/systemIcons.js'
import { OrFilterGroupSchema } from '../types/endpoint.js'
import { ColorScaleSchema, colorThemeUser, colorThemeWithInvert } from '../utils/colors.js'
import type { vue } from '../utils/libraries.js'

Expand Down Expand Up @@ -181,10 +182,24 @@ export const PostSchema = z.object({
authors: z.array(UserSchema).optional(),
})

export const GlobalQuerySchema = z.object({
filters: z.array(OrFilterGroupSchema).optional(), // Array of OR filter groups
sortBy: z.string().optional(),
sortOrder: z.enum(['asc', 'desc']).optional(),
search: z.string().optional(),
dateRange: z.object({
start: z.date().optional(),
end: z.date().optional(),
}).optional(),
})

// Updated PostHandlingSchema
export const PostHandlingSchema = z.object({
mode: z.enum(['global', 'inline']).optional(),
format: z.enum(['global', 'local']).default('local'),
limit: z.number().optional(),
items: z.array(PostSchema).optional(),
posts: z.array(PostSchema).optional(),
query: GlobalQuerySchema.optional(),
})

export type PostObject = z.infer<typeof PostSchema>
export type PostHandlingObject = z.infer<typeof PostHandlingSchema>
6 changes: 4 additions & 2 deletions @fiction/core/types/endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ import type express from 'express'
import type { ErrorCode } from '../utils/error.js'
import type { UserRoles } from './roles.js'

export const DataFilterSchema = z.object({
export const AndDataFilterSchema = z.object({
field: z.string(),
value: z.union([z.string(), z.number(), z.array(z.union([z.string(), z.number()]))]),
operator: z.enum(['=', '!=', '>', '<', '>=', '<=', 'like', 'not like', 'in', 'not in']),
})

export const OrFilterGroupSchema = z.array(AndDataFilterSchema)

// sql where operators.value
export type DataFilter = z.infer<typeof DataFilterSchema>
export type DataFilter = z.infer<typeof AndDataFilterSchema>

export type IndexQuery = {
offset?: number
Expand Down
6 changes: 3 additions & 3 deletions @fiction/plugins/plugin-send/admin/SidebarEmailEditor.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<script lang="ts" setup>
import ElTool from '@fiction/admin/tools/ElTool.vue'
import ToolForm from '@fiction/admin/tools/ToolForm.vue'
import { standardOption } from '@fiction/cards/inputSets.js'
import { vue } from '@fiction/core'
import { refineOptions } from '@fiction/site/utils/schema'
import { InputOption } from '@fiction/ui/index.js'
import ElForm from '@fiction/ui/inputs/ElForm.vue'
import FormEngine from '@fiction/ui/inputs/FormEngine.vue'
import type { EditorTool } from '@fiction/admin'
import type { Card } from '@fiction/site'
import { sendTable } from '../schema.js'
Expand Down Expand Up @@ -54,7 +54,7 @@ function updatePost(config: Partial<EmailCampaignConfig>) {
<template>
<ElTool :tool="tool">
<ElForm v-if="email" id="toolForm">
<ToolForm
<FormEngine
:model-value="email.toConfig()"
:options
:input-props="{ email, card }"
Expand Down
4 changes: 2 additions & 2 deletions @fiction/plugins/plugin-send/admin/SidebarEmailPreview.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<script lang="ts" setup>
import ElTool from '@fiction/admin/tools/ElTool.vue'
import ToolForm from '@fiction/admin/tools/ToolForm.vue'
import { vue } from '@fiction/core'
import { InputOption } from '@fiction/ui/index.js'
import ElForm from '@fiction/ui/inputs/ElForm.vue'
import FormEngine from '@fiction/ui/inputs/FormEngine.vue'
import type { EditorTool } from '@fiction/admin'
import type { Card } from '@fiction/site'
Expand Down Expand Up @@ -31,7 +31,7 @@ function updatePost(config: Partial<EmailCampaignConfig>) {
<template>
<ElTool :tool="tool">
<ElForm v-if="email" id="toolForm">
<ToolForm
<FormEngine
:model-value="email.toConfig()"
:options
:input-props="{ email, card }"
Expand Down
4 changes: 2 additions & 2 deletions @fiction/plugins/plugin-send/schema.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Col, DataFilterSchema, FictionDbTable, MediaDisplaySchema, ProgressStatusSchema, standardTable } from '@fiction/core'
import { AndDataFilterSchema, Col, FictionDbTable, MediaDisplaySchema, ProgressStatusSchema, standardTable } from '@fiction/core'
import { t as postTableNames } from '@fiction/posts'

import { z } from 'zod'
Expand Down Expand Up @@ -37,7 +37,7 @@ export const sendColumns = [
new Col({ key: 'avatar', sch: () => MediaDisplaySchema, make: ({ s, col }) => s.jsonb(col.k).defaultTo({}) }),
new Col({ key: 'scheduleMode', sch: ({ z }) => z.enum(['now', 'schedule']), make: ({ s, col }) => s.string(col.k) }),
new Col({ key: 'scheduledAt', sch: ({ z }) => z.string(), make: ({ s, col }) => s.timestamp(col.k).defaultTo(null) }),
new Col({ key: 'filters', sch: ({ z }) => z.array(DataFilterSchema), make: ({ s, col }) => s.jsonb(col.k).defaultTo([]) }),
new Col({ key: 'filters', sch: ({ z }) => z.array(AndDataFilterSchema), make: ({ s, col }) => s.jsonb(col.k).defaultTo([]) }),
new Col({ key: 'counts', sch: () => EmailAnalyticsSchema, make: ({ s, col }) => s.jsonb(col.k).defaultTo({}) }),
new Col({ key: 'draft', sch: ({ z }) => z.record(z.string(), z.any()), make: ({ s, col }) => s.jsonb(col.k).defaultTo({}) }),
new Col({ key: 'userConfig', sch: () => EmailUserConfigSchema, make: ({ s, col }) => s.jsonb(col.k).defaultTo({}) }),
Expand Down
Loading

0 comments on commit 9cd8a5f

Please sign in to comment.