mirror of
https://github.com/docmost/docmost.git
synced 2026-06-11 02:36:56 +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);
|
||||
|
||||
return this.baseService.create(user.id, parent.workspaceId, {
|
||||
spaceId: parent.spaceId,
|
||||
parentPageId: dto.parentPageId,
|
||||
name: 'Untitled',
|
||||
});
|
||||
// Inline embeds land mid-document and need to be visually meaningful
|
||||
// on first paint — a single "Title" column with no rows looks broken.
|
||||
// Seed two extra text columns and one empty row so the freshly-
|
||||
// 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 { BaseRepo } from '@docmost/db/repos/base/base.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 { PageService } from '../../page/services/page.service';
|
||||
import { PageRepo } from '@docmost/db/repos/page/page.repo';
|
||||
@@ -22,12 +23,18 @@ export class BaseService {
|
||||
@InjectKysely() private readonly db: KyselyDB,
|
||||
private readonly baseRepo: BaseRepo,
|
||||
private readonly basePropertyRepo: BasePropertyRepo,
|
||||
private readonly baseRowRepo: BaseRowRepo,
|
||||
private readonly baseViewRepo: BaseViewRepo,
|
||||
private readonly pageService: PageService,
|
||||
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) => {
|
||||
const page = await this.pageService.create(
|
||||
userId,
|
||||
@@ -56,6 +63,28 @@ export class BaseService {
|
||||
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(
|
||||
{
|
||||
pageId: page.id,
|
||||
@@ -69,6 +98,26 @@ export class BaseService {
|
||||
{ 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, {
|
||||
includeProperties: true,
|
||||
includeViews: true,
|
||||
|
||||
Reference in New Issue
Block a user