Skip to content

Commit

Permalink
Merge pull request #2055 from undb-io/release/v1.0.0-84
Browse files Browse the repository at this point in the history
Release version v1.0.0-84
  • Loading branch information
nichenqin authored Sep 21, 2024
2 parents 89540ae + 6abc7b8 commit c7e88c0
Show file tree
Hide file tree
Showing 50 changed files with 759 additions and 93 deletions.
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"json.schemas": [
{
"fileMatch": ["packages/template/src/templates/*.base.json"],
"url": "http://localhost:3721/api/template/base/schema.json"
}
]
}
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

## v1.0.0-84


### 🏡 Chore

- Fix ts issue ([68c5291](https://github.com/undb-io/undb/commit/68c5291))

### ❤️ Contributors

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

## v1.0.0-83


Expand Down
1 change: 1 addition & 0 deletions apps/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@undb/realtime": "workspace:*",
"@undb/share": "workspace:*",
"@undb/space": "workspace:*",
"@undb/template": "workspace:*",
"@undb/trpc": "workspace:*",
"@undb/webhook": "workspace:*",
"arctic": "^1.9.2",
Expand Down
3 changes: 3 additions & 0 deletions apps/backend/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ import * as pkg from "../../../package.json"
import { Auth, OpenAPI, Realtime, SpaceModule, TableModule, Web } from "./modules"
import { FileService } from "./modules/file/file"
import { OpenTelemetryModule } from "./modules/opentelemetry/opentelemetry.module"
import { TemplateModule } from "./modules/template/template.module"
import { loggerPlugin } from "./plugins/logging"

const auth = container.resolve(Auth)
const web = container.resolve(Web)
const openapi = container.resolve(OpenAPI)
const opentelemetry = container.resolve(OpenTelemetryModule)
const template = container.resolve(TemplateModule)

export const app = new Elysia()
.onStart(async () => {
Expand Down Expand Up @@ -132,6 +134,7 @@ export const app = new Elysia()
.use(auth.route())
.use(web.route())
.use(openapi.route())
.use(template.route())
.use(trpc(route))
.guard(
{
Expand Down
12 changes: 12 additions & 0 deletions apps/backend/src/modules/template/template.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { singleton } from "@undb/di"
import { baseTemplateSchema } from "@undb/template"
import Elysia from "elysia"

@singleton()
export class TemplateModule {
route() {
return new Elysia().get("/api/template/base/schema.json", () => {
return baseTemplateSchema
})
}
}
25 changes: 25 additions & 0 deletions apps/frontend/src/lib/components/blocks/nav/nav-tools.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,24 @@
import SpaceDropdown from "../space/space-dropdown.svelte"
import type { ISpaceDTO } from "@undb/space"
import { preferences } from "$lib/store/persisted.store"
import { createMutation } from "@tanstack/svelte-query"
import { trpc } from "$lib/trpc/client"
import { toast } from "svelte-sonner"
import { goto, invalidateAll } from "$app/navigation"
export let space: ISpaceDTO | undefined | null
export let me: any
const createFromTemplateMutation = createMutation({
mutationFn: trpc.template.createFromTemplate.mutate,
onSuccess: async (data) => {
await invalidateAll()
toast.success("Base created successfully")
if (data.baseIds.length > 0) {
goto(`/bases/${data.baseIds[0]}`)
}
},
})
</script>

<div class="w-full space-y-1">
Expand Down Expand Up @@ -67,5 +82,15 @@
<PlusIcon class="mr-2 h-3 w-3" />
Create New Base
</Button>

<!-- <Button
class="w-full justify-start text-left"
on:click={() => $createFromTemplateMutation.mutate({ templateName: "test" })}
variant="link"
size="sm"
>
<PlusIcon class="mr-2 h-3 w-3" />
Create New Base
</Button> -->
{/if}
</div>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
query GetCreateFromTemplateData($shareId: ID!) {
query GetCreateFromShareData($shareId: ID!) {
space {
id
name
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { GetCreateFromTemplateDataStore } from "$houdini"
import { GetCreateFromShareDataStore } from "$houdini"
import type { LayoutLoad } from "./$types"

export const ssr = false
Expand All @@ -7,7 +7,7 @@ export const prerender = "auto"
export const load: LayoutLoad = async (event) => {
const { shareId } = event.params

const store = new GetCreateFromTemplateDataStore()
const store = new GetCreateFromShareDataStore()

await store.fetch({
event,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import * as Form from "$lib/components/ui/form"
import * as Alert from "$lib/components/ui/alert/index.js"
import { LoaderCircleIcon, SirenIcon, Store } from "lucide-svelte"
import { createFromTemplateCommand } from "@undb/commands"
import { createFromShareCommand } from "@undb/commands"
import { Checkbox } from "$lib/components/ui/checkbox"
import { trpc } from "$lib/trpc/client"
import { page } from "$app/stores"
Expand Down Expand Up @@ -39,8 +39,8 @@
})
}
const createFromTemplateMutation = createMutation({
mutationFn: trpc.base.createFromTemplate.mutate,
const createFromShareMutation = createMutation({
mutationFn: trpc.base.createFromShare.mutate,
onError(error, variables, context) {
toast.error(error.message)
},
Expand All @@ -60,12 +60,12 @@
name: template?.name,
includeData: true,
},
zodClient(createFromTemplateCommand),
zodClient(createFromShareCommand),
),
{
SPA: true,
dataType: "json",
validators: zodClient(createFromTemplateCommand),
validators: zodClient(createFromShareCommand),
resetForm: false,
invalidateAll: false,
onSubmit(input) {
Expand All @@ -77,7 +77,7 @@
return
}
await $createFromTemplateMutation.mutateAsync(event.form.data)
await $createFromShareMutation.mutateAsync(event.form.data)
},
},
)
Expand Down Expand Up @@ -176,8 +176,8 @@
System fields will be updated to the current user and timestamp.
</Alert.Description>
</Alert.Root>
<Form.Button type="submit" class="w-full" disabled={$createFromTemplateMutation.isPending}>
{#if $createFromTemplateMutation.isPending}
<Form.Button type="submit" class="w-full" disabled={$createFromShareMutation.isPending}>
{#if $createFromShareMutation.isPending}
<LoaderCircleIcon class="mr-2 h-5 w-5 animate-spin" />
{/if}
Create
Expand Down
Binary file modified bun.lockb
Binary file not shown.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "undb",
"version": "1.0.0-83",
"version": "1.0.0-84",
"private": true,
"scripts": {
"build": "NODE_ENV=production bun --bun turbo build",
Expand Down
1 change: 1 addition & 0 deletions packages/base/src/dto/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export * from "./base.dto"
export * from "./create-base.dto"
export * from "./delete-base.dto"
export * from "./duplicate-base.dto"
export * from "./unique-base.dto"
export * from "./update-base.dto"
13 changes: 13 additions & 0 deletions packages/base/src/dto/unique-base.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { spaceIdSchema } from "@undb/space"
import { z } from "@undb/zod"
import { baseIdSchema, baseNameSchema } from "../value-objects"

export const uniqueBaseDTO = z
.object({
baseId: baseIdSchema,
baseName: baseNameSchema,
spaceId: spaceIdSchema,
})
.partial()

export type IUniqueBaseDTO = z.infer<typeof uniqueBaseDTO>
20 changes: 20 additions & 0 deletions packages/base/src/specifications/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,23 @@ export * from "./base-id.specification.js"
export * from "./base-name.specification.js"
export * from "./base-q.specification.js"
export * from "./base-space-id.specification.js"

import { CompositeSpecification, Err, Ok, Result } from "@undb/domain"
import type { Base } from "../base.js"
import type { IUniqueBaseDTO } from "../dto/unique-base.dto.js"
import type { IBaseSpecVisitor } from "../interface.js"
import { BaseId } from "../value-objects/base-id.vo.js"
import { WithBaseId } from "./base-id.specification.js"
import { WithBaseName } from "./base-name.specification.js"

type BaseComositeSpecification = CompositeSpecification<Base, IBaseSpecVisitor>

export const withUniqueBase = (dto: IUniqueBaseDTO): Result<BaseComositeSpecification, string> => {
if (dto.baseId) {
return Ok(new WithBaseId(new BaseId(dto.baseId)))
}
if (dto.baseName && dto.spaceId) {
return Ok(WithBaseName.fromString(dto.baseName))
}
return Err("Invalid base specification")
}
2 changes: 1 addition & 1 deletion packages/base/src/value-objects/base-name.vo.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ValueObject } from "@undb/domain"
import * as z from "@undb/zod"

export const baseNameSchema = z.string().min(1)
export const baseNameSchema = z.string().min(1, { message: "Base name must be at least 1 character" })

export class BaseName extends ValueObject<z.infer<typeof baseNameSchema>> {
static from(name: string): BaseName {
Expand Down
1 change: 1 addition & 0 deletions packages/command-handlers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@undb/cqrs": "workspace:*",
"@undb/di": "workspace:*",
"@undb/logger": "workspace:*",
"@undb/template": "workspace:*",
"@undb/openapi": "workspace:*",
"@undb/user": "workspace:*",
"ts-pattern": "^5.3.1"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { checkPermission, injectSpaceMemberService, type ISpaceMemberService } from "@undb/authz"
import { BaseId, injectBaseRepository, WithBaseId, WithBaseSpaceId, type IBaseRepository } from "@undb/base"
import { CreateFromShareCommand } from "@undb/commands"
import { getCurrentUserId, mustGetCurrentSpaceId } from "@undb/context/server"
import { commandHandler } from "@undb/cqrs"
import { singleton } from "@undb/di"
import { type ICommandHandler } from "@undb/domain"
import { createLogger } from "@undb/logger"
import { injectShareRepository, WithShareId, type IShareRepository } from "@undb/share"
import { injectTableService, type ITableService } from "@undb/table"

@commandHandler(CreateFromShareCommand)
@singleton()
export class CreateFromShareCommandHandler implements ICommandHandler<CreateFromShareCommand, any> {
private readonly logger = createLogger(CreateFromShareCommandHandler.name)

constructor(
@injectBaseRepository()
private readonly baseRepository: IBaseRepository,
@injectTableService()
private readonly tableService: ITableService,
@injectSpaceMemberService()
private readonly spaceMemberService: ISpaceMemberService,
@injectShareRepository()
private readonly shareRepository: IShareRepository,
) {}

async execute(command: CreateFromShareCommand): Promise<any> {
this.logger.debug("CreateFromShareCommandHandler execute command", command)
const share = (await this.shareRepository.findOne(WithShareId.fromString(command.shareId))).expect(
"Share not found",
)

if (share.target.type !== "base") {
throw new Error("Share target is not base")
}

const baseId = share.target.id
const spaceId = share.spaceId

const userId = getCurrentUserId()
const targetSpaceId = command.targetSpaceId ?? mustGetCurrentSpaceId()

const member = (await this.spaceMemberService.getSpaceMember(userId, targetSpaceId)).expect("Member not found")
checkPermission(member.props.role, ["base:create"])

const spec = new WithBaseId(new BaseId(baseId)).and(new WithBaseSpaceId(spaceId))
const base = (await this.baseRepository.findOne(spec)).expect("Base not found")

const duplicatedBase = await this.tableService.duplicateBase(base, spaceId, targetSpaceId, {
id: baseId,
name: command.name,
includeData: command.includeData,
})

return duplicatedBase.id.value
}
}
Original file line number Diff line number Diff line change
@@ -1,58 +1,31 @@
import { checkPermission, injectSpaceMemberService, type ISpaceMemberService } from "@undb/authz"
import { BaseId, injectBaseRepository, WithBaseId, WithBaseSpaceId, type IBaseRepository } from "@undb/base"
import { CreateFromTemplateCommand } from "@undb/commands"
import { getCurrentUserId, mustGetCurrentSpaceId } from "@undb/context/server"
import { CreateFromTemplateCommand, type ICreateFromTemplateCommandOutput } from "@undb/commands"
import { mustGetCurrentSpaceId } from "@undb/context/server"
import { commandHandler } from "@undb/cqrs"
import { singleton } from "@undb/di"
import { type ICommandHandler } from "@undb/domain"
import { createLogger } from "@undb/logger"
import { injectShareRepository, WithShareId, type IShareRepository } from "@undb/share"
import { injectTableService, type ITableService } from "@undb/table"
import { injectTemplateService, type ITemplateService, templates } from "@undb/template"

@commandHandler(CreateFromTemplateCommand)
@singleton()
export class CreateFromTemplateCommandHandler implements ICommandHandler<CreateFromTemplateCommand, any> {
export class CreateFromTemplateCommandHandler
implements ICommandHandler<CreateFromTemplateCommand, ICreateFromTemplateCommandOutput>
{
private readonly logger = createLogger(CreateFromTemplateCommandHandler.name)

constructor(
@injectBaseRepository()
private readonly baseRepository: IBaseRepository,
@injectTableService()
private readonly tableService: ITableService,
@injectSpaceMemberService()
private readonly spaceMemberService: ISpaceMemberService,
@injectShareRepository()
private readonly shareRepository: IShareRepository,
@injectTemplateService()
private readonly templateService: ITemplateService,
) {}

async execute(command: CreateFromTemplateCommand): Promise<any> {
this.logger.debug("CreateFromTemplateCommandHandler execute command", command)
const share = (await this.shareRepository.findOne(WithShareId.fromString(command.shareId))).expect(
"Share not found",
)
async execute(command: CreateFromTemplateCommand): Promise<ICreateFromTemplateCommandOutput> {
this.logger.info(`create from template command received: ${command.templateName}`)

if (share.target.type !== "base") {
throw new Error("Share target is not base")
}
const template = templates["test"]

const baseId = share.target.id
const spaceId = share.spaceId
const spaceId = mustGetCurrentSpaceId()
const result = await this.templateService.createBase(template, spaceId)

const userId = getCurrentUserId()
const targetSpaceId = command.targetSpaceId ?? mustGetCurrentSpaceId()

const member = (await this.spaceMemberService.getSpaceMember(userId, targetSpaceId)).expect("Member not found")
checkPermission(member.props.role, ["base:create"])

const spec = new WithBaseId(new BaseId(baseId)).and(new WithBaseSpaceId(spaceId))
const base = (await this.baseRepository.findOne(spec)).expect("Base not found")

const duplicatedBase = await this.tableService.duplicateBase(base, spaceId, targetSpaceId, {
id: baseId,
name: command.name,
includeData: command.includeData,
})

return duplicatedBase.id.value
return { baseIds: result.map(({ base }) => base.id.value) }
}
}
Loading

0 comments on commit c7e88c0

Please sign in to comment.