mirror of
https://github.com/docmost/docmost.git
synced 2026-08-29 01:37:05 +08:00
feat(base): seed inline-embed bases with two extra text columns and one row
A freshly-created inline-embed used to render with only the primary
"Title" column and zero rows — visually it looks more like a broken
widget than a database, so users always had to do at least three
manual setup steps before the embed conveyed its purpose.
BaseService.create now accepts an optional `defaults` arg for
`extraTextProperties` and `defaultRows`; both extras are inserted in
the same transaction as the page/property/view so a half-built base
can never slip out. The inline-embed controller passes
{ extraTextProperties: 2, defaultRows: 1 } so the embed lands as
"Title + Text 1 + Text 2", with one empty row ready to type into.
Standalone base creation goes through the same code path with no
defaults, so its existing single-Title-column shape is unchanged.
This commit is contained in:
@@ -177,10 +177,20 @@ export class BaseController {
|
|||||||
|
|
||||||
await this.pageAccessService.validateCanEdit(parent, user);
|
await this.pageAccessService.validateCanEdit(parent, user);
|
||||||
|
|
||||||
return this.baseService.create(user.id, parent.workspaceId, {
|
// Inline embeds land mid-document and need to be visually meaningful
|
||||||
spaceId: parent.spaceId,
|
// on first paint — a single "Title" column with no rows looks broken.
|
||||||
parentPageId: dto.parentPageId,
|
// Seed two extra text columns and one empty row so the freshly-
|
||||||
name: 'Untitled',
|
// created base looks like a typical database (Title + Text 1 + Text 2,
|
||||||
});
|
// one ready-to-fill row).
|
||||||
|
return this.baseService.create(
|
||||||
|
user.id,
|
||||||
|
parent.workspaceId,
|
||||||
|
{
|
||||||
|
spaceId: parent.spaceId,
|
||||||
|
parentPageId: dto.parentPageId,
|
||||||
|
name: 'Untitled',
|
||||||
|
},
|
||||||
|
{ extraTextProperties: 2, defaultRows: 1 },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { KyselyDB } from '@docmost/db/types/kysely.types';
|
|||||||
import { executeTx } from '@docmost/db/utils';
|
import { executeTx } from '@docmost/db/utils';
|
||||||
import { BaseRepo } from '@docmost/db/repos/base/base.repo';
|
import { BaseRepo } from '@docmost/db/repos/base/base.repo';
|
||||||
import { BasePropertyRepo } from '@docmost/db/repos/base/base-property.repo';
|
import { BasePropertyRepo } from '@docmost/db/repos/base/base-property.repo';
|
||||||
|
import { BaseRowRepo } from '@docmost/db/repos/base/base-row.repo';
|
||||||
import { BaseViewRepo } from '@docmost/db/repos/base/base-view.repo';
|
import { BaseViewRepo } from '@docmost/db/repos/base/base-view.repo';
|
||||||
import { PageService } from '../../page/services/page.service';
|
import { PageService } from '../../page/services/page.service';
|
||||||
import { PageRepo } from '@docmost/db/repos/page/page.repo';
|
import { PageRepo } from '@docmost/db/repos/page/page.repo';
|
||||||
@@ -22,12 +23,18 @@ export class BaseService {
|
|||||||
@InjectKysely() private readonly db: KyselyDB,
|
@InjectKysely() private readonly db: KyselyDB,
|
||||||
private readonly baseRepo: BaseRepo,
|
private readonly baseRepo: BaseRepo,
|
||||||
private readonly basePropertyRepo: BasePropertyRepo,
|
private readonly basePropertyRepo: BasePropertyRepo,
|
||||||
|
private readonly baseRowRepo: BaseRowRepo,
|
||||||
private readonly baseViewRepo: BaseViewRepo,
|
private readonly baseViewRepo: BaseViewRepo,
|
||||||
private readonly pageService: PageService,
|
private readonly pageService: PageService,
|
||||||
private readonly pageRepo: PageRepo,
|
private readonly pageRepo: PageRepo,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async create(userId: string, workspaceId: string, dto: CreateBaseDto) {
|
async create(
|
||||||
|
userId: string,
|
||||||
|
workspaceId: string,
|
||||||
|
dto: CreateBaseDto,
|
||||||
|
defaults: { extraTextProperties?: number; defaultRows?: number } = {},
|
||||||
|
) {
|
||||||
return executeTx(this.db, async (trx) => {
|
return executeTx(this.db, async (trx) => {
|
||||||
const page = await this.pageService.create(
|
const page = await this.pageService.create(
|
||||||
userId,
|
userId,
|
||||||
@@ -56,6 +63,28 @@ export class BaseService {
|
|||||||
trx,
|
trx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Extra default text properties (used by the inline-embed flow so
|
||||||
|
// a freshly-inserted database renders with a few visible columns
|
||||||
|
// instead of a single "Title" lane). Positions are chained off
|
||||||
|
// each other so they keep the requested order.
|
||||||
|
let lastPropertyPosition = firstPosition;
|
||||||
|
const extraTextProperties = defaults.extraTextProperties ?? 0;
|
||||||
|
for (let i = 0; i < extraTextProperties; i++) {
|
||||||
|
const next = generateJitteredKeyBetween(lastPropertyPosition, null);
|
||||||
|
await this.basePropertyRepo.insertProperty(
|
||||||
|
{
|
||||||
|
pageId: page.id,
|
||||||
|
name: `Text ${i + 1}`,
|
||||||
|
type: BasePropertyType.TEXT,
|
||||||
|
position: next,
|
||||||
|
isPrimary: false,
|
||||||
|
workspaceId,
|
||||||
|
},
|
||||||
|
trx,
|
||||||
|
);
|
||||||
|
lastPropertyPosition = next;
|
||||||
|
}
|
||||||
|
|
||||||
await this.baseViewRepo.insertView(
|
await this.baseViewRepo.insertView(
|
||||||
{
|
{
|
||||||
pageId: page.id,
|
pageId: page.id,
|
||||||
@@ -69,6 +98,26 @@ export class BaseService {
|
|||||||
{ trx },
|
{ trx },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Default empty rows. Same flow rationale as extra properties —
|
||||||
|
// the inline-embed flow asks for one so the freshly-inserted
|
||||||
|
// database is interactive on first paint.
|
||||||
|
let lastRowPosition: string | null = null;
|
||||||
|
const defaultRows = defaults.defaultRows ?? 0;
|
||||||
|
for (let i = 0; i < defaultRows; i++) {
|
||||||
|
const next = generateJitteredKeyBetween(lastRowPosition, null);
|
||||||
|
await this.baseRowRepo.insertRow(
|
||||||
|
{
|
||||||
|
pageId: page.id,
|
||||||
|
workspaceId,
|
||||||
|
position: next,
|
||||||
|
cells: {},
|
||||||
|
creatorId: userId,
|
||||||
|
},
|
||||||
|
{ trx },
|
||||||
|
);
|
||||||
|
lastRowPosition = next;
|
||||||
|
}
|
||||||
|
|
||||||
return this.baseRepo.findById(page.id, {
|
return this.baseRepo.findById(page.id, {
|
||||||
includeProperties: true,
|
includeProperties: true,
|
||||||
includeViews: true,
|
includeViews: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user