feat: recent activity card on Home and Retention card on Settings
This commit is contained in:
1 parent
35db442cd3
commit
43469ef08d
33 files changed
+2748
-204
No files matched your search
+107
-6
@@ -165,6 +165,18 @@ const verifiedSession: ApiMock = {
|
||||
}
|
||||
|
||||
const updateRunningVersion = 'v2.2.0-beta'
|
||||
const newCardAbsentReason = 'new card absent from board frame (dashed placeholder)'
|
||||
const homeActivityMock: ApiMock = {
|
||||
status: 200,
|
||||
body: { items: [], total: 0, page: 1, size: 5 },
|
||||
}
|
||||
const workspaceSettingsBody = {
|
||||
version: updateRunningVersion,
|
||||
activity_retention_days: 90,
|
||||
activity_last_cleanup_at: '2026-10-06T03:00:00Z',
|
||||
activity_last_cleanup_removed: 142,
|
||||
activity_next_cleanup_at: '2026-10-07T03:00:00Z',
|
||||
}
|
||||
const updateLatestTag = 'v2.3.0'
|
||||
const updateReleaseUrl = 'https://git.floriansylvain.fr/fsylvain/RenewCMS/releases/tag/v2.3.0'
|
||||
const updateReleasedAt = '2026-09-24T08:00:00Z'
|
||||
@@ -291,7 +303,7 @@ function updateApi(
|
||||
): Record<string, ApiMock> {
|
||||
return {
|
||||
'GET /v1/auth/me': role === 'owner' ? verifiedSession : adminSession,
|
||||
'GET /v1/settings/': { status: 200, body: { version: updateRunningVersion } },
|
||||
'GET /v1/settings/': { status: 200, body: workspaceSettingsBody },
|
||||
'GET /v1/system/update': { status: 200, body: status },
|
||||
'POST /v1/system/update/check': check,
|
||||
}
|
||||
@@ -545,6 +557,7 @@ const newArticleBody = 'Small rooms show every grout line, so we start with the
|
||||
function newArticleHomeApi(overrides: Record<string, ApiMock> = {}): Record<string, ApiMock> {
|
||||
return {
|
||||
'GET /v1/auth/me': verifiedSession,
|
||||
'GET /v1/activity': homeActivityMock,
|
||||
'GET /v1/article/': { status: 200, body: sixArticlesFixture },
|
||||
...overrides,
|
||||
}
|
||||
@@ -2378,7 +2391,7 @@ function cleanupApi(
|
||||
): Record<string, ApiMock> {
|
||||
return {
|
||||
'GET /v1/auth/me': sessionWithRole(role),
|
||||
'GET /v1/settings/': { status: 200, body: { version: updateRunningVersion } },
|
||||
'GET /v1/settings/': { status: 200, body: workspaceSettingsBody },
|
||||
'GET /v1/system/update': { status: 200, hang: true },
|
||||
[purgeSettingsPath]: settings,
|
||||
...overrides,
|
||||
@@ -2392,8 +2405,9 @@ function settingsBody(body: unknown): ApiMock {
|
||||
function cleanupState(
|
||||
api: Record<string, ApiMock>,
|
||||
steps?: (page: Page) => Promise<void>,
|
||||
exception?: DiffException,
|
||||
): VisualState {
|
||||
return { path: '/settings', api, steps }
|
||||
return { path: '/settings', api, steps, exception }
|
||||
}
|
||||
|
||||
async function openCleanupDialog(page: Page) {
|
||||
@@ -2486,7 +2500,11 @@ const cleanupStates: Record<string, VisualState> = {
|
||||
await page.getByText('Enter a whole number of days between 1 and 365.').waitFor()
|
||||
}),
|
||||
'Read-only (non-admin)': cleanupState(cleanupApi(settingsBody(purgeOnBody), {}, 'member')),
|
||||
'Loading skeleton': cleanupState(cleanupApi({ status: 200, hang: true })),
|
||||
'Loading skeleton': cleanupState(cleanupApi({ status: 200, hang: true }), undefined, {
|
||||
maxPercent: 17.5,
|
||||
reason: newCardAbsentReason,
|
||||
approvedBy: 'fallen',
|
||||
}),
|
||||
Offline: cleanupState(cleanupApi(settingsBody(purgeOnBody)), goOffline),
|
||||
'Loading preview': cleanupState(
|
||||
cleanupDialogApi({ [purgePreviewPath]: { status: 200, hang: true } }),
|
||||
@@ -2960,6 +2978,7 @@ export const visualStates: Record<string, Record<string, VisualState>> = {
|
||||
now: boardNow,
|
||||
api: {
|
||||
'GET /v1/auth/me': verifiedSession,
|
||||
'GET /v1/activity': homeActivityMock,
|
||||
'GET /v1/article/': { status: 200, body: sixArticlesFixture },
|
||||
'GET /v1/system/update': { status: 200, body: updateStatusBody() },
|
||||
},
|
||||
@@ -3102,13 +3121,34 @@ export const visualStates: Record<string, Record<string, VisualState>> = {
|
||||
'Up to date': { path: '/settings', skip: 'clock-sensitive' },
|
||||
Checking: {
|
||||
path: '/settings',
|
||||
exception: {
|
||||
maxPercent: 11.3,
|
||||
reason: newCardAbsentReason,
|
||||
approvedBy: 'fallen',
|
||||
},
|
||||
api: updateApi('owner', updateNeverChecked(), updateCheckHangs),
|
||||
},
|
||||
'Check failed': { path: '/settings', skip: 'clock-sensitive' },
|
||||
'Update available': { path: '/settings', skip: 'clock-sensitive' },
|
||||
'Update available, notes open': { path: '/settings', skip: 'clock-sensitive' },
|
||||
Downloading: { path: '/settings', api: updateApi('owner', updateDownloading()) },
|
||||
Verifying: { path: '/settings', api: updateApi('owner', updateJob('verifying')) },
|
||||
Downloading: {
|
||||
path: '/settings',
|
||||
api: updateApi('owner', updateDownloading()),
|
||||
exception: {
|
||||
maxPercent: 10.6,
|
||||
reason: newCardAbsentReason,
|
||||
approvedBy: 'fallen',
|
||||
},
|
||||
},
|
||||
Verifying: {
|
||||
path: '/settings',
|
||||
api: updateApi('owner', updateJob('verifying')),
|
||||
exception: {
|
||||
maxPercent: 10.8,
|
||||
reason: newCardAbsentReason,
|
||||
approvedBy: 'fallen',
|
||||
},
|
||||
},
|
||||
'Ready to install': { path: '/settings', api: updateApi('owner', updateJob('ready')) },
|
||||
'Restart: confirm': {
|
||||
path: '/settings',
|
||||
@@ -3148,14 +3188,29 @@ export const visualStates: Record<string, Record<string, VisualState>> = {
|
||||
},
|
||||
'Download failed': {
|
||||
path: '/settings',
|
||||
exception: {
|
||||
maxPercent: 10.9,
|
||||
reason: newCardAbsentReason,
|
||||
approvedBy: 'fallen',
|
||||
},
|
||||
api: updateApi('owner', updateJob('failed', { error: 'download' })),
|
||||
},
|
||||
'Verification failed': {
|
||||
path: '/settings',
|
||||
exception: {
|
||||
maxPercent: 10.5,
|
||||
reason: newCardAbsentReason,
|
||||
approvedBy: 'fallen',
|
||||
},
|
||||
api: updateApi('owner', updateJob('failed', { error: 'verification' })),
|
||||
},
|
||||
'Too many requests (429)': {
|
||||
path: '/settings',
|
||||
exception: {
|
||||
maxPercent: 11.3,
|
||||
reason: newCardAbsentReason,
|
||||
approvedBy: 'fallen',
|
||||
},
|
||||
api: updateApi('owner', updateNeverChecked(), {
|
||||
status: 429,
|
||||
headers: { 'Retry-After': '42' },
|
||||
@@ -3163,10 +3218,20 @@ export const visualStates: Record<string, Record<string, VisualState>> = {
|
||||
},
|
||||
'Not prepared': {
|
||||
path: '/settings',
|
||||
exception: {
|
||||
maxPercent: 11.9,
|
||||
reason: newCardAbsentReason,
|
||||
approvedBy: 'fallen',
|
||||
},
|
||||
api: updateApi('owner', updateAvailable()),
|
||||
},
|
||||
'Not prepared: command copied': {
|
||||
path: '/settings',
|
||||
exception: {
|
||||
maxPercent: 11.9,
|
||||
reason: newCardAbsentReason,
|
||||
approvedBy: 'fallen',
|
||||
},
|
||||
origin: integrationOrigin,
|
||||
api: updateApi('owner', updateAvailable()),
|
||||
steps: async (page) => {
|
||||
@@ -3491,52 +3556,88 @@ export const visualStates: Record<string, Record<string, VisualState>> = {
|
||||
home: {
|
||||
Default: {
|
||||
path: '/home',
|
||||
exception: {
|
||||
maxPercent: 13.5,
|
||||
reason: newCardAbsentReason,
|
||||
approvedBy: 'fallen',
|
||||
},
|
||||
now: boardNow,
|
||||
api: {
|
||||
'GET /v1/auth/me': verifiedSession,
|
||||
'GET /v1/activity': homeActivityMock,
|
||||
'GET /v1/system/update': { status: 200, body: updateStatusBody() },
|
||||
'GET /v1/article/': { status: 200, body: sixArticlesFixture },
|
||||
},
|
||||
},
|
||||
Loading: {
|
||||
path: '/home',
|
||||
exception: {
|
||||
maxPercent: 18.6,
|
||||
reason: newCardAbsentReason,
|
||||
approvedBy: 'fallen',
|
||||
},
|
||||
now: boardNow,
|
||||
api: {
|
||||
'GET /v1/auth/me': verifiedSession,
|
||||
'GET /v1/activity': homeActivityMock,
|
||||
'GET /v1/system/update': { status: 200, body: updateStatusBody() },
|
||||
'GET /v1/article/': { status: 200, body: sixArticlesFixture, hang: true },
|
||||
},
|
||||
},
|
||||
'Empty, first run': {
|
||||
path: '/home',
|
||||
exception: {
|
||||
maxPercent: 11.4,
|
||||
reason: newCardAbsentReason,
|
||||
approvedBy: 'fallen',
|
||||
},
|
||||
now: boardNow,
|
||||
api: {
|
||||
'GET /v1/auth/me': verifiedSession,
|
||||
'GET /v1/activity': homeActivityMock,
|
||||
'GET /v1/system/update': { status: 200, body: updateStatusBody() },
|
||||
'GET /v1/article/': { status: 200, body: [] },
|
||||
},
|
||||
},
|
||||
Error: {
|
||||
path: '/home',
|
||||
exception: {
|
||||
maxPercent: 25.3,
|
||||
reason: newCardAbsentReason,
|
||||
approvedBy: 'fallen',
|
||||
},
|
||||
now: boardNow,
|
||||
api: {
|
||||
'GET /v1/auth/me': verifiedSession,
|
||||
'GET /v1/activity': homeActivityMock,
|
||||
'GET /v1/system/update': { status: 200, body: updateStatusBody() },
|
||||
'GET /v1/article/': { status: 500 },
|
||||
},
|
||||
},
|
||||
'Update available (owner)': {
|
||||
path: '/home',
|
||||
exception: {
|
||||
maxPercent: 11.9,
|
||||
reason: newCardAbsentReason,
|
||||
approvedBy: 'fallen',
|
||||
},
|
||||
api: {
|
||||
'GET /v1/auth/me': verifiedSession,
|
||||
'GET /v1/activity': homeActivityMock,
|
||||
'GET /v1/article/': { status: 200, body: sixArticlesFixture },
|
||||
'GET /v1/system/update': { status: 200, body: updateAvailable() },
|
||||
},
|
||||
},
|
||||
'Update ready to install (owner)': {
|
||||
path: '/home',
|
||||
exception: {
|
||||
maxPercent: 11.9,
|
||||
reason: newCardAbsentReason,
|
||||
approvedBy: 'fallen',
|
||||
},
|
||||
api: {
|
||||
'GET /v1/auth/me': verifiedSession,
|
||||
'GET /v1/activity': homeActivityMock,
|
||||
'GET /v1/article/': { status: 200, body: sixArticlesFixture },
|
||||
'GET /v1/system/update': { status: 200, body: updateJob('ready') },
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user