diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a9cbee49..e87e88275 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## v1.0.0-92 + + +### 🩹 Fixes + +- Remove template build now ([f0fa496](https://github.com/undb-io/undb/commit/f0fa496)) + +### ❀️ Contributors + +- Nichenqin ([@nichenqin](http://github.com/nichenqin)) + ## v1.0.0-91 diff --git a/apps/backend/src/modules/template/template.module.ts b/apps/backend/src/modules/template/template.module.ts index f16390717..f6c924269 100644 --- a/apps/backend/src/modules/template/template.module.ts +++ b/apps/backend/src/modules/template/template.module.ts @@ -1,12 +1,25 @@ import { singleton } from "@undb/di" -import { baseTemplateSchema } from "@undb/template" +import { None } from "@undb/domain" +import { baseTemplateSchema, injectTemplateQueryRepository, type ITemplateQueryRepository } from "@undb/template" import Elysia from "elysia" @singleton() export class TemplateModule { + constructor( + @injectTemplateQueryRepository() + private readonly templateRepo: ITemplateQueryRepository, + ) {} route() { - return new Elysia().get("/api/template/base/schema.json", () => { - return baseTemplateSchema - }) + return new Elysia() + .get("/api/template/base/schema.json", () => { + return baseTemplateSchema + }) + .get("/api/templates", async () => { + const templates = await this.templateRepo.find(None) + + return { + templates, + } + }) } } diff --git a/apps/frontend/src/lib/components/blocks/base/create-base-button.svelte b/apps/frontend/src/lib/components/blocks/base/create-base-button.svelte index bac5b7d93..3393020d3 100644 --- a/apps/frontend/src/lib/components/blocks/base/create-base-button.svelte +++ b/apps/frontend/src/lib/components/blocks/base/create-base-button.svelte @@ -1,9 +1,11 @@ {#if $hasPermission("base:create")} - + + {/if} diff --git a/apps/frontend/src/lib/components/blocks/field-control/checkbox-control.svelte b/apps/frontend/src/lib/components/blocks/field-control/checkbox-control.svelte index 380c9f1cc..e6f1e9b8b 100644 --- a/apps/frontend/src/lib/components/blocks/field-control/checkbox-control.svelte +++ b/apps/frontend/src/lib/components/blocks/field-control/checkbox-control.svelte @@ -5,4 +5,6 @@ export let value: boolean - +
+ +
diff --git a/apps/frontend/src/lib/components/blocks/grid-view/editable-cell/button-cell.svelte b/apps/frontend/src/lib/components/blocks/grid-view/editable-cell/button-cell.svelte index bc907dfc5..8efd59902 100644 --- a/apps/frontend/src/lib/components/blocks/grid-view/editable-cell/button-cell.svelte +++ b/apps/frontend/src/lib/components/blocks/grid-view/editable-cell/button-cell.svelte @@ -17,6 +17,7 @@ export let field: ButtonField export let recordId: string export let record: RecordDO | undefined + export let readonly = false const table = getTable() const recordsStore = getRecordsStore() @@ -93,7 +94,8 @@ (confirm = false)}>Cancel - Continue + Continue diff --git a/apps/frontend/src/lib/components/blocks/grid-view/editable-cell/email-cell.svelte b/apps/frontend/src/lib/components/blocks/grid-view/editable-cell/email-cell.svelte index 7b0d12570..244eb9deb 100644 --- a/apps/frontend/src/lib/components/blocks/grid-view/editable-cell/email-cell.svelte +++ b/apps/frontend/src/lib/components/blocks/grid-view/editable-cell/email-cell.svelte @@ -52,7 +52,7 @@ }} /> {:else} -
+
{#if value} {value} {/if} diff --git a/apps/frontend/src/lib/components/blocks/grid-view/editable-cell/rollup-cell.svelte b/apps/frontend/src/lib/components/blocks/grid-view/editable-cell/rollup-cell.svelte index 133f926a1..f07b599cf 100644 --- a/apps/frontend/src/lib/components/blocks/grid-view/editable-cell/rollup-cell.svelte +++ b/apps/frontend/src/lib/components/blocks/grid-view/editable-cell/rollup-cell.svelte @@ -22,7 +22,7 @@ {#each value as item} {#if !!item} {item} @@ -54,7 +54,7 @@ {#each value as item} {#if !!item} {item} diff --git a/apps/frontend/src/lib/components/blocks/grid-view/grid-view-data-table.svelte b/apps/frontend/src/lib/components/blocks/grid-view/grid-view-data-table.svelte index fe419e593..2ae13a776 100644 --- a/apps/frontend/src/lib/components/blocks/grid-view/grid-view-data-table.svelte +++ b/apps/frontend/src/lib/components/blocks/grid-view/grid-view-data-table.svelte @@ -40,6 +40,7 @@ export let currentPage: Writable export let isLoading = false export let total: number + export let hidePagination = false const t = getTable() @@ -350,6 +351,7 @@ + {#if !hidePagination}
@@ -378,6 +380,7 @@ {total} Rows
+
-
+ {/if} diff --git a/apps/frontend/src/lib/components/blocks/kanban-view/kanban-card.svelte b/apps/frontend/src/lib/components/blocks/kanban-view/kanban-card.svelte index a2aa470ef..f47ff2160 100644 --- a/apps/frontend/src/lib/components/blocks/kanban-view/kanban-card.svelte +++ b/apps/frontend/src/lib/components/blocks/kanban-view/kanban-card.svelte @@ -32,24 +32,27 @@ >
{#each fields as field, idx (field.id.value)} -
- - - - - -

{field.name.value}

-
-
-
+ {@const value = values[field.id.value]} + {#if value !== null && value !== undefined} +
+ + + + + +

{field.name.value}

+
+
+
+ {/if} {/each}
{#if isMatch} diff --git a/apps/frontend/src/lib/components/blocks/tables-nav/tables-nav.svelte b/apps/frontend/src/lib/components/blocks/tables-nav/tables-nav.svelte index bb2804f7d..2ba7ee53a 100644 --- a/apps/frontend/src/lib/components/blocks/tables-nav/tables-nav.svelte +++ b/apps/frontend/src/lib/components/blocks/tables-nav/tables-nav.svelte @@ -12,7 +12,6 @@ InboxIcon, } from "lucide-svelte" import { - CREATE_BASE_MODAL, CREATE_TABLE_MODAL, DELETE_VIEW, DUPLICATE_VIEW, @@ -20,6 +19,7 @@ toggleModal, UPDATE_VIEW, } from "$lib/store/modal.store" + import CreateBaseButton from "../base/create-base-button.svelte" import { baseId } from "$lib/store/base.store" import * as Collapsible from "$lib/components/ui/collapsible" import { cn } from "$lib/utils" @@ -27,7 +27,6 @@ import { onMount } from "svelte" import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js" import { hasPermission } from "$lib/store/space-member.store" - import { Button } from "$lib/components/ui/button" import { Skeleton } from "$lib/components/ui/skeleton" import ViewIcon from "../view/view-icon.svelte" @@ -261,9 +260,7 @@

No bases

- {#if $hasPermission("base:create")} - - {/if} +
{/if} diff --git a/apps/frontend/src/lib/components/blocks/template/template-card.svelte b/apps/frontend/src/lib/components/blocks/template/template-card.svelte index 12707d52a..e09991f25 100644 --- a/apps/frontend/src/lib/components/blocks/template/template-card.svelte +++ b/apps/frontend/src/lib/components/blocks/template/template-card.svelte @@ -42,7 +42,11 @@ {template.name} - # {template.category} +
+ {#each template.categories as category} + # {category} + {/each} +
@@ -80,6 +84,7 @@
+ + + + GitHub + + + +
diff --git a/apps/template/src/lib/components/template/template-card.svelte b/apps/template/src/lib/components/template/template-card.svelte new file mode 100644 index 000000000..fde5ba005 --- /dev/null +++ b/apps/template/src/lib/components/template/template-card.svelte @@ -0,0 +1,16 @@ + + + + + + {template.name} + + + diff --git a/apps/template/src/lib/components/template/templates.svelte b/apps/template/src/lib/components/template/templates.svelte new file mode 100644 index 000000000..d76e87a7c --- /dev/null +++ b/apps/template/src/lib/components/template/templates.svelte @@ -0,0 +1,14 @@ + + +
+
+ {#each templates as template} + + {/each} +
+
diff --git a/apps/template/src/lib/components/ui/aspect-ratio/aspect-ratio.svelte b/apps/template/src/lib/components/ui/aspect-ratio/aspect-ratio.svelte new file mode 100644 index 000000000..b3da1f3c8 --- /dev/null +++ b/apps/template/src/lib/components/ui/aspect-ratio/aspect-ratio.svelte @@ -0,0 +1,11 @@ + + + + + diff --git a/apps/template/src/lib/components/ui/aspect-ratio/index.ts b/apps/template/src/lib/components/ui/aspect-ratio/index.ts new file mode 100644 index 000000000..985c75fdb --- /dev/null +++ b/apps/template/src/lib/components/ui/aspect-ratio/index.ts @@ -0,0 +1,3 @@ +import Root from "./aspect-ratio.svelte"; + +export { Root, Root as AspectRatio }; diff --git a/apps/template/src/lib/components/ui/button/button.svelte b/apps/template/src/lib/components/ui/button/button.svelte new file mode 100644 index 000000000..86827f32d --- /dev/null +++ b/apps/template/src/lib/components/ui/button/button.svelte @@ -0,0 +1,25 @@ + + + + + diff --git a/apps/template/src/lib/components/ui/button/index.ts b/apps/template/src/lib/components/ui/button/index.ts new file mode 100644 index 000000000..af1e188cc --- /dev/null +++ b/apps/template/src/lib/components/ui/button/index.ts @@ -0,0 +1,49 @@ +import { type VariantProps, tv } from "tailwind-variants"; +import type { Button as ButtonPrimitive } from "bits-ui"; +import Root from "./button.svelte"; + +const buttonVariants = tv({ + base: "ring-offset-background focus-visible:ring-ring inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90", + outline: + "border-input bg-background hover:bg-accent hover:text-accent-foreground border", + secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-10 px-4 py-2", + sm: "h-9 rounded-md px-3", + lg: "h-11 rounded-md px-8", + icon: "h-10 w-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, +}); + +type Variant = VariantProps["variant"]; +type Size = VariantProps["size"]; + +type Props = ButtonPrimitive.Props & { + variant?: Variant; + size?: Size; +}; + +type Events = ButtonPrimitive.Events; + +export { + Root, + type Props, + type Events, + // + Root as Button, + type Props as ButtonProps, + type Events as ButtonEvents, + buttonVariants, +}; diff --git a/apps/template/src/lib/components/ui/card/card-content.svelte b/apps/template/src/lib/components/ui/card/card-content.svelte new file mode 100644 index 000000000..89d82b20b --- /dev/null +++ b/apps/template/src/lib/components/ui/card/card-content.svelte @@ -0,0 +1,13 @@ + + +
+ +
diff --git a/apps/template/src/lib/components/ui/card/card-description.svelte b/apps/template/src/lib/components/ui/card/card-description.svelte new file mode 100644 index 000000000..f65821dce --- /dev/null +++ b/apps/template/src/lib/components/ui/card/card-description.svelte @@ -0,0 +1,13 @@ + + +

+ +

diff --git a/apps/template/src/lib/components/ui/card/card-footer.svelte b/apps/template/src/lib/components/ui/card/card-footer.svelte new file mode 100644 index 000000000..32f90bbb1 --- /dev/null +++ b/apps/template/src/lib/components/ui/card/card-footer.svelte @@ -0,0 +1,13 @@ + + +
+ +
diff --git a/apps/template/src/lib/components/ui/card/card-header.svelte b/apps/template/src/lib/components/ui/card/card-header.svelte new file mode 100644 index 000000000..e4745286a --- /dev/null +++ b/apps/template/src/lib/components/ui/card/card-header.svelte @@ -0,0 +1,13 @@ + + +
+ +
diff --git a/apps/template/src/lib/components/ui/card/card-title.svelte b/apps/template/src/lib/components/ui/card/card-title.svelte new file mode 100644 index 000000000..719808ee2 --- /dev/null +++ b/apps/template/src/lib/components/ui/card/card-title.svelte @@ -0,0 +1,21 @@ + + + + + diff --git a/apps/template/src/lib/components/ui/card/card.svelte b/apps/template/src/lib/components/ui/card/card.svelte new file mode 100644 index 000000000..b69c15c01 --- /dev/null +++ b/apps/template/src/lib/components/ui/card/card.svelte @@ -0,0 +1,16 @@ + + +
+ +
diff --git a/apps/template/src/lib/components/ui/card/index.ts b/apps/template/src/lib/components/ui/card/index.ts new file mode 100644 index 000000000..bcc031d00 --- /dev/null +++ b/apps/template/src/lib/components/ui/card/index.ts @@ -0,0 +1,24 @@ +import Root from "./card.svelte"; +import Content from "./card-content.svelte"; +import Description from "./card-description.svelte"; +import Footer from "./card-footer.svelte"; +import Header from "./card-header.svelte"; +import Title from "./card-title.svelte"; + +export { + Root, + Content, + Description, + Footer, + Header, + Title, + // + Root as Card, + Content as CardContent, + Description as CardDescription, + Footer as CardFooter, + Header as CardHeader, + Title as CardTitle, +}; + +export type HeadingLevel = "h1" | "h2" | "h3" | "h4" | "h5" | "h6"; diff --git a/apps/template/src/lib/components/ui/carousel/carousel-content.svelte b/apps/template/src/lib/components/ui/carousel/carousel-content.svelte new file mode 100644 index 000000000..bc85456be --- /dev/null +++ b/apps/template/src/lib/components/ui/carousel/carousel-content.svelte @@ -0,0 +1,35 @@ + + +
+
+ +
+
diff --git a/apps/template/src/lib/components/ui/carousel/carousel-item.svelte b/apps/template/src/lib/components/ui/carousel/carousel-item.svelte new file mode 100644 index 000000000..3d0fdfbb2 --- /dev/null +++ b/apps/template/src/lib/components/ui/carousel/carousel-item.svelte @@ -0,0 +1,25 @@ + + +
+ +
diff --git a/apps/template/src/lib/components/ui/carousel/carousel-next.svelte b/apps/template/src/lib/components/ui/carousel/carousel-next.svelte new file mode 100644 index 000000000..c6f2e297b --- /dev/null +++ b/apps/template/src/lib/components/ui/carousel/carousel-next.svelte @@ -0,0 +1,39 @@ + + + diff --git a/apps/template/src/lib/components/ui/carousel/carousel-previous.svelte b/apps/template/src/lib/components/ui/carousel/carousel-previous.svelte new file mode 100644 index 000000000..bd3169b73 --- /dev/null +++ b/apps/template/src/lib/components/ui/carousel/carousel-previous.svelte @@ -0,0 +1,40 @@ + + + diff --git a/apps/template/src/lib/components/ui/carousel/carousel.svelte b/apps/template/src/lib/components/ui/carousel/carousel.svelte new file mode 100644 index 000000000..12243036b --- /dev/null +++ b/apps/template/src/lib/components/ui/carousel/carousel.svelte @@ -0,0 +1,98 @@ + + +
+ +
diff --git a/apps/template/src/lib/components/ui/carousel/context.ts b/apps/template/src/lib/components/ui/carousel/context.ts new file mode 100644 index 000000000..c90b4cb84 --- /dev/null +++ b/apps/template/src/lib/components/ui/carousel/context.ts @@ -0,0 +1,56 @@ +import type { EmblaCarouselSvelteType } from "embla-carousel-svelte"; +import type emblaCarouselSvelte from "embla-carousel-svelte"; +import { getContext, hasContext, setContext } from "svelte"; +import type { HTMLAttributes } from "svelte/elements"; +import type { Readable, Writable } from "svelte/store"; + +export type CarouselAPI = + NonNullable["on:emblaInit"]> extends ( + evt: CustomEvent + ) => void + ? CarouselAPI + : never; + +type EmblaCarouselConfig = NonNullable[1]>; + +export type CarouselOptions = EmblaCarouselConfig["options"]; +export type CarouselPlugins = EmblaCarouselConfig["plugins"]; + +//// + +export type CarouselProps = { + opts?: CarouselOptions; + plugins?: CarouselPlugins; + api?: CarouselAPI; + orientation?: "horizontal" | "vertical"; +} & HTMLAttributes; + +const EMBLA_CAROUSEL_CONTEXT = Symbol("EMBLA_CAROUSEL_CONTEXT"); + +type EmblaContext = { + api: Writable; + orientation: Writable<"horizontal" | "vertical">; + scrollNext: () => void; + scrollPrev: () => void; + canScrollNext: Readable; + canScrollPrev: Readable; + handleKeyDown: (e: KeyboardEvent) => void; + options: Writable; + plugins: Writable; + onInit: (e: CustomEvent) => void; + scrollTo: (index: number, jump?: boolean) => void; + scrollSnaps: Readable; + selectedIndex: Readable; +}; + +export function setEmblaContext(config: EmblaContext): EmblaContext { + setContext(EMBLA_CAROUSEL_CONTEXT, config); + return config; +} + +export function getEmblaContext(name = "This component") { + if (!hasContext(EMBLA_CAROUSEL_CONTEXT)) { + throw new Error(`${name} must be used within a component`); + } + return getContext>(EMBLA_CAROUSEL_CONTEXT); +} diff --git a/apps/template/src/lib/components/ui/carousel/index.ts b/apps/template/src/lib/components/ui/carousel/index.ts new file mode 100644 index 000000000..78102bf79 --- /dev/null +++ b/apps/template/src/lib/components/ui/carousel/index.ts @@ -0,0 +1,5 @@ +export { default as Root } from "./carousel.svelte"; +export { default as Content } from "./carousel-content.svelte"; +export { default as Item } from "./carousel-item.svelte"; +export { default as Previous } from "./carousel-previous.svelte"; +export { default as Next } from "./carousel-next.svelte"; diff --git a/apps/template/src/lib/components/ui/dialog/dialog-content.svelte b/apps/template/src/lib/components/ui/dialog/dialog-content.svelte new file mode 100644 index 000000000..a06ccb293 --- /dev/null +++ b/apps/template/src/lib/components/ui/dialog/dialog-content.svelte @@ -0,0 +1,36 @@ + + + + + + + + + Close + + + diff --git a/apps/template/src/lib/components/ui/dialog/dialog-description.svelte b/apps/template/src/lib/components/ui/dialog/dialog-description.svelte new file mode 100644 index 000000000..8bc70cca6 --- /dev/null +++ b/apps/template/src/lib/components/ui/dialog/dialog-description.svelte @@ -0,0 +1,16 @@ + + + + + diff --git a/apps/template/src/lib/components/ui/dialog/dialog-footer.svelte b/apps/template/src/lib/components/ui/dialog/dialog-footer.svelte new file mode 100644 index 000000000..a235d1f8d --- /dev/null +++ b/apps/template/src/lib/components/ui/dialog/dialog-footer.svelte @@ -0,0 +1,16 @@ + + +
+ +
diff --git a/apps/template/src/lib/components/ui/dialog/dialog-header.svelte b/apps/template/src/lib/components/ui/dialog/dialog-header.svelte new file mode 100644 index 000000000..6b4448c7c --- /dev/null +++ b/apps/template/src/lib/components/ui/dialog/dialog-header.svelte @@ -0,0 +1,13 @@ + + +
+ +
diff --git a/apps/template/src/lib/components/ui/dialog/dialog-overlay.svelte b/apps/template/src/lib/components/ui/dialog/dialog-overlay.svelte new file mode 100644 index 000000000..1d376e46d --- /dev/null +++ b/apps/template/src/lib/components/ui/dialog/dialog-overlay.svelte @@ -0,0 +1,21 @@ + + + diff --git a/apps/template/src/lib/components/ui/dialog/dialog-portal.svelte b/apps/template/src/lib/components/ui/dialog/dialog-portal.svelte new file mode 100644 index 000000000..eb5d0a574 --- /dev/null +++ b/apps/template/src/lib/components/ui/dialog/dialog-portal.svelte @@ -0,0 +1,8 @@ + + + + + diff --git a/apps/template/src/lib/components/ui/dialog/dialog-title.svelte b/apps/template/src/lib/components/ui/dialog/dialog-title.svelte new file mode 100644 index 000000000..06574f3e9 --- /dev/null +++ b/apps/template/src/lib/components/ui/dialog/dialog-title.svelte @@ -0,0 +1,16 @@ + + + + + diff --git a/apps/template/src/lib/components/ui/dialog/index.ts b/apps/template/src/lib/components/ui/dialog/index.ts new file mode 100644 index 000000000..b17ba5e6d --- /dev/null +++ b/apps/template/src/lib/components/ui/dialog/index.ts @@ -0,0 +1,37 @@ +import { Dialog as DialogPrimitive } from "bits-ui"; + +import Title from "./dialog-title.svelte"; +import Portal from "./dialog-portal.svelte"; +import Footer from "./dialog-footer.svelte"; +import Header from "./dialog-header.svelte"; +import Overlay from "./dialog-overlay.svelte"; +import Content from "./dialog-content.svelte"; +import Description from "./dialog-description.svelte"; + +const Root = DialogPrimitive.Root; +const Trigger = DialogPrimitive.Trigger; +const Close = DialogPrimitive.Close; + +export { + Root, + Title, + Portal, + Footer, + Header, + Trigger, + Overlay, + Content, + Description, + Close, + // + Root as Dialog, + Title as DialogTitle, + Portal as DialogPortal, + Footer as DialogFooter, + Header as DialogHeader, + Trigger as DialogTrigger, + Overlay as DialogOverlay, + Content as DialogContent, + Description as DialogDescription, + Close as DialogClose, +}; diff --git a/apps/template/src/lib/components/ui/hover-card/hover-card-content.svelte b/apps/template/src/lib/components/ui/hover-card/hover-card-content.svelte new file mode 100644 index 000000000..e3f929878 --- /dev/null +++ b/apps/template/src/lib/components/ui/hover-card/hover-card-content.svelte @@ -0,0 +1,27 @@ + + + + + diff --git a/apps/template/src/lib/components/ui/hover-card/index.ts b/apps/template/src/lib/components/ui/hover-card/index.ts new file mode 100644 index 000000000..2d0c5c5af --- /dev/null +++ b/apps/template/src/lib/components/ui/hover-card/index.ts @@ -0,0 +1,14 @@ +import { LinkPreview as HoverCardPrimitive } from "bits-ui"; + +import Content from "./hover-card-content.svelte"; +const Root = HoverCardPrimitive.Root; +const Trigger = HoverCardPrimitive.Trigger; + +export { + Root, + Content, + Trigger, + Root as HoverCard, + Content as HoverCardContent, + Trigger as HoverCardTrigger, +}; diff --git a/apps/template/src/lib/images/github.svg b/apps/template/src/lib/images/github.svg new file mode 100644 index 000000000..bc5d249d3 --- /dev/null +++ b/apps/template/src/lib/images/github.svg @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/apps/template/src/lib/images/logo.svg b/apps/template/src/lib/images/logo.svg new file mode 100644 index 000000000..ab6b72099 --- /dev/null +++ b/apps/template/src/lib/images/logo.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apps/template/src/lib/images/svelte-logo.svg b/apps/template/src/lib/images/svelte-logo.svg new file mode 100644 index 000000000..49492a83c --- /dev/null +++ b/apps/template/src/lib/images/svelte-logo.svg @@ -0,0 +1 @@ +svelte-logo \ No newline at end of file diff --git a/apps/template/src/lib/images/svelte-welcome.png b/apps/template/src/lib/images/svelte-welcome.png new file mode 100644 index 000000000..fe7d2d6b5 Binary files /dev/null and b/apps/template/src/lib/images/svelte-welcome.png differ diff --git a/apps/template/src/lib/images/svelte-welcome.webp b/apps/template/src/lib/images/svelte-welcome.webp new file mode 100644 index 000000000..6ec1a28d6 Binary files /dev/null and b/apps/template/src/lib/images/svelte-welcome.webp differ diff --git a/apps/template/src/lib/utils.ts b/apps/template/src/lib/utils.ts new file mode 100644 index 000000000..88712453a --- /dev/null +++ b/apps/template/src/lib/utils.ts @@ -0,0 +1,62 @@ +import { type ClassValue, clsx } from "clsx"; +import { twMerge } from "tailwind-merge"; +import { cubicOut } from "svelte/easing"; +import type { TransitionConfig } from "svelte/transition"; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} + +type FlyAndScaleParams = { + y?: number; + x?: number; + start?: number; + duration?: number; +}; + +export const flyAndScale = ( + node: Element, + params: FlyAndScaleParams = { y: -8, x: 0, start: 0.95, duration: 150 } +): TransitionConfig => { + const style = getComputedStyle(node); + const transform = style.transform === "none" ? "" : style.transform; + + const scaleConversion = ( + valueA: number, + scaleA: [number, number], + scaleB: [number, number] + ) => { + const [minA, maxA] = scaleA; + const [minB, maxB] = scaleB; + + const percentage = (valueA - minA) / (maxA - minA); + const valueB = percentage * (maxB - minB) + minB; + + return valueB; + }; + + const styleToString = ( + style: Record + ): string => { + return Object.keys(style).reduce((str, key) => { + if (style[key] === undefined) return str; + return str + `${key}:${style[key]};`; + }, ""); + }; + + return { + duration: params.duration ?? 200, + delay: 0, + css: (t) => { + const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0]); + const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0]); + const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1]); + + return styleToString({ + transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`, + opacity: t + }); + }, + easing: cubicOut + }; +}; \ No newline at end of file diff --git a/apps/template/src/routes/+layout.svelte b/apps/template/src/routes/+layout.svelte new file mode 100644 index 000000000..bcd158972 --- /dev/null +++ b/apps/template/src/routes/+layout.svelte @@ -0,0 +1,29 @@ + + +
+
+
+ +
+
+
+ + + {#if !dev} + + {/if} + + + diff --git a/apps/template/src/routes/+page.server.ts b/apps/template/src/routes/+page.server.ts new file mode 100644 index 000000000..f30b2e4a8 --- /dev/null +++ b/apps/template/src/routes/+page.server.ts @@ -0,0 +1,11 @@ +import type { ITemplateDTO } from "@undb/template" +import type { PageServerLoad } from "./$types" + +export const load: PageServerLoad = async ({ fetch }) => { + const res = await fetch("http://localhost:3721/api/templates") + const { templates } = (await res.json()) as { templates: ITemplateDTO[] } + + return { + templates, + } +} diff --git a/apps/template/src/routes/+page.svelte b/apps/template/src/routes/+page.svelte new file mode 100644 index 000000000..e437fccfa --- /dev/null +++ b/apps/template/src/routes/+page.svelte @@ -0,0 +1,21 @@ + + + + Templates | Undb + + +
+

+ Undb starter templates +

+ +

✨ Build your database with thousands of templates

+

🚧 Work in progress

+ +
diff --git a/apps/template/src/routes/+page.ts b/apps/template/src/routes/+page.ts new file mode 100644 index 000000000..2554216be --- /dev/null +++ b/apps/template/src/routes/+page.ts @@ -0,0 +1 @@ +export const prerender = "auto" diff --git a/apps/template/src/routes/template/[templateId]/+layout.svelte b/apps/template/src/routes/template/[templateId]/+layout.svelte new file mode 100644 index 000000000..48caab79f --- /dev/null +++ b/apps/template/src/routes/template/[templateId]/+layout.svelte @@ -0,0 +1,3 @@ +
+ +
diff --git a/apps/template/src/routes/template/[templateId]/+page.server.ts b/apps/template/src/routes/template/[templateId]/+page.server.ts new file mode 100644 index 000000000..0b5e92e9f --- /dev/null +++ b/apps/template/src/routes/template/[templateId]/+page.server.ts @@ -0,0 +1,5 @@ +import type { PageServerLoad } from "./$types" + +export const load: PageServerLoad = async ({ params, fetch }) => { + return { template: undefined } +} diff --git a/apps/template/src/routes/template/[templateId]/+page.svelte b/apps/template/src/routes/template/[templateId]/+page.svelte new file mode 100644 index 000000000..34fec509b --- /dev/null +++ b/apps/template/src/routes/template/[templateId]/+page.svelte @@ -0,0 +1,67 @@ + + + + {template?.values.Title} | Undb Templates + + +
+
+ {#if template} + + {@const cover = template.values.Cover?.[0]} + {#if cover} + + {template.values.Title} + + {/if} + +

{template.values.Title}

+ + {#if template.values.Images?.length} +
+

Images

+
+ {#each template.values.Images ?? [] as image} + + + {template.values.Title} + + + {template.values.Title} + + + {/each} +
+
+ {/if} + +
+

Summary

+

+ {template.values.Summary} +

+
+ {/if} +
+ + {#if template} +
+

Template Preview

+
+ {/if} +
diff --git a/apps/template/src/routes/template/[templateId]/+page.ts b/apps/template/src/routes/template/[templateId]/+page.ts new file mode 100644 index 000000000..2554216be --- /dev/null +++ b/apps/template/src/routes/template/[templateId]/+page.ts @@ -0,0 +1 @@ +export const prerender = "auto" diff --git a/apps/template/static/favicon.png b/apps/template/static/favicon.png new file mode 100644 index 000000000..825b9e65a Binary files /dev/null and b/apps/template/static/favicon.png differ diff --git a/apps/template/static/robots.txt b/apps/template/static/robots.txt new file mode 100644 index 000000000..e9e57dc4d --- /dev/null +++ b/apps/template/static/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/apps/template/svelte.config.js b/apps/template/svelte.config.js new file mode 100644 index 000000000..c40d38b75 --- /dev/null +++ b/apps/template/svelte.config.js @@ -0,0 +1,21 @@ +import adapter from "svelte-adapter-bun" +import { vitePreprocess } from "@sveltejs/vite-plugin-svelte" + +/** @type {import('@sveltejs/kit').Config} */ +const config = { + // Consult https://kit.svelte.dev/docs/integrations#preprocessors + // for more information about preprocessors + preprocess: vitePreprocess(), + + kit: { + // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. + // If your environment is not supported, or you settled on a specific environment, switch out the adapter. + // See https://kit.svelte.dev/docs/adapters for more information about adapters. + adapter: adapter(), + alias: { + "@/*": "./path/to/lib/*", + }, + }, +} + +export default config diff --git a/apps/template/tailwind.config.ts b/apps/template/tailwind.config.ts new file mode 100644 index 000000000..c4bf23554 --- /dev/null +++ b/apps/template/tailwind.config.ts @@ -0,0 +1,64 @@ +import { fontFamily } from "tailwindcss/defaultTheme"; +import type { Config } from "tailwindcss"; + +const config: Config = { + darkMode: ["class"], + content: ["./src/**/*.{html,js,svelte,ts}"], + safelist: ["dark"], + theme: { + container: { + center: true, + padding: "2rem", + screens: { + "2xl": "1400px" + } + }, + extend: { + colors: { + border: "hsl(var(--border) / )", + input: "hsl(var(--input) / )", + ring: "hsl(var(--ring) / )", + background: "hsl(var(--background) / )", + foreground: "hsl(var(--foreground) / )", + primary: { + DEFAULT: "hsl(var(--primary) / )", + foreground: "hsl(var(--primary-foreground) / )" + }, + secondary: { + DEFAULT: "hsl(var(--secondary) / )", + foreground: "hsl(var(--secondary-foreground) / )" + }, + destructive: { + DEFAULT: "hsl(var(--destructive) / )", + foreground: "hsl(var(--destructive-foreground) / )" + }, + muted: { + DEFAULT: "hsl(var(--muted) / )", + foreground: "hsl(var(--muted-foreground) / )" + }, + accent: { + DEFAULT: "hsl(var(--accent) / )", + foreground: "hsl(var(--accent-foreground) / )" + }, + popover: { + DEFAULT: "hsl(var(--popover) / )", + foreground: "hsl(var(--popover-foreground) / )" + }, + card: { + DEFAULT: "hsl(var(--card) / )", + foreground: "hsl(var(--card-foreground) / )" + } + }, + borderRadius: { + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)" + }, + fontFamily: { + sans: [...fontFamily.sans] + } + } + }, +}; + +export default config; diff --git a/apps/template/tsconfig.json b/apps/template/tsconfig.json new file mode 100644 index 000000000..fc93cbd94 --- /dev/null +++ b/apps/template/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + } + // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias + // except $lib which is handled by https://kit.svelte.dev/docs/configuration#files + // + // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes + // from the referenced tsconfig.json - TypeScript does not merge them in +} diff --git a/apps/template/vite.config.ts b/apps/template/vite.config.ts new file mode 100644 index 000000000..daa9604c8 --- /dev/null +++ b/apps/template/vite.config.ts @@ -0,0 +1,9 @@ +import { sveltekit } from "@sveltejs/kit/vite"; +import { defineConfig } from "vite"; + +export default defineConfig({ + server: { + port: 5735, + }, + plugins: [sveltekit()], +}); diff --git a/bun.lockb b/bun.lockb index 845e6949b..a7dd6a5ae 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 9e1e02b0b..375da1f52 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "undb", - "version": "1.0.0-91", + "version": "1.0.0-92", "private": true, "scripts": { "build": "NODE_ENV=production bun --bun turbo build", diff --git a/packages/env/src/index.ts b/packages/env/src/index.ts index 0e729e303..46bab5132 100644 --- a/packages/env/src/index.ts +++ b/packages/env/src/index.ts @@ -148,6 +148,7 @@ export const env = createEnv({ clientPrefix: "UNDB_PUBLIC_", client: {}, server: { + NODE_ENV: z.enum(["development", "production", "test"]).default("development"), UNDB_BASE_URL: z.string().optional().default("http://localhost:3721"), UNDB_COOKIE_DOMAIN: z.string().optional(), }, diff --git a/packages/persistence/src/template/template-data.ts b/packages/persistence/src/template/template-data.ts index 57cd8f726..316540361 100644 --- a/packages/persistence/src/template/template-data.ts +++ b/packages/persistence/src/template/template-data.ts @@ -5,7 +5,7 @@ export const templateData: ITemplateDTO[] = [ id: "550e8400-e29b-41d4-a716-446655440000", icon: "πŸš€", name: "Project Management", - category: "it", + categories: ["it"], description: "A comprehensive template for managing projects, tasks, and team collaboration. It includes features for tracking project progress, assigning tasks, managing resources, and facilitating team communication, helping you achieve project goals more efficiently.", template: { @@ -13,12 +13,35 @@ export const templateData: ITemplateDTO[] = [ template: templates.projectManagement as IBaseTemplateDTO, }, }, + { + id: "6ba7b814-9dad-11d1-80b4-00c04fd430c8", + icon: "πŸ’Ό", + name: "CRM", + categories: ["sales"], + description: "A template for managing customer relationships, deals, and activities.", + template: { + type: "base", + template: templates.crm as IBaseTemplateDTO, + }, + }, + { + id: "f47ac10b-58cc-4372-a567-0e02b2c3d479", + icon: "πŸ’Ό", + name: "Sales CRM", + categories: ["sales", "crm"], + description: + "A CRM for sales. It includes features for tracking customer interactions, managing deals, and analyzing sales data.", + template: { + type: "base", + template: templates.salesCrm as IBaseTemplateDTO, + }, + }, { id: "6ba7b810-9dad-11d1-80b4-00c04fd430c8", icon: "πŸŽ‰", name: "Event Planning List", description: "A template for planning events, including tasks, deadlines, and resources.", - category: "sales", + categories: ["sales"], template: { type: "base", template: templates.eventPlaningList as IBaseTemplateDTO, @@ -28,7 +51,7 @@ export const templateData: ITemplateDTO[] = [ id: "6ba7b811-9dad-11d1-80b4-00c04fd430c8", icon: "πŸ“", name: "To-Do List", - category: "other", + categories: ["other"], description: "A simple template for managing daily tasks and reminders.", template: { type: "base", @@ -39,22 +62,25 @@ export const templateData: ITemplateDTO[] = [ id: "6ba7b813-9dad-11d1-80b4-00c04fd430c8", icon: "πŸ“¦", name: "Office Inventory Management", - category: "finance", + categories: ["finance"], description: "A template for managing office supplies, equipment, and inventory.", template: { type: "base", template: templates.officeInventoryManagement as IBaseTemplateDTO, }, }, - { - id: "6ba7b814-9dad-11d1-80b4-00c04fd430c8", - icon: "πŸ’Ό", - name: "CRM", - category: "sales", - description: "A template for managing customer relationships, deals, and activities.", - template: { - type: "base", - template: templates.crm as IBaseTemplateDTO, - }, - }, ] + +// if (env.NODE_ENV === "development") { +// templateData.unshift({ +// id: "test", +// icon: "πŸ’Ό", +// name: "Test", +// categories: ["sales"], +// description: "A template for testing", +// template: { +// type: "base", +// template: templates.test as IBaseTemplateDTO, +// }, +// }) +// } diff --git a/packages/table/src/modules/schema/fields/variants/checkbox-field/checkbox-field-constraint.vo.ts b/packages/table/src/modules/schema/fields/variants/checkbox-field/checkbox-field-constraint.vo.ts index 40ccb625a..9d42062d3 100644 --- a/packages/table/src/modules/schema/fields/variants/checkbox-field/checkbox-field-constraint.vo.ts +++ b/packages/table/src/modules/schema/fields/variants/checkbox-field/checkbox-field-constraint.vo.ts @@ -12,7 +12,7 @@ export class CheckboxFieldConstraint extends FieldConstraintVO export type ICreateReferenceFieldDTO = z.infer export const updateReferenceFieldDTO = createReferenceFieldDTO @@ -121,15 +126,27 @@ export class ReferenceField extends AbstractField< name: dto.name, option: { foreignTableId, condition, isOwner: true }, id: FieldIdVo.fromStringOrCreate(dto.id).value, + constraint: dto.constraint, }) } - static createSymmetricField(foreignTable: TableDo, table: TableDo, field: ReferenceField) { + static createSymmetricField( + foreignTable: TableDo, + table: TableDo, + field: ReferenceField, + dto?: ICreateTablesReferenceFieldDTO, + ) { const symmetricField = new ReferenceField({ type: "reference", - name: table.schema.getNextFieldName(foreignTable.name.value), - option: { isOwner: false, foreignTableId: foreignTable.id.value, symmetricFieldId: field.id.value }, - id: FieldIdVo.create().value, + id: dto?.id || FieldIdVo.create().value, + name: table.schema.getNextFieldName(dto?.name || foreignTable.name.value), + option: { + isOwner: false, + foreignTableId: foreignTable.id.value, + symmetricFieldId: field.id.value, + condition: dto?.option.condition, + }, + constraint: dto?.constraint, }) symmetricField.connect(field) diff --git a/packages/table/src/table.factory.ts b/packages/table/src/table.factory.ts index a64008ea0..8b28f1dc9 100644 --- a/packages/table/src/table.factory.ts +++ b/packages/table/src/table.factory.ts @@ -10,6 +10,7 @@ import { type ICreateFieldDTO, type ICreateReferenceFieldDTO, type ICreateSchemaDTO, + type ICreateTablesReferenceFieldDTO, } from "./modules" import { FieldNameShouldBeUnique } from "./modules/schema/rules" import { TableIdVo } from "./table-id.vo" @@ -82,15 +83,25 @@ export class TableFactory { const baseName = getNextName(baseNames, base.name.value) const referenceIds = new Set() + const symmetricFields: ICreateTablesReferenceFieldDTO[] = [] const tables = dtos.map((dto) => { const schema = dto.schema - .filter((f) => f.type !== "rollup") .map((field) => { + if (field.type === "rollup") { + return null + } if (field.type === "reference") { - const foreignTableId = ids.mustGet(baseName, field.option.foreignTable.tableName) if (!field.id) { field.id = FieldIdVo.create().value } + + // Symmetric field + if (!field.option.foreignTable) { + symmetricFields.push(field) + return null + } + + const foreignTableId = ids.mustGet(baseName, field.option.foreignTable.tableName) if (field.option.createSymmetricField) { referenceIds.add(field.id!) } @@ -103,7 +114,8 @@ export class TableFactory { } as ICreateReferenceFieldDTO } return field as ICreateFieldDTO - }) as ICreateSchemaDTO + }) + .filter((v) => !!v) as ICreateSchemaDTO const id = ids.mustGet(baseName, dto.name) const table = this.create({ ...dto, id, schema }) @@ -118,7 +130,9 @@ export class TableFactory { if (!foreignTable) { throw new Error("Foreign table not found") } - const symmetricField = ReferenceField.createSymmetricField(table, foreignTable, referenceField) + const dto = symmetricFields.find((f) => f.option.symmetricFieldId === referenceField.id.value) + console.log(dto) + const symmetricField = ReferenceField.createSymmetricField(table, foreignTable, referenceField, dto) foreignTable.$createFieldSpec(symmetricField) } } diff --git a/packages/template/src/dto/template.dto.ts b/packages/template/src/dto/template.dto.ts index c8c20aa6b..fa824139b 100644 --- a/packages/template/src/dto/template.dto.ts +++ b/packages/template/src/dto/template.dto.ts @@ -9,7 +9,7 @@ export const templateDTO = z.object({ icon: z.string().optional(), name: templateName, description: z.string().optional(), - category: templateCategory, + categories: templateCategory.array(), template: templateSchemaVariants, }) diff --git a/packages/template/src/template/value-objects/template-category.vo.ts b/packages/template/src/template/value-objects/template-category.vo.ts index 8b7faab27..d58279228 100644 --- a/packages/template/src/template/value-objects/template-category.vo.ts +++ b/packages/template/src/template/value-objects/template-category.vo.ts @@ -3,6 +3,7 @@ import { z } from "@undb/zod" export const templateCategory = z.enum([ "hr", + "crm", "marketing", "sales", "it", diff --git a/packages/template/src/templates/index.ts b/packages/template/src/templates/index.ts index 60eb249f0..fd1d0bd13 100644 --- a/packages/template/src/templates/index.ts +++ b/packages/template/src/templates/index.ts @@ -2,14 +2,18 @@ import { default as crm } from "./crm.base.json" import { default as eventPlaningList } from "./eventPlaning.base.json" import { default as officeInventoryManagement } from "./officeInventoryManagement.base.json" import { default as projectManagement } from "./projectManagement.base.json" +import { default as salesCrm } from "./salesCrm.base.json" +import { default as test } from "./test.base.json" import { default as todoList } from "./todoList.base.json" const templates = { + test, todoList, projectManagement, officeInventoryManagement, eventPlaningList, crm, + salesCrm, } as const export { templates } diff --git a/packages/template/src/templates/salesCrm.base.json b/packages/template/src/templates/salesCrm.base.json new file mode 100644 index 000000000..56ed91520 --- /dev/null +++ b/packages/template/src/templates/salesCrm.base.json @@ -0,0 +1,712 @@ +{ + "Sales CRM": { + "tables": { + "CRM": { + "schema": { + "Name": { + "id": "name", + "type": "string", + "constraint": { + "required": true + }, + "display": true + }, + "Company": { + "id": "company", + "type": "string" + }, + "Status": { + "id": "status", + "type": "select", + "constraint": { + "max": 1 + }, + "defaultValue": "lead", + "option": { + "options": [ + { + "id": "lead", + "name": "Lead", + "color": "blue" + }, + { + "id": "qualified", + "name": "Qualified", + "color": "green" + }, + { + "id": "customer", + "name": "Customer", + "color": "purple" + } + ] + } + }, + "Priority": { + "id": "priority", + "type": "select", + "constraint": { + "max": 1 + }, + "option": { + "options": [ + { + "id": "low", + "name": "Low", + "color": "gray" + }, + { + "id": "medium", + "name": "Medium", + "color": "yellow" + }, + { + "id": "high", + "name": "High", + "color": "red" + } + ] + } + }, + "Estimated Value": { + "id": "estimatedValue", + "type": "currency", + "option": { + "symbol": "$" + } + }, + "Account Owner": { + "id": "accountOwner", + "type": "string" + }, + "Email": { + "id": "email", + "type": "email" + }, + "Phone": { + "id": "phone", + "type": "string" + }, + "Expected Close": { + "id": "expectedClose", + "type": "date" + }, + "Last Contact": { + "id": "lastContact", + "type": "date" + }, + "Contacted": { + "id": "contacted", + "type": "checkbox" + }, + "Contacted Button": { + "id": "contactedButton", + "type": "button", + "option": { + "label": "Mark Contacted", + "action": { + "confirm": true, + "type": "update", + "values": [ + { + "field": "contacted", + "value": true + } + ] + } + } + } + }, + "views": { + "All Contacts": { + "type": "grid" + }, + "By Status": { + "type": "kanban", + "kanban": { + "field": "status" + } + } + }, + "records": [ + { + "Name": "John Smith", + "Company": "Acme Corp", + "Status": "lead", + "Priority": "high", + "Estimated Value": 50000, + "Account Owner": "Sarah Johnson", + "Email": "john.smith@acme.com", + "Contacted": false, + "Expected Close": "2023-12-15", + "Last Contact": null + }, + { + "Name": "Emily Brown", + "Company": "TechGiant Inc", + "Status": "qualified", + "Priority": "medium", + "Estimated Value": 30000, + "Account Owner": "Michael Lee", + "Email": "emily.brown@techgiant.com", + "Contacted": true, + "Expected Close": "2023-11-30", + "Last Contact": "2023-10-05" + }, + { + "Name": "David Wilson", + "Company": "Global Solutions", + "Status": "customer", + "Priority": "low", + "Estimated Value": 20000, + "Account Owner": "Jennifer Chen", + "Email": "david.wilson@globalsolutions.com", + "Contacted": true, + "Expected Close": "2023-10-20", + "Last Contact": "2023-09-28" + }, + { + "Name": "Lisa Taylor", + "Company": "Innovate Systems", + "Status": "lead", + "Priority": "high", + "Estimated Value": 80000, + "Account Owner": "Robert Kim", + "Email": "lisa.taylor@innovatesystems.com", + "Contacted": false, + "Expected Close": "2024-01-10", + "Last Contact": null + }, + { + "Name": "Mark Johnson", + "Company": "Smart Tech", + "Status": "qualified", + "Priority": "medium", + "Estimated Value": 40000, + "Account Owner": "Amanda Wong", + "Email": "mark.johnson@smarttech.com", + "Contacted": true, + "Expected Close": "2023-12-05", + "Last Contact": "2023-10-12" + }, + { + "Name": "Sarah Davis", + "Company": "Mega Retail", + "Status": "customer", + "Priority": "high", + "Estimated Value": 60000, + "Account Owner": "Thomas Zhang", + "Email": "sarah.davis@megaretail.com", + "Contacted": true, + "Expected Close": "2023-11-15", + "Last Contact": "2023-10-01" + }, + { + "Name": "James Wilson", + "Company": "Tech Solutions", + "Status": "lead", + "Priority": "medium", + "Estimated Value": 35000, + "Account Owner": "Emma Liu", + "Email": "james.wilson@techsolutions.com", + "Contacted": false, + "Expected Close": "2023-12-20", + "Last Contact": null + }, + { + "Name": "Jessica Lee", + "Company": "Global Innovations", + "Status": "qualified", + "Priority": "high", + "Estimated Value": 70000, + "Account Owner": "Daniel Park", + "Email": "jessica.lee@globalinnovations.com", + "Contacted": true, + "Expected Close": "2023-11-25", + "Last Contact": "2023-10-08" + }, + { + "Name": "Ryan Chen", + "Company": "Smart Systems", + "Status": "customer", + "Priority": "low", + "Estimated Value": 25000, + "Account Owner": "Olivia Wang", + "Email": "ryan.chen@smartsystems.com", + "Contacted": true, + "Expected Close": "2023-10-30", + "Last Contact": "2023-09-22" + }, + { + "Name": "Michelle Kim", + "Company": "Innovative Tech", + "Status": "lead", + "Priority": "medium", + "Estimated Value": 45000, + "Account Owner": "Andrew Ng", + "Email": "michelle.kim@innovativetech.com", + "Contacted": false, + "Expected Close": "2023-12-10", + "Last Contact": null + }, + { + "Name": "Kevin Zhang", + "Company": "Global Tech", + "Status": "qualified", + "Priority": "high", + "Estimated Value": 55000, + "Account Owner": "Sophia Li", + "Email": "kevin.zhang@globaltech.com", + "Contacted": true, + "Expected Close": "2023-11-20", + "Last Contact": "2023-10-03" + }, + { + "Name": "Laura Martinez", + "Company": "Smart Solutions", + "Status": "customer", + "Priority": "medium", + "Estimated Value": 38000, + "Account Owner": "Chris Wong", + "Email": "laura.martinez@smartsolutions.com", + "Contacted": true, + "Expected Close": "2023-10-25", + "Last Contact": "2023-09-30" + }, + { + "Name": "Alex Johnson", + "Company": "Tech Innovators", + "Status": "lead", + "Priority": "low", + "Estimated Value": 28000, + "Account Owner": "Rachel Kim", + "Email": "alex.johnson@techinnovators.com", + "Contacted": false, + "Expected Close": "2023-12-30", + "Last Contact": null + }, + { + "Name": "Samantha Brown", + "Company": "Global Systems", + "Status": "qualified", + "Priority": "high", + "Estimated Value": 65000, + "Account Owner": "Eric Chen", + "Email": "samantha.brown@globalsystems.com", + "Contacted": true, + "Expected Close": "2023-11-10", + "Last Contact": "2023-10-07" + }, + { + "Name": "Daniel Lee", + "Company": "Innovative Solutions", + "Status": "customer", + "Priority": "medium", + "Estimated Value": 42000, + "Account Owner": "Megan Liu", + "Email": "daniel.lee@innovativesolutions.com", + "Contacted": true, + "Expected Close": "2023-10-15", + "Last Contact": "2023-09-25" + }, + { + "Name": "Emma Wilson", + "Company": "Tech Giants", + "Status": "lead", + "Priority": "high", + "Estimated Value": 75000, + "Account Owner": "Jason Wang", + "Email": "emma.wilson@techgiants.com", + "Contacted": false, + "Expected Close": "2024-01-05", + "Last Contact": null + }, + { + "Name": "Michael Chen", + "Company": "Smart Innovations", + "Status": "qualified", + "Priority": "low", + "Estimated Value": 32000, + "Account Owner": "Linda Kim", + "Email": "michael.chen@smartinnovations.com", + "Contacted": true, + "Expected Close": "2023-11-28", + "Last Contact": "2023-10-10" + }, + { + "Name": "Olivia Davis", + "Company": "Global Tech Solutions", + "Status": "customer", + "Priority": "high", + "Estimated Value": 58000, + "Account Owner": "David Zhang", + "Email": "olivia.davis@globaltechsolutions.com", + "Contacted": true, + "Expected Close": "2023-10-28", + "Last Contact": "2023-09-20" + }, + { + "Name": "William Taylor", + "Company": "Innovative Systems", + "Status": "lead", + "Priority": "medium", + "Estimated Value": 48000, + "Account Owner": "Sophie Chen", + "Email": "william.taylor@innovativesystems.com", + "Contacted": false, + "Expected Close": "2023-12-25", + "Last Contact": null + }, + { + "Name": "Sophia Wang", + "Company": "Tech Solutions Inc", + "Status": "qualified", + "Priority": "high", + "Estimated Value": 68000, + "Account Owner": "Ryan Kim", + "Email": "sophia.wang@techsolutionsinc.com", + "Contacted": true, + "Expected Close": "2023-11-18", + "Last Contact": "2023-10-02" + }, + { + "Name": "Ethan Brown", + "Company": "Smart Tech Solutions", + "Status": "customer", + "Priority": "low", + "Estimated Value": 22000, + "Account Owner": "Emily Liu", + "Email": "ethan.brown@smarttechsolutions.com", + "Contacted": true, + "Expected Close": "2023-10-18", + "Last Contact": "2023-09-29" + }, + { + "Name": "Ava Johnson", + "Company": "Global Innovations Inc", + "Status": "lead", + "Priority": "high", + "Estimated Value": 72000, + "Account Owner": "Kevin Chen", + "Email": "ava.johnson@globalinnovationsinc.com", + "Contacted": false, + "Expected Close": "2024-01-15", + "Last Contact": null + }, + { + "Name": "Noah Martinez", + "Company": "Tech Systems", + "Status": "qualified", + "Priority": "medium", + "Estimated Value": 36000, + "Account Owner": "Michelle Wang", + "Email": "noah.martinez@techsystems.com", + "Contacted": true, + "Expected Close": "2023-11-22", + "Last Contact": "2023-10-09" + }, + { + "Name": "Isabella Kim", + "Company": "Innovative Tech Solutions", + "Status": "customer", + "Priority": "high", + "Estimated Value": 62000, + "Account Owner": "Andrew Lee", + "Email": "isabella.kim@innovativetechsolutions.com", + "Contacted": true, + "Expected Close": "2023-10-22", + "Last Contact": "2023-09-27" + }, + { + "Name": "Liam Wilson", + "Company": "Smart Innovations Inc", + "Status": "lead", + "Priority": "low", + "Estimated Value": 26000, + "Account Owner": "Jessica Chen", + "Email": "liam.wilson@smartinnovationsinc.com", + "Contacted": false, + "Expected Close": "2023-12-28", + "Last Contact": null + }, + { + "Name": "Mia Davis", + "Company": "Global Tech Systems", + "Status": "qualified", + "Priority": "high", + "Estimated Value": 78000, + "Account Owner": "Daniel Kim", + "Email": "mia.davis@globaltechsystems.com", + "Contacted": true, + "Expected Close": "2023-11-12", + "Last Contact": "2023-10-06" + }, + { + "Name": "Jacob Lee", + "Company": "Tech Innovators Inc", + "Status": "customer", + "Priority": "medium", + "Estimated Value": 44000, + "Account Owner": "Olivia Zhang", + "Email": "jacob.lee@techinnovatorsinc.com", + "Contacted": true, + "Expected Close": "2023-10-12", + "Last Contact": "2023-09-24" + }, + { + "Name": "Charlotte Brown", + "Company": "Smart Solutions Inc", + "Status": "lead", + "Priority": "high", + "Estimated Value": 66000, + "Account Owner": "William Wang", + "Email": "charlotte.brown@smartsolutionsinc.com", + "Contacted": false, + "Expected Close": "2024-01-08", + "Last Contact": null + }, + { + "Name": "Benjamin Chen", + "Company": "Global Systems Solutions", + "Status": "qualified", + "Priority": "low", + "Estimated Value": 30000, + "Account Owner": "Sophia Kim", + "Email": "benjamin.chen@globalsystemssolutions.com", + "Contacted": true, + "Expected Close": "2023-11-26", + "Last Contact": "2023-10-11" + }, + { + "Name": "Amelia Taylor", + "Company": "Innovative Tech Inc", + "Status": "customer", + "Priority": "high", + "Estimated Value": 56000, + "Account Owner": "Ethan Liu", + "Email": "amelia.taylor@innovativetechinc.com", + "Contacted": true, + "Expected Close": "2023-10-26", + "Last Contact": "2023-09-21" + }, + { + "Name": "Lucas Johnson", + "Company": "Tech Solutions Group", + "Status": "lead", + "Priority": "medium", + "Estimated Value": 46000, + "Account Owner": "Ava Chen", + "Email": "lucas.johnson@techsolutionsgroup.com", + "Contacted": false, + "Expected Close": "2023-12-22", + "Last Contact": null + }, + { + "Name": "Harper Wilson", + "Company": "Smart Innovations Group", + "Status": "qualified", + "Priority": "high", + "Estimated Value": 70000, + "Account Owner": "Noah Kim", + "Email": "harper.wilson@smartinnovationsgroup.com", + "Contacted": true, + "Expected Close": "2023-11-16", + "Last Contact": "2023-10-04" + }, + { + "Name": "Evelyn Martinez", + "Company": "Global Tech Innovations", + "Status": "customer", + "Priority": "low", + "Estimated Value": 24000, + "Account Owner": "Isabella Wang", + "Email": "evelyn.martinez@globaltechinnovations.com", + "Contacted": true, + "Expected Close": "2023-10-16", + "Last Contact": "2023-09-26" + }, + { + "Name": "Alexander Kim", + "Company": "Tech Systems Group", + "Status": "lead", + "Priority": "high", + "Estimated Value": 74000, + "Account Owner": "Liam Chen", + "Email": "alexander.kim@techsystemsgroup.com", + "Contacted": false, + "Expected Close": "2024-01-12", + "Last Contact": null + }, + { + "Name": "Abigail Davis", + "Company": "Innovative Solutions Group", + "Status": "qualified", + "Priority": "medium", + "Estimated Value": 34000, + "Account Owner": "Mia Liu", + "Email": "abigail.davis@innovativesolutionsgroup.com", + "Contacted": true, + "Expected Close": "2023-11-24", + "Last Contact": "2023-10-08" + }, + { + "Name": "Daniel Brown", + "Company": "Smart Tech Group", + "Status": "customer", + "Priority": "high", + "Estimated Value": 64000, + "Account Owner": "Jacob Zhang", + "Email": "daniel.brown@smarttechgroup.com", + "Contacted": true, + "Expected Close": "2023-10-24", + "Last Contact": "2023-09-23" + }, + { + "Name": "Sofia Wilson", + "Company": "Global Innovations Group", + "Status": "lead", + "Priority": "low", + "Estimated Value": 28000, + "Account Owner": "Charlotte Kim", + "Email": "sofia.wilson@globalinnovationsgroup.com", + "Contacted": false, + "Expected Close": "2023-12-26", + "Last Contact": null + }, + { + "Name": "Matthew Lee", + "Company": "Tech Innovators Group", + "Status": "qualified", + "Priority": "high", + "Estimated Value": 76000, + "Account Owner": "Benjamin Wang", + "Email": "matthew.lee@techinnovatorsgroup.com", + "Contacted": true, + "Expected Close": "2023-11-14", + "Last Contact": "2023-10-01" + }, + { + "Name": "Scarlett Chen", + "Company": "Smart Systems Solutions", + "Status": "customer", + "Priority": "medium", + "Estimated Value": 40000, + "Account Owner": "Amelia Liu", + "Email": "scarlett.chen@smartsystemssolutions.com", + "Contacted": true, + "Expected Close": "2023-10-14", + "Last Contact": "2023-09-28" + }, + { + "Name": "Joseph Taylor", + "Company": "Global Tech Solutions Group", + "Status": "lead", + "Priority": "high", + "Estimated Value": 68000, + "Account Owner": "Lucas Chen", + "Email": "joseph.taylor@globaltechsolutionsgroup.com", + "Contacted": false, + "Expected Close": "2024-01-06", + "Last Contact": null + }, + { + "Name": "Victoria Johnson", + "Company": "Innovative Systems Group", + "Status": "qualified", + "Priority": "low", + "Estimated Value": 32000, + "Account Owner": "Harper Kim", + "Email": "victoria.johnson@innovativesystemsgroup.com", + "Contacted": true, + "Expected Close": "2023-11-30", + "Last Contact": "2023-10-10" + }, + { + "Name": "Christopher Martinez", + "Company": "Tech Solutions Innovations", + "Status": "customer", + "Priority": "high", + "Estimated Value": 58000, + "Account Owner": "Evelyn Wang", + "Email": "christopher.martinez@techsolutionsinnovations.com", + "Contacted": true, + "Expected Close": "2023-10-30", + "Last Contact": "2023-09-22" + }, + { + "Name": "Madison Wilson", + "Company": "Smart Innovations Solutions", + "Status": "lead", + "Priority": "medium", + "Estimated Value": 48000, + "Account Owner": "Alexander Liu", + "Email": "madison.wilson@smartinnovationssolutions.com", + "Contacted": false, + "Expected Close": "2023-12-18", + "Last Contact": null + }, + { + "Name": "Andrew Kim", + "Company": "Global Systems Innovations", + "Status": "qualified", + "Priority": "high", + "Estimated Value": 72000, + "Account Owner": "Abigail Chen", + "Email": "andrew.kim@globalsystemsinnovations.com", + "Contacted": true, + "Expected Close": "2023-11-20", + "Last Contact": "2023-10-05" + }, + { + "Name": "Grace Davis", + "Company": "Tech Innovations Solutions", + "Status": "customer", + "Priority": "low", + "Estimated Value": 26000, + "Account Owner": "Daniel Wang", + "Email": "grace.davis@techinnovationssolutions.com", + "Contacted": true, + "Expected Close": "2023-10-20", + "Last Contact": "2023-09-27" + }, + { + "Name": "David Brown", + "Company": "Smart Tech Innovations", + "Status": "lead", + "Priority": "high", + "Estimated Value": 70000, + "Account Owner": "Sofia Kim", + "Email": "david.brown@smarttechinnovations.com", + "Contacted": false, + "Expected Close": "2024-01-02", + "Last Contact": null + }, + { + "Name": "Zoe Lee", + "Company": "Global Solutions Innovations", + "Status": "qualified", + "Priority": "medium", + "Estimated Value": 38000, + "Account Owner": "Matthew Liu", + "Email": "zoe.lee@globalsolutionsinnovations.com", + "Contacted": true, + "Expected Close": "2023-11-28", + "Last Contact": "2023-10-09" + }, + { + "Name": "Elijah Chen", + "Company": "Innovative Tech Group", + "Status": "customer", + "Priority": "high", + "Estimated Value": 60000, + "Account Owner": "Scarlett Wang", + "Email": "elijah.chen@innovativetechgroup.com", + "Contacted": true, + "Expected Close": "2023-10-28", + "Last Contact": "2023-09-25" + } + ] + } + } + } +} diff --git a/packages/template/src/templates/test.base.json b/packages/template/src/templates/test.base.json new file mode 100644 index 000000000..8ee491014 --- /dev/null +++ b/packages/template/src/templates/test.base.json @@ -0,0 +1,77 @@ +{ + "Test": { + "tables": { + "Table1": { + "schema": { + "Title": { + "id": "title", + "type": "string" + }, + "Ref2": { + "id": "ref2", + "type": "reference", + "option": { + "createSymmetricField": true, + "foreignTable": { + "tableName": "Table2" + } + } + }, + "Roll1": { + "id": "roll1", + "type": "rollup", + "option": { + "referenceFieldId": "ref2", + "rollupFieldId": "title", + "fn": "lookup" + } + } + }, + "records": [ + { + "Title": "1-1", + "Ref2": ["1", "2"] + }, + { + "Title": "1-2", + "Ref2": ["2"] + } + ] + }, + "Table2": { + "schema": { + "Title": { + "id": "title", + "type": "string" + }, + "Ref1": { + "id": "ref1", + "type": "reference", + "option": { + "symmetricFieldId": "ref2" + } + }, + "T1": { + "id": "t1", + "type": "rollup", + "option": { + "referenceFieldId": "ref1", + "rollupFieldId": "title", + "fn": "lookup" + } + } + }, + "records": [ + { + "id": "1", + "Title": "2-1" + }, + { + "id": "2", + "Title": "2-2" + } + ] + } + } + } +} diff --git a/turbo.json b/turbo.json index 8121cb3ea..1860d2ab9 100644 --- a/turbo.json +++ b/turbo.json @@ -1,7 +1,7 @@ { "$schema": "https://turbo.build/schema.json", "globalDependencies": ["**/.env.*local", ".env"], - "ui": "stream", + "ui": "tui", "globalEnv": ["LOG_LEVEL", "AXIOM_TOKEN", "AXIOM_DATASET", "UNDB_*", "GITHUB_*", "GOOGLE_*"], "tasks": { "build": {