Skip to content

Commit

Permalink
fix: publishing -d
Browse files Browse the repository at this point in the history
  • Loading branch information
arpowers committed Sep 22, 2024
1 parent ac3d783 commit 0ab2ba0
Show file tree
Hide file tree
Showing 9 changed files with 315 additions and 51 deletions.
73 changes: 56 additions & 17 deletions @fiction/site/endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ export class ManagePage extends Query<SitesQuerySettings> {
const cardId = card.cardId

const currentDraft = await db
.select<TableCardConfig[]>('draft', 'draft_history')
.select<TableCardConfig[]>('draft')
.from(t.pages)
.where({ siteId, orgId, card_id: cardId })
.first()
Expand Down Expand Up @@ -480,20 +480,43 @@ export class ManageSite extends SitesQuery {
}

private async updateSite(params: ManageSiteParams & { _action: 'update' }, meta: EndpointMeta): Promise<EndpointResponse<TableSiteConfig>> {
const { fields, where, userId, orgId } = params
const { fields, where, userId, orgId, scope = 'publish' } = params
if (!userId || !orgId)
throw abort('orgId required')

if (scope === 'draft') {
return this.saveDraft({ ...params, _action: 'saveDraft' }, meta)
}

const selector = await this.getSiteSelector(where)
const prepped = this.settings.fictionDb.prep({ type: 'update', fields, table: t.sites, meta })

const [updatedSite] = await this.settings.fictionDb.client().update({ orgId, userId, ...prepped }).where({ orgId, ...selector }).into(t.sites).returning<TableSiteConfig[]>('*')
this.log.info('UPDATING SITE', { data: { selector, fields: fields.pages?.find(_ => _.slug === '_home') } })

const db = this.settings.fictionDb.client()

let updatedSite: TableSiteConfig | undefined

await db.transaction(async (trx) => {
[updatedSite] = await trx(t.sites)
.update({ orgId, userId, ...prepped })
.where({ orgId, ...selector })
.returning('*')

if (!updatedSite)
throw abort('site not found')

// If updating in publish mode, clear all drafts
if (scope === 'publish') {
await this.clearSiteDrafts(trx, { siteId: updatedSite.siteId }, orgId)
}
})

if (!updatedSite)
throw abort('site not found')
throw abort('updated site not found')

if (fields.pages && fields.pages.length) {
await this.updateSitePages({ siteId: updatedSite.siteId, fields: fields.pages, userId, orgId, scope: 'publish' }, meta)
await this.updateSitePages({ siteId: updatedSite.siteId, fields: fields.pages, userId, orgId, scope }, meta)
}

return { status: 'success', data: updatedSite, message: 'site saved' }
Expand All @@ -510,7 +533,7 @@ export class ManageSite extends SitesQuery {
const now = new Date()
fields.updatedAt = now.toISOString()

const currentDrafts = await db.select<TableSiteConfig>('draft', 'draft_history')
const currentDrafts = await db.select<TableSiteConfig>('draft')
.from(t.sites)
.where(where)
.first()
Expand Down Expand Up @@ -543,27 +566,43 @@ export class ManageSite extends SitesQuery {
return { status: 'success', data: r.data }
}

async clearSiteDrafts(db: Knex, selector: WhereSite, orgId: string): Promise<TableSiteConfig | null> {
return db.transaction(async (trx) => {
// Clear site draft
const [updatedSite] = await trx(t.sites)
.where({ orgId, ...selector })
.update({ draft: '{}' })
.returning('*')

if (!updatedSite) {
return null
}

// Clear page drafts
await trx(t.pages)
.where({ siteId: updatedSite.siteId })
.update({ draft: '{}' })

return updatedSite
})
}

private async revertDraft(params: ManageSiteParams & { _action: 'revertDraft' }, meta: EndpointMeta): Promise<EndpointResponse<TableSiteConfig>> {
const { where, orgId } = params
const db = this.settings.fictionDb.client()

if (!orgId)
throw abort('orgId required')

const selector = await this.getSiteSelector(where)

// Revert site draft
const [updatedSite] = await db(t.sites)
.where({ orgId, ...selector })
.update({ draft: '{}' })
.returning('*')
const db = this.settings.fictionDb.client()

const updatedSite = await this.clearSiteDrafts(db, selector, orgId)

if (!updatedSite) {
throw abort('Site not found')
}

// Revert page drafts
await db(t.pages)
.where({ siteId: updatedSite.siteId })
.update({ draft: '{}' })

// Fetch the updated site with reverted drafts
const result = await this.retrieveSite({
_action: 'retrieve',
Expand Down
2 changes: 1 addition & 1 deletion @fiction/site/plugin-builder/SiteEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ async function save() {
// make sure any blur events are triggered
resetUi({ scope: 'all', cause: 'saveSite', trigger: 'manualReset' })
await site.value.save({ minTime: 500 })
await site.value.save({ minTime: 500, scope: 'publish' })
sending.value = ''
}
Expand Down
4 changes: 0 additions & 4 deletions @fiction/site/tables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@ export const siteCols = [
new Col({ key: 'editor', sec: 'setting', sch: () => z.record(z.unknown()) as z.Schema<Partial<EditorState>>, make: ({ s, col }) => s.jsonb(col.k).defaultTo({}), prepare: ({ value }) => JSON.stringify(value) }),
new Col({ key: 'sections', sec: 'setting', sch: () => z.record(z.unknown()) as z.Schema<Record<string, CardConfigPortable>>, make: ({ s, col }) => s.jsonb(col.k).defaultTo({}), prepare: ({ value }) => JSON.stringify(value) }),
new Col({ key: 'draft', sec: 'setting', sch: () => z.record(z.unknown()), make: ({ s, col }) => s.jsonb(col.k).defaultTo({}), prepare: ({ value }) => JSON.stringify(value) }),
new Col({ key: 'draftHistory', sec: 'setting', sch: () => z.array(z.record(z.unknown())), make: ({ s, col }) => s.jsonb(col.k).defaultTo([]), prepare: ({ value }) => JSON.stringify(value) }),
new Col({ key: 'archiveAt', sec: 'setting', sch: () => z.string(), make: ({ s, col }) => s.timestamp(col.k) }),
] as const

export const pageCols = [
Expand All @@ -81,8 +79,6 @@ export const pageCols = [
new Col({ key: 'editor', sec: 'setting', sch: () => z.record(z.unknown()), make: ({ s, col }) => s.jsonb(col.k).defaultTo({}), prepare: ({ value }) => JSON.stringify(value) }),
new Col({ key: 'generation', sec: 'setting', sch: () => z.record(z.unknown()) as z.Schema<CardGenerationConfig>, make: ({ s, col }) => s.jsonb(col.k).defaultTo({}), prepare: ({ value }) => JSON.stringify(value) }),
new Col({ key: 'draft', sec: 'setting', sch: () => z.record(z.unknown()), make: ({ s, col }) => s.jsonb(col.k).defaultTo({}) }),
new Col({ key: 'draftHistory', sec: 'setting', sch: () => z.array(z.record(z.unknown())), make: ({ s, col }) => s.jsonb(col.k).defaultTo([]) }),
new Col({ key: 'archiveAt', sec: 'setting', sch: () => z.string(), make: ({ s, col }) => s.timestamp(col.k) }),
] as const

export const domainCols = [
Expand Down
144 changes: 144 additions & 0 deletions @fiction/site/test/manageSite.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,150 @@ describe('manageSite query', () => {
})
})

describe('draft clearing on publish', () => {
let siteId: string
let cardId: string

beforeEach(async () => {
const fields = createSiteFields('Draft Clearing Test Site')
const response = await testUtils.fictionSites.queries.ManageSite.run(
{ _action: 'create', fields, orgId, userId, caller: 'test' },
{ server: true },
)
siteId = response.data?.siteId as string
cardId = objectId({ prefix: 'card' })

// Add a published page to the site
await testUtils.fictionSites.queries.ManagePage.serve(
{
_action: 'upsert',
siteId,
fields: [{ cardId, templateId: 'wrap', title: 'Published Page', slug: 'published-page' }],
orgId,
userId,
caller: 'test',
scope: 'publish',
},
{ server: true },
)
})

it('should clear site and page drafts when publishing', async () => {
// Create drafts for site and page
const siteDraft = { title: 'Draft Site Title' }
const pageDraft = { cardId, templateId: 'wrap', title: 'Draft Page Title', slug: 'published-page' }

await testUtils.fictionSites.queries.ManageSite.serve(
{ _action: 'saveDraft', where: { siteId }, fields: siteDraft, orgId, userId, caller: 'test' },
{ server: true },
)

await testUtils.fictionSites.queries.ManagePage.serve(
{
_action: 'saveDraft',
siteId,
fields: [pageDraft],
orgId,
userId,
caller: 'test',
scope: 'draft',
},
{ server: true },
)

// Publish the site
const publishResponse = await testUtils.fictionSites.queries.ManageSite.run(
{ _action: 'update', where: { siteId }, fields: { title: 'Published Site Title' }, orgId, userId, caller: 'test', scope: 'publish' },
{ server: true },
)

expect(publishResponse.status).toBe('success')
expect(publishResponse.data?.title).toBe('Published Site Title')

// Verify site draft is cleared
const siteResponse = await testUtils.fictionSites.queries.ManageSite.run(
{ _action: 'retrieve', where: { siteId }, orgId, userId, caller: 'test', scope: 'draft' },
{ server: true },
)

expect(siteResponse.data?.title).toBe('Published Site Title')
expect(siteResponse.data?.draft).toBeUndefined()

// Verify page draft is cleared
const pageResponse = await testUtils.fictionSites.queries.ManagePage.serve(
{
_action: 'retrieve',
where: [{ cardId }],
siteId,
orgId,
caller: 'test',
scope: 'draft',
},
{ server: true },
)

expect(pageResponse.data?.[0]?.title).toBe('Published Page')
expect(pageResponse.data?.[0]?.draft).toBeUndefined()
})

it('should not clear drafts when updating in draft mode', async () => {
// Create drafts for site and page
const siteDraft = { title: 'Draft Site Title' }
const pageDraft = { cardId, templateId: 'wrap', title: 'Draft Page Title', slug: 'published-page' }

await testUtils.fictionSites.queries.ManageSite.serve(
{ _action: 'saveDraft', where: { siteId }, fields: siteDraft, orgId, userId, caller: 'test' },
{ server: true },
)

await testUtils.fictionSites.queries.ManagePage.serve(
{
_action: 'saveDraft',
siteId,
fields: [pageDraft],
orgId,
userId,
caller: 'test',
scope: 'draft',
},
{ server: true },
)

// Update the site in draft mode
const updateResponse = await testUtils.fictionSites.queries.ManageSite.run(
{ _action: 'update', where: { siteId }, fields: { title: 'Updated Draft Title' }, orgId, userId, caller: 'test', scope: 'draft' },
{ server: true },
)

expect(updateResponse.status).toBe('success')

// Verify site draft is not cleared
const siteResponse = await testUtils.fictionSites.queries.ManageSite.run(
{ _action: 'retrieve', where: { siteId }, orgId, userId, caller: 'test', scope: 'draft' },
{ server: true },
)

expect(siteResponse.data?.title).toBe('Updated Draft Title')
expect(siteResponse.data?.draft).toBeFalsy()

// Verify page draft is not cleared
const pageResponse = await testUtils.fictionSites.queries.ManagePage.serve(
{
_action: 'retrieve',
where: [{ cardId }],
siteId,
orgId,
caller: 'test',
scope: 'draft',
},
{ server: true },
)

expect(pageResponse.data?.[0]?.title).toBe('Draft Page Title')
expect(pageResponse.data?.[0]?.draft).toBeFalsy()
})
})

describe('edge cases and error handling', () => {
it('should have correct error message for invalid theme', async () => {
const fields = { ...createSiteFields('Invalid Theme Site'), themeId: 'non-existent-theme' }
Expand Down
2 changes: 1 addition & 1 deletion @fiction/site/utils/site.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export async function saveSite(args: { site: Site, scope?: 'draft' | 'publish',
caller: 'saveSite',
}, { minTime })

await updateSite({ site, newConfig: r.data || {}, caller: 'saveSite' })
await updateSite({ site, newConfig: r.data || {}, caller: 'saveSite', noSave: true })

site.editor.value.isDirty = false
site.clearAutosave()
Expand Down
6 changes: 3 additions & 3 deletions @fiction/themes/fiction/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,21 @@ const socials: NavItem[] = [
href: 'https://www.linkedin.com/company/fictionco',
target: '_blank',
name: 'LinkedIn',
icon: `linkedin`,
media: { iconId: `linkedin` },
},
{
key: 'github',
href: 'https://github.com/fictionco',
target: '_blank',
name: 'Github',
icon: `github`,
media: { iconId: `github` },
},
{
key: 'x',
href: 'https://www.x.com/fictionplatform',
target: '_blank',
name: 'X',
icon: 'x',
media: { iconId: `x` },
},
]

Expand Down
Loading

0 comments on commit 0ab2ba0

Please sign in to comment.