Merge pull request #161 from umbraco/feature/published-dashboard
Feature/published dashboard
This commit is contained in:
@@ -105,6 +105,35 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ProblemDetails'
|
||||
/published-cache/status:
|
||||
get:
|
||||
operationId: PublishedCacheStatus
|
||||
responses:
|
||||
'200':
|
||||
description: 200 response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: string
|
||||
default:
|
||||
description: default response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ProblemDetails'
|
||||
/published-cache/reload:
|
||||
post:
|
||||
operationId: PublishedCacheReload
|
||||
parameters: []
|
||||
responses:
|
||||
'201':
|
||||
description: 201 response
|
||||
'400':
|
||||
description: 400 response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ProblemDetails'
|
||||
/server/status:
|
||||
get:
|
||||
operationId: GetStatus
|
||||
|
||||
@@ -22,6 +22,12 @@ export interface paths {
|
||||
"/manifests/packages/installed": {
|
||||
get: operations["ManifestsPackagesInstalled"];
|
||||
};
|
||||
"/published-cache/status": {
|
||||
get: operations["PublishedCacheStatus"];
|
||||
};
|
||||
"/published-cache/reload": {
|
||||
post: operations["PublishedCacheReload"];
|
||||
};
|
||||
"/server/status": {
|
||||
get: operations["GetStatus"];
|
||||
};
|
||||
@@ -418,6 +424,35 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
PublishedCacheStatus: {
|
||||
responses: {
|
||||
/** 200 response */
|
||||
200: {
|
||||
content: {
|
||||
"application/json": string;
|
||||
};
|
||||
};
|
||||
/** default response */
|
||||
default: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
PublishedCacheReload: {
|
||||
parameters: {};
|
||||
responses: {
|
||||
/** 201 response */
|
||||
201: unknown;
|
||||
/** 400 response */
|
||||
400: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
GetStatus: {
|
||||
responses: {
|
||||
/** 200 response */
|
||||
|
||||
@@ -1,15 +1,107 @@
|
||||
import { UUIButtonState } from '@umbraco-ui/uui';
|
||||
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
|
||||
import { css, html, LitElement } from 'lit';
|
||||
import { customElement } from 'lit/decorators.js';
|
||||
import { customElement, state } from 'lit/decorators.js';
|
||||
|
||||
import { getPublishedCacheStatus, postPublishedCacheReload } from '../../../core/api/fetcher';
|
||||
import { UmbContextConsumerMixin } from '../../../core/context';
|
||||
import { UmbNotificationService } from '../../../core/services/notification';
|
||||
import { UmbNotificationDefaultData } from '../../../core/services/notification/layouts/default';
|
||||
|
||||
@customElement('umb-dashboard-published-status')
|
||||
export class UmbDashboardPublishedStatusElement extends LitElement {
|
||||
static styles = [UUITextStyles, css``];
|
||||
export class UmbDashboardPublishedStatusElement extends UmbContextConsumerMixin(LitElement) {
|
||||
static styles = [UUITextStyles, css`
|
||||
uui-box + uui-box {
|
||||
margin-top: var(--uui-size-space-5);
|
||||
}
|
||||
uui-box p:first-child {
|
||||
margin-block-start: 0;
|
||||
}
|
||||
`];
|
||||
|
||||
@state()
|
||||
private _publishedStatusText = '';
|
||||
|
||||
@state()
|
||||
private _buttonState: UUIButtonState = undefined;
|
||||
|
||||
private _notificationService?: UmbNotificationService;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext('umbNotificationService', (notificationService: UmbNotificationService) => {
|
||||
this._notificationService = notificationService;
|
||||
});
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
||||
this._getPublishedStatus();
|
||||
}
|
||||
|
||||
private async _getPublishedStatus() {
|
||||
try {
|
||||
const { data } = await getPublishedCacheStatus({});
|
||||
this._publishedStatusText = data;
|
||||
} catch (e) {
|
||||
if (e instanceof getPublishedCacheStatus.Error) {
|
||||
const error = e.getActualType();
|
||||
const data: UmbNotificationDefaultData = { message: error.data.detail ?? 'Something went wrong' };
|
||||
this._notificationService?.peek('danger', { data });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async _onRefreshCacheHandler() {
|
||||
this._buttonState = 'waiting';
|
||||
try {
|
||||
await postPublishedCacheReload({});
|
||||
this._getPublishedStatus();
|
||||
this._buttonState = 'success';
|
||||
} catch (e) {
|
||||
this._buttonState = 'failed';
|
||||
if (e instanceof postPublishedCacheReload.Error) {
|
||||
const error = e.getActualType();
|
||||
const data: UmbNotificationDefaultData = { message: error.data.detail ?? 'Something went wrong' };
|
||||
this._notificationService?.peek('danger', { data });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async _onReloadCacheHandler() {
|
||||
await undefined;
|
||||
}
|
||||
|
||||
private async _onRebuildCacheHandler() {
|
||||
await undefined;
|
||||
}
|
||||
|
||||
private async _onSnapshotCacheHandler() {
|
||||
await undefined;
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<uui-box>
|
||||
<h1>Published Status</h1>
|
||||
<uui-box headline="Published Cache Status">
|
||||
<p>${this._publishedStatusText}</p>
|
||||
<uui-button .state=${this._buttonState} type="button" look="primary" @click=${this._onRefreshCacheHandler}>Refresh Status</uui-button>
|
||||
</uui-box>
|
||||
|
||||
<uui-box headline="Memory Cache">
|
||||
<p>This button lets you reload the in-memory cache, by entirely reloading it from the database cache (but it does not rebuild that database cache). This is relatively fast. Use it when you think that the memory cache has not been properly refreshed, after some events triggered—which would indicate a minor Umbraco issue. (note: triggers the reload on all servers in an LB environment).</p>
|
||||
<uui-button type="button" look="danger" @click=${this._onReloadCacheHandler}>Reload Memory Cache</uui-button>
|
||||
</uui-box>
|
||||
|
||||
<uui-box headline="Database Cache">
|
||||
<p>This button lets you rebuild the database cache, ie the content of the cmsContentNu table. Rebuilding can be expensive. Use it when reloading is not enough, and you think that the database cache has not been properly generated—which would indicate some critical Umbraco issue.</p>
|
||||
<uui-button type="button" look="danger" @click=${this._onRebuildCacheHandler}>Rebuild Database Cache</uui-button>
|
||||
</uui-box>
|
||||
|
||||
<uui-box headline="Internal Cache">
|
||||
<p>This button lets you trigger a NuCache snapshots collection (after running a fullCLR GC). Unless you know what that means, you probably do not need to use it.</p>
|
||||
<uui-button type="button" look="danger" @click=${this._onSnapshotCacheHandler}>Snapshot Internal Cache</uui-button>
|
||||
</uui-box>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { expect, fixture, html } from '@open-wc/testing';
|
||||
|
||||
import { defaultA11yConfig } from '../../../core/helpers/chai';
|
||||
import { UmbDashboardPublishedStatusElement } from './dashboard-published-status.element';
|
||||
|
||||
describe('UmbDashboardPublishedStatus', () => {
|
||||
let element: UmbDashboardPublishedStatusElement;
|
||||
|
||||
beforeEach(async () => {
|
||||
element = await fixture(html`<umb-dashboard-published-status></umb-dashboard-published-status>`);
|
||||
});
|
||||
|
||||
it('is defined with its own instance', () => {
|
||||
expect(element).to.be.instanceOf(UmbDashboardPublishedStatusElement);
|
||||
});
|
||||
|
||||
it('passes the a11y audit', async () => {
|
||||
await expect(element).to.be.accessible(defaultA11yConfig);
|
||||
});
|
||||
});
|
||||
@@ -31,6 +31,10 @@ export class UmbSectionDashboards extends UmbContextConsumerMixin(LitElement) {
|
||||
padding: var(--uui-size-space-5);
|
||||
display: block;
|
||||
}
|
||||
|
||||
#scroll-container {
|
||||
height: 500px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
@@ -146,7 +150,9 @@ export class UmbSectionDashboards extends UmbContextConsumerMixin(LitElement) {
|
||||
render() {
|
||||
return html`
|
||||
${this._renderNavigation()}
|
||||
<router-slot id="router-slot" .routes="${this._routes}"></router-slot>
|
||||
<uui-scroll-container id="scroll-container">
|
||||
<router-slot id="router-slot" .routes="${this._routes}"></router-slot>
|
||||
</uui-scroll-container>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,3 +21,5 @@ export const getUpgradeSettings = fetcher.path('/upgrade/settings').method('get'
|
||||
export const PostUpgradeAuthorize = fetcher.path('/upgrade/authorize').method('post').create();
|
||||
export const getManifests = fetcher.path('/manifests').method('get').create();
|
||||
export const getPackagesInstalled = fetcher.path('/manifests/packages/installed').method('get').create();
|
||||
export const getPublishedCacheStatus = fetcher.path('/published-cache/status').method('get').create();
|
||||
export const postPublishedCacheReload = fetcher.path('/published-cache/reload').method('post').create();
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { handlers as contentHandlers } from './domains/node.handlers';
|
||||
import { handlers as dataTypeHandlers } from './domains/data-type.handlers';
|
||||
import { handlers as documentTypeHandlers } from './domains/document-type.handlers';
|
||||
import { handlers as treeHandlers } from './domains/entity.handlers';
|
||||
import { handlers as installHandlers } from './domains/install.handlers';
|
||||
import * as manifestsHandlers from './domains/manifests.handlers';
|
||||
import { handlers as contentHandlers } from './domains/node.handlers';
|
||||
import { handlers as publishedStatusHandlers } from './domains/published-status.handlers';
|
||||
import * as serverHandlers from './domains/server.handlers';
|
||||
import { handlers as upgradeHandlers } from './domains/upgrade.handlers';
|
||||
import { handlers as userHandlers } from './domains/user.handlers';
|
||||
import { handlers as treeHandlers } from './domains/entity.handlers';
|
||||
|
||||
const handlers = [
|
||||
serverHandlers.serverVersionHandler,
|
||||
@@ -18,6 +19,7 @@ const handlers = [
|
||||
...documentTypeHandlers,
|
||||
...treeHandlers,
|
||||
...manifestsHandlers.default,
|
||||
...publishedStatusHandlers,
|
||||
];
|
||||
|
||||
switch (import.meta.env.VITE_UMBRACO_INSTALL_STATUS) {
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { rest } from 'msw';
|
||||
|
||||
import umbracoPath from '../../core/helpers/umbraco-path';
|
||||
|
||||
export const handlers = [
|
||||
rest.get(umbracoPath('/published-cache/status'), (_req, res, ctx) => {
|
||||
return res(
|
||||
// Respond with a 200 status code
|
||||
ctx.status(200),
|
||||
ctx.json<string>(
|
||||
'Database cache is ok. ContentStore contains 1 item and has 1 generation and 0 snapshot. MediaStore contains 5 items and has 1 generation and 0 snapshot.'
|
||||
)
|
||||
);
|
||||
}),
|
||||
|
||||
rest.post(umbracoPath('/published-cache/reload'), async (_req, res, ctx) => {
|
||||
await new Promise((resolve) => setTimeout(resolve, (Math.random() + 1) * 1000)); // simulate a delay of 1-2 seconds
|
||||
|
||||
return res(
|
||||
// Respond with a 200 status code
|
||||
ctx.status(201)
|
||||
);
|
||||
}),
|
||||
];
|
||||
@@ -1,8 +1,9 @@
|
||||
import { handlers as contentHandlers } from './domains/node.handlers';
|
||||
import { handlers as dataTypeHandlers } from './domains/data-type.handlers';
|
||||
import { handlers as documentTypeHandlers } from './domains/document-type.handlers';
|
||||
import { handlers as installHandlers } from './domains/install.handlers';
|
||||
import * as manifestsHandlers from './domains/manifests.handlers';
|
||||
import { handlers as contentHandlers } from './domains/node.handlers';
|
||||
import { handlers as publishedStatusHandlers } from './domains/published-status.handlers';
|
||||
import * as serverHandlers from './domains/server.handlers';
|
||||
import { handlers as upgradeHandlers } from './domains/upgrade.handlers';
|
||||
import { handlers as userHandlers } from './domains/user.handlers';
|
||||
@@ -18,4 +19,5 @@ export const handlers = [
|
||||
...dataTypeHandlers,
|
||||
...documentTypeHandlers,
|
||||
...manifestsHandlers.default,
|
||||
...publishedStatusHandlers,
|
||||
];
|
||||
|
||||
@@ -118,6 +118,18 @@ export const internalManifests: Array<ManifestTypes & { loader: () => Promise<ob
|
||||
weight: 10,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'dashboard',
|
||||
alias: 'Umb.Dashboard.PublishedStatus',
|
||||
name: 'Published Status',
|
||||
elementName: 'umb-dashboard-published-status',
|
||||
loader: () => import('./backoffice/dashboards/published-status/dashboard-published-status.element'),
|
||||
meta: {
|
||||
sections: ['Umb.Section.Settings'],
|
||||
pathname: 'published-status', // TODO: how to we want to support pretty urls?
|
||||
weight: 9,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'dashboard',
|
||||
alias: 'Umb.Dashboard.MediaManagement',
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import './installer';
|
||||
import './manifests';
|
||||
import './publishedstatus';
|
||||
import './server';
|
||||
import './upgrader';
|
||||
import './user';
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { body, defaultResponse, endpoint, request, response } from '@airtasker/spot';
|
||||
|
||||
import { ProblemDetails } from './models';
|
||||
|
||||
@endpoint({
|
||||
method: 'GET',
|
||||
path: '/published-cache/status',
|
||||
})
|
||||
export class PublishedCacheStatus {
|
||||
@response({ status: 200 })
|
||||
success(@body body: string) {}
|
||||
|
||||
@defaultResponse
|
||||
default(@body body: ProblemDetails) {}
|
||||
}
|
||||
|
||||
@endpoint({
|
||||
method: 'POST',
|
||||
path: '/published-cache/reload',
|
||||
})
|
||||
export class PublishedCacheReload {
|
||||
@request
|
||||
request() {}
|
||||
|
||||
@response({ status: 201 })
|
||||
success() {}
|
||||
|
||||
@response({ status: 400 })
|
||||
badRequest(@body body: ProblemDetails) {}
|
||||
}
|
||||
Reference in New Issue
Block a user