Overviews: icon toolbar, dashboard drafts, publish all
Both overviews carried the same toolbar twice, left-aligned, with a search
field permanently taking a row of width. One `OverviewToolbar` now serves
them: the search folds into an icon and expands again on click (Escape puts
it away and hands focus back), create is a `+`, and everything sits right of
the page. Each page keeps its own create dialog — the toolbar only renders
the trigger — so the testids the runtime spec and the capture script drive
stayed where they were.
Dashboards get the flow store's draft/publish split. The editor autosaves
`dashboard.draft.json` beside `dashboard.json`; `/view/{name}`, `bindings_for`
and `history_requirements` keep reading the published file, so a wall panel
sees an edit only once someone publishes it. `POST /dashboards/{name}/publish`
and `/discard` mirror the flow routes down to the version precondition and the
409, `GET /dashboards/{name}?draft=true` is what the editor asks for, and the
dock grows the same Publish button — which flushes a queued save first, so an
autosave in flight is not published around. Creating a dashboard still writes
the published file directly: an empty document on a panel is harmless, and it
keeps the store free of a never-published case.
"Publish all" is a checkmark in the toolbar, live only when something actually
has `has_draft`. A summary carries no version and publish needs the one it is
based on, so each document's detail is read immediately before its publish —
honest against a stale list, and no version-less backend path to maintain.
Failures are counted rather than swallowed: three of five fails says so and
names the three.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XC2jX6Hdj7pxGGKzBTrbqB
This commit is contained in:
@@ -359,6 +359,11 @@ export const DashboardDef_InputSchema = {
|
||||
type: 'integer',
|
||||
title: 'Version',
|
||||
default: 1
|
||||
},
|
||||
has_draft: {
|
||||
type: 'boolean',
|
||||
title: 'Has Draft',
|
||||
default: false
|
||||
}
|
||||
},
|
||||
type: 'object',
|
||||
@@ -410,6 +415,11 @@ export const DashboardDef_OutputSchema = {
|
||||
type: 'integer',
|
||||
title: 'Version',
|
||||
default: 1
|
||||
},
|
||||
has_draft: {
|
||||
type: 'boolean',
|
||||
title: 'Has Draft',
|
||||
default: false
|
||||
}
|
||||
},
|
||||
type: 'object',
|
||||
@@ -438,6 +448,11 @@ export const DashboardSummarySchema = {
|
||||
type: 'integer',
|
||||
title: 'Widget Count',
|
||||
default: 0
|
||||
},
|
||||
has_draft: {
|
||||
type: 'boolean',
|
||||
title: 'Has Draft',
|
||||
default: false
|
||||
}
|
||||
},
|
||||
type: 'object',
|
||||
@@ -2501,6 +2516,18 @@ message it publishes — and is validated against the type below rather than
|
||||
by a schema per class, because the whole set is small and closed.`
|
||||
} as const;
|
||||
|
||||
export const app__api__routes__dashboards__PublishRequestSchema = {
|
||||
properties: {
|
||||
version: {
|
||||
type: 'integer',
|
||||
title: 'Version'
|
||||
}
|
||||
},
|
||||
type: 'object',
|
||||
required: ['version'],
|
||||
title: 'PublishRequest'
|
||||
} as const;
|
||||
|
||||
export const app__api__routes__dashboards__RenameRequestSchema = {
|
||||
properties: {
|
||||
name: {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import type { CancelablePromise } from './core/CancelablePromise';
|
||||
import { OpenAPI } from './core/OpenAPI';
|
||||
import { request as __request } from './core/request';
|
||||
import type { AlertsReadAlertsConfigResponse, AlertsSaveAlertsConfigData, AlertsSaveAlertsConfigResponse, AlertsTestChannelData, AlertsTestChannelResponse, DashboardsReadDashboardsResponse, DashboardsReadDashboardData, DashboardsReadDashboardResponse, DashboardsCreateDashboardData, DashboardsCreateDashboardResponse, DashboardsSaveDashboardData, DashboardsSaveDashboardResponse, DashboardsDeleteDashboardData, DashboardsDeleteDashboardResponse, DashboardsRenameDashboardData, DashboardsRenameDashboardResponse, FlowsReadFlowsResponse, FlowsReadNodeTypesResponse, FlowsReadGraphResponse, FlowsReadLibraryResponse, FlowsDeleteSharedNodeData, FlowsDeleteSharedNodeResponse, FlowsReadFlowData, FlowsReadFlowResponse, FlowsSaveFlowData, FlowsSaveFlowResponse, FlowsDeleteFlowData, FlowsDeleteFlowResponse, FlowsPublishFlowData, FlowsPublishFlowResponse, FlowsDiscardDraftData, FlowsDiscardDraftResponse, FlowsRenameFlowData, FlowsRenameFlowResponse, FlowsReadNodeSourceData, FlowsReadNodeSourceResponse, FlowsSaveNodeSourceData, FlowsSaveNodeSourceResponse, FlowsShareNodeData, FlowsShareNodeResponse, FlowsUnshareNodeData, FlowsUnshareNodeResponse, FlowsStartFlowData, FlowsStartFlowResponse, FlowsStopFlowData, FlowsStopFlowResponse, FlowsPauseFlowData, FlowsPauseFlowResponse, FlowsResumeFlowData, FlowsResumeFlowResponse, FlowsStepFlowData, FlowsStepFlowResponse, FlowsValidateFlowData, FlowsValidateFlowResponse, FlowsRunFlowData, FlowsRunFlowResponse, FlowsTriggerNodeData, FlowsTriggerNodeResponse, FlowsCancelNodeData, FlowsCancelNodeResponse, FlowsReadFlowStateData, FlowsReadFlowStateResponse, FlowsReadMessageHistoryData, FlowsReadMessageHistoryResponse, LoginLoginAccessTokenData, LoginLoginAccessTokenResponse, LoginTestTokenResponse, LoginRecoverPasswordData, LoginRecoverPasswordResponse, LoginResetPasswordData, LoginResetPasswordResponse, LoginRecoverPasswordHtmlContentData, LoginRecoverPasswordHtmlContentResponse, MessagesReadMessagesResponse, MessagesPublishMessageData, MessagesPublishMessageResponse, MessagesReadMessageHistoryData, MessagesReadMessageHistoryResponse, ModulesReadModulesResponse, ModulesApplyModulesData, ModulesApplyModulesResponse, OauthRegisterClientData, OauthRegisterClientResponse, OauthAuthorizeValidateData, OauthAuthorizeValidateResponse, OauthAuthorizeData, OauthAuthorizeResponse, OauthTokenData, OauthTokenResponse, OauthReadClientsResponse, OauthRevokeClientData, OauthRevokeClientResponse, ObservabilityReadSummaryResponse, ObservabilityReadTimeseriesData, ObservabilityReadTimeseriesResponse, ObservabilityReadFlowRollupsData, ObservabilityReadFlowRollupsResponse, ObservabilityReadRunsData, ObservabilityReadRunsResponse, ObservabilityReadEventsData, ObservabilityReadEventsResponse, ObservabilityReadDeadLettersData, ObservabilityReadDeadLettersResponse, PrivateCreateUserData, PrivateCreateUserResponse, SecretsReadSecretsResponse, SecretsSaveSecretData, SecretsSaveSecretResponse, SecretsDeleteSecretData, SecretsDeleteSecretResponse, UsersReadUsersData, UsersReadUsersResponse, UsersCreateUserData, UsersCreateUserResponse, UsersReadUserMeResponse, UsersDeleteUserMeResponse, UsersUpdateUserMeData, UsersUpdateUserMeResponse, UsersUpdatePasswordMeData, UsersUpdatePasswordMeResponse, UsersRegisterUserData, UsersRegisterUserResponse, UsersReadUserByIdData, UsersReadUserByIdResponse, UsersUpdateUserData, UsersUpdateUserResponse, UsersDeleteUserData, UsersDeleteUserResponse, UtilsTestEmailData, UtilsTestEmailResponse, UtilsHealthCheckResponse, UtilsHealthResponse } from './types.gen';
|
||||
import type { AlertsReadAlertsConfigResponse, AlertsSaveAlertsConfigData, AlertsSaveAlertsConfigResponse, AlertsTestChannelData, AlertsTestChannelResponse, DashboardsReadDashboardsResponse, DashboardsReadDashboardData, DashboardsReadDashboardResponse, DashboardsCreateDashboardData, DashboardsCreateDashboardResponse, DashboardsSaveDashboardData, DashboardsSaveDashboardResponse, DashboardsDeleteDashboardData, DashboardsDeleteDashboardResponse, DashboardsPublishDashboardData, DashboardsPublishDashboardResponse, DashboardsDiscardDashboardDraftData, DashboardsDiscardDashboardDraftResponse, DashboardsRenameDashboardData, DashboardsRenameDashboardResponse, FlowsReadFlowsResponse, FlowsReadNodeTypesResponse, FlowsReadGraphResponse, FlowsReadLibraryResponse, FlowsDeleteSharedNodeData, FlowsDeleteSharedNodeResponse, FlowsReadFlowData, FlowsReadFlowResponse, FlowsSaveFlowData, FlowsSaveFlowResponse, FlowsDeleteFlowData, FlowsDeleteFlowResponse, FlowsPublishFlowData, FlowsPublishFlowResponse, FlowsDiscardDraftData, FlowsDiscardDraftResponse, FlowsRenameFlowData, FlowsRenameFlowResponse, FlowsReadNodeSourceData, FlowsReadNodeSourceResponse, FlowsSaveNodeSourceData, FlowsSaveNodeSourceResponse, FlowsShareNodeData, FlowsShareNodeResponse, FlowsUnshareNodeData, FlowsUnshareNodeResponse, FlowsStartFlowData, FlowsStartFlowResponse, FlowsStopFlowData, FlowsStopFlowResponse, FlowsPauseFlowData, FlowsPauseFlowResponse, FlowsResumeFlowData, FlowsResumeFlowResponse, FlowsStepFlowData, FlowsStepFlowResponse, FlowsValidateFlowData, FlowsValidateFlowResponse, FlowsRunFlowData, FlowsRunFlowResponse, FlowsTriggerNodeData, FlowsTriggerNodeResponse, FlowsCancelNodeData, FlowsCancelNodeResponse, FlowsReadFlowStateData, FlowsReadFlowStateResponse, FlowsReadMessageHistoryData, FlowsReadMessageHistoryResponse, LoginLoginAccessTokenData, LoginLoginAccessTokenResponse, LoginTestTokenResponse, LoginRecoverPasswordData, LoginRecoverPasswordResponse, LoginResetPasswordData, LoginResetPasswordResponse, LoginRecoverPasswordHtmlContentData, LoginRecoverPasswordHtmlContentResponse, MessagesReadMessagesResponse, MessagesPublishMessageData, MessagesPublishMessageResponse, MessagesReadMessageHistoryData, MessagesReadMessageHistoryResponse, ModulesReadModulesResponse, ModulesApplyModulesData, ModulesApplyModulesResponse, OauthRegisterClientData, OauthRegisterClientResponse, OauthAuthorizeValidateData, OauthAuthorizeValidateResponse, OauthAuthorizeData, OauthAuthorizeResponse, OauthTokenData, OauthTokenResponse, OauthReadClientsResponse, OauthRevokeClientData, OauthRevokeClientResponse, ObservabilityReadSummaryResponse, ObservabilityReadTimeseriesData, ObservabilityReadTimeseriesResponse, ObservabilityReadFlowRollupsData, ObservabilityReadFlowRollupsResponse, ObservabilityReadRunsData, ObservabilityReadRunsResponse, ObservabilityReadEventsData, ObservabilityReadEventsResponse, ObservabilityReadDeadLettersData, ObservabilityReadDeadLettersResponse, PrivateCreateUserData, PrivateCreateUserResponse, SecretsReadSecretsResponse, SecretsSaveSecretData, SecretsSaveSecretResponse, SecretsDeleteSecretData, SecretsDeleteSecretResponse, UsersReadUsersData, UsersReadUsersResponse, UsersCreateUserData, UsersCreateUserResponse, UsersReadUserMeResponse, UsersDeleteUserMeResponse, UsersUpdateUserMeData, UsersUpdateUserMeResponse, UsersUpdatePasswordMeData, UsersUpdatePasswordMeResponse, UsersRegisterUserData, UsersRegisterUserResponse, UsersReadUserByIdData, UsersReadUserByIdResponse, UsersUpdateUserData, UsersUpdateUserResponse, UsersDeleteUserData, UsersDeleteUserResponse, UtilsTestEmailData, UtilsTestEmailResponse, UtilsHealthCheckResponse, UtilsHealthResponse } from './types.gen';
|
||||
|
||||
export class AlertsService {
|
||||
/**
|
||||
@@ -77,8 +77,10 @@ export class DashboardsService {
|
||||
|
||||
/**
|
||||
* Read Dashboard
|
||||
* What a panel shows, or with ``draft`` the copy the editor is on.
|
||||
* @param data The data for the request.
|
||||
* @param data.name
|
||||
* @param data.draft
|
||||
* @returns DashboardDef_Output Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
@@ -89,6 +91,9 @@ export class DashboardsService {
|
||||
path: {
|
||||
name: data.name
|
||||
},
|
||||
query: {
|
||||
draft: data.draft
|
||||
},
|
||||
errors: {
|
||||
422: 'Validation Error'
|
||||
}
|
||||
@@ -118,7 +123,11 @@ export class DashboardsService {
|
||||
|
||||
/**
|
||||
* Save Dashboard
|
||||
* Replace a dashboard, refusing a save someone else has moved past.
|
||||
* Save unpublished changes, refusing a save someone else has moved past.
|
||||
*
|
||||
* This writes a draft: panels keep showing the published document until
|
||||
* someone publishes, so nothing here can change what a wall is displaying —
|
||||
* which is also why the engine's history limits are left alone.
|
||||
* @param data The data for the request.
|
||||
* @param data.name
|
||||
* @param data.requestBody
|
||||
@@ -160,6 +169,51 @@ export class DashboardsService {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish Dashboard
|
||||
* Put the unpublished changes on the panels.
|
||||
* @param data The data for the request.
|
||||
* @param data.name
|
||||
* @param data.requestBody
|
||||
* @returns DashboardDef_Output Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static publishDashboard(data: DashboardsPublishDashboardData): CancelablePromise<DashboardsPublishDashboardResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'POST',
|
||||
url: '/api/v1/dashboards/{name}/publish',
|
||||
path: {
|
||||
name: data.name
|
||||
},
|
||||
body: data.requestBody,
|
||||
mediaType: 'application/json',
|
||||
errors: {
|
||||
422: 'Validation Error'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Discard Dashboard Draft
|
||||
* Throw the unpublished changes away and go back to what is shown.
|
||||
* @param data The data for the request.
|
||||
* @param data.name
|
||||
* @returns DashboardDef_Output Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static discardDashboardDraft(data: DashboardsDiscardDashboardDraftData): CancelablePromise<DashboardsDiscardDashboardDraftResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'POST',
|
||||
url: '/api/v1/dashboards/{name}/discard',
|
||||
path: {
|
||||
name: data.name
|
||||
},
|
||||
errors: {
|
||||
422: 'Validation Error'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename Dashboard
|
||||
* @param data The data for the request.
|
||||
|
||||
@@ -9,6 +9,10 @@ export type AlertsConfig = {
|
||||
rules?: Array<Rule>;
|
||||
};
|
||||
|
||||
export type app__api__routes__dashboards__PublishRequest = {
|
||||
version: number;
|
||||
};
|
||||
|
||||
export type app__api__routes__dashboards__RenameRequest = {
|
||||
name: string;
|
||||
};
|
||||
@@ -132,6 +136,7 @@ export type DashboardDef_Input = {
|
||||
canvas_height?: number;
|
||||
pages?: Array<PageDef_Input>;
|
||||
version?: number;
|
||||
has_draft?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -145,6 +150,7 @@ export type DashboardDef_Output = {
|
||||
canvas_height?: number;
|
||||
pages?: Array<PageDef_Output>;
|
||||
version?: number;
|
||||
has_draft?: boolean;
|
||||
};
|
||||
|
||||
export type DashboardsPublic = {
|
||||
@@ -160,6 +166,7 @@ export type DashboardSummary = {
|
||||
title?: string;
|
||||
page_count?: number;
|
||||
widget_count?: number;
|
||||
has_draft?: boolean;
|
||||
};
|
||||
|
||||
export type DeadLetter = {
|
||||
@@ -785,6 +792,7 @@ export type AlertsTestChannelResponse = (Message);
|
||||
export type DashboardsReadDashboardsResponse = (DashboardsPublic);
|
||||
|
||||
export type DashboardsReadDashboardData = {
|
||||
draft?: boolean;
|
||||
name: string;
|
||||
};
|
||||
|
||||
@@ -809,6 +817,19 @@ export type DashboardsDeleteDashboardData = {
|
||||
|
||||
export type DashboardsDeleteDashboardResponse = (Message);
|
||||
|
||||
export type DashboardsPublishDashboardData = {
|
||||
name: string;
|
||||
requestBody: app__api__routes__dashboards__PublishRequest;
|
||||
};
|
||||
|
||||
export type DashboardsPublishDashboardResponse = (DashboardDef_Output);
|
||||
|
||||
export type DashboardsDiscardDashboardDraftData = {
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type DashboardsDiscardDashboardDraftResponse = (DashboardDef_Output);
|
||||
|
||||
export type DashboardsRenameDashboardData = {
|
||||
name: string;
|
||||
requestBody: app__api__routes__dashboards__RenameRequest;
|
||||
|
||||
Reference in New Issue
Block a user