Merge changes from topic "checks-fetch"
* changes:
Change the Checks fetch API to send a data object
Add a plugin endpoint to the expanded check result
Add support for top-level actions
diff --git a/polygerrit-ui/app/api/checks.ts b/polygerrit-ui/app/api/checks.ts
index 143fbd1..799d1f7 100644
--- a/polygerrit-ui/app/api/checks.ts
+++ b/polygerrit-ui/app/api/checks.ts
@@ -43,6 +43,12 @@
fetchPollingIntervalSeconds: number;
}
+export interface ChangeData {
+ changeNumber: number;
+ patchsetNumber: number;
+ repo: string;
+}
+
export interface ChecksProvider {
/**
* Gerrit calls this method when ...
@@ -51,7 +57,7 @@
* - ... while the tab is visible in a regular polling interval, see
* ChecksApiConfig.
*/
- fetch(change: number, patchset: number): Promise<FetchResponse>;
+ fetch(change: ChangeData): Promise<FetchResponse>;
}
export interface FetchResponse {
@@ -224,10 +230,21 @@
export type ActionCallback = (
change: number,
patchset: number,
+ /**
+ * Identical to 'attempt' property of CheckRun. Not set for top-level
+ * actions.
+ */
attempt: number | undefined,
+ /**
+ * Identical to 'externalId' property of CheckRun. Not set for top-level
+ * actions.
+ */
externalId: string | undefined,
- /** Identical to 'checkName' property of CheckRun. */
- checkName: string,
+ /**
+ * Identical to 'checkName' property of CheckRun. Not set for top-level
+ * actions.
+ */
+ checkName: string | undefined,
/** Identical to 'name' property of Action entity. */
actionName: string
) => Promise<ActionResult>;
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-results.ts b/polygerrit-ui/app/elements/checks/gr-checks-results.ts
index 007af97..34945a9 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-results.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-results.ts
@@ -81,7 +81,7 @@
}
td .summary-cell {
display: flex;
- max-width: calc(100vw - 579px);
+ max-width: calc(100vw - 700px);
}
td .summary-cell .summary {
font-weight: var(--font-weight-bold);
@@ -237,9 +237,19 @@
render() {
if (!this.result) return '';
return html`
- <div class="message">
- ${this.result.message}
- </div>
+ <gr-endpoint-decorator name="check-result-expanded">
+ <gr-endpoint-param
+ name="run"
+ value="${this.result}"
+ ></gr-endpoint-param>
+ <gr-endpoint-param
+ name="result"
+ value="${this.result}"
+ ></gr-endpoint-param>
+ <div class="message">
+ ${this.result.message}
+ </div>
+ </gr-endpoint-decorator>
`;
}
}
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-runs.ts b/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
index 4a34700..5b7428b 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
@@ -22,6 +22,7 @@
import {sharedStyles} from '../../styles/shared-styles';
import {
compareByWorstCategory,
+ fireActionTriggered,
iconForRun,
primaryRunAction,
} from '../../services/checks/checks-util';
@@ -60,33 +61,6 @@
);
}
-export interface ActionTriggeredEventDetail {
- action: Action;
- run: CheckRun;
-}
-
-export type ActionTriggeredEvent = CustomEvent<ActionTriggeredEventDetail>;
-
-declare global {
- interface HTMLElementEventMap {
- 'action-triggered': ActionTriggeredEvent;
- }
-}
-
-function fireActionTriggered(
- target: EventTarget,
- action: Action,
- run: CheckRun
-) {
- target.dispatchEvent(
- new CustomEvent('action-triggered', {
- detail: {action, run},
- composed: true,
- bubbles: true,
- })
- );
-}
-
@customElement('gr-checks-run')
export class GrChecksRun extends GrLitElement {
static get styles() {
@@ -106,6 +80,11 @@
margin-top: var(--spacing-s);
cursor: pointer;
}
+ .left {
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ }
.name {
font-weight: var(--font-weight-bold);
}
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-tab.ts b/polygerrit-ui/app/elements/checks/gr-checks-tab.ts
index d31ec53..1abe631 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-tab.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-tab.ts
@@ -18,13 +18,20 @@
import {css, customElement, property} from 'lit-element';
import {GrLitElement} from '../lit/gr-lit-element';
import {Action, CheckResult, CheckRun} from '../../api/checks';
-import {allResults$, allRuns$} from '../../services/checks/checks-model';
+import {
+ allActions$,
+ allResults$,
+ allRuns$,
+} from '../../services/checks/checks-model';
import './gr-checks-runs';
import './gr-checks-results';
import {sharedStyles} from '../../styles/shared-styles';
import {changeNum$, currentPatchNum$} from '../../services/change/change-model';
import {NumericChangeId, PatchSetNum} from '../../types/common';
-import {ActionTriggeredEvent} from './gr-checks-runs';
+import {
+ ActionTriggeredEvent,
+ fireActionTriggered,
+} from '../../services/checks/checks-util';
/**
* The "Checks" tab on the Gerrit change page. Gets its data from plugins that
@@ -37,6 +44,8 @@
results: CheckResult[] = [];
+ actions: Action[] = [];
+
@property()
currentPatchNum: PatchSetNum | undefined = undefined;
@@ -46,6 +55,7 @@
constructor() {
super();
this.subscribe('runs', allRuns$);
+ this.subscribe('actions', allActions$);
this.subscribe('results', allResults$);
this.subscribe('currentPatchNum', currentPatchNum$);
this.subscribe('changeNum', changeNum$);
@@ -63,17 +73,13 @@
display: block;
}
.header {
- display: block;
+ display: flex;
+ justify-content: space-between;
padding: var(--spacing-m) var(--spacing-l);
border-bottom: 1px solid var(--border-color);
}
- .header span {
- display: inline-block;
- color: var(--link-color);
- padding: var(--spacing-s) var(--spacing-m);
- margin-right: var(--spacing-l);
- border: 1px solid var(--border-color);
- border-radius: var(--border-radius);
+ .action {
+ margin-left: var(--spacing-m);
}
.container {
display: flex;
@@ -95,15 +101,20 @@
const ps = `Patchset ${this.currentPatchNum} (Latest)`;
return html`
<div class="header">
- <gr-dropdown-list
- value="${ps}"
- .items="${[
- {
- value: `${ps}`,
- text: `${ps}`,
- },
- ]}"
- ></gr-dropdown-list>
+ <div class="left">
+ <gr-dropdown-list
+ value="${ps}"
+ .items="${[
+ {
+ value: `${ps}`,
+ text: `${ps}`,
+ },
+ ]}"
+ ></gr-dropdown-list>
+ </div>
+ <div class="right">
+ ${this.actions.map(this.renderAction)}
+ </div>
</div>
<div class="container">
<gr-checks-runs class="runs" .runs="${this.runs}"></gr-checks-runs>
@@ -115,7 +126,13 @@
`;
}
- private handleActionTriggered(action: Action, run: CheckRun) {
+ renderAction(action: Action) {
+ return html`<gr-checks-top-level-action
+ .action="${action}"
+ ></gr-checks-top-level-action>`;
+ }
+
+ handleActionTriggered(action: Action, run?: CheckRun) {
if (!this.changeNum) return;
if (!this.currentPatchNum) return;
// TODO(brohlfs): The callback is supposed to be returning a promise.
@@ -124,16 +141,35 @@
action.callback(
this.changeNum,
this.currentPatchNum as number,
- run.attempt,
- run.externalId,
- run.checkName,
+ run?.attempt,
+ run?.externalId,
+ run?.checkName,
action.name
);
}
}
+@customElement('gr-checks-top-level-action')
+export class GrChecksTopLevelAction extends GrLitElement {
+ @property()
+ action!: Action;
+
+ render() {
+ return html`
+ <gr-button link class="action" @click="${this.handleClick}"
+ >${this.action.name}</gr-button
+ >
+ `;
+ }
+
+ handleClick() {
+ fireActionTriggered(this, this.action);
+ }
+}
+
declare global {
interface HTMLElementTagNameMap {
'gr-checks-tab': GrChecksTab;
+ 'gr-checks-top-level-action': GrChecksTopLevelAction;
}
}
diff --git a/polygerrit-ui/app/services/checks/checks-model.ts b/polygerrit-ui/app/services/checks/checks-model.ts
index 9546d0b..6705a85 100644
--- a/polygerrit-ui/app/services/checks/checks-model.ts
+++ b/polygerrit-ui/app/services/checks/checks-model.ts
@@ -17,6 +17,7 @@
import {BehaviorSubject, Observable} from 'rxjs';
import {
+ Action,
Category,
CheckResult,
CheckRun,
@@ -35,6 +36,7 @@
pluginName: string;
config?: ChecksApiConfig;
runs: CheckRun[];
+ actions: Action[];
}
interface ChecksState {
@@ -53,6 +55,18 @@
distinctUntilChanged()
);
+export const allActions$ = checksState$.pipe(
+ map(state => {
+ return Object.values(state).reduce(
+ (allActions: Action[], providerState: ChecksProviderState) => [
+ ...allActions,
+ ...providerState.actions,
+ ],
+ []
+ );
+ })
+);
+
export const allRuns$ = checksState$.pipe(
map(state => {
return Object.values(state).reduce(
@@ -94,6 +108,7 @@
pluginName,
config,
runs: [],
+ actions: [],
};
privateState$.next(nextState);
}
@@ -162,11 +177,16 @@
status: RunStatus.COMPLETED,
};
-export function updateStateSetResults(pluginName: string, runs: CheckRun[]) {
+export function updateStateSetResults(
+ pluginName: string,
+ runs: CheckRun[],
+ actions: Action[] = []
+) {
const nextState = {...privateState$.getValue()};
nextState[pluginName] = {
...nextState[pluginName],
runs: [...runs],
+ actions: [...actions],
};
privateState$.next(nextState);
}
diff --git a/polygerrit-ui/app/services/checks/checks-service.ts b/polygerrit-ui/app/services/checks/checks-service.ts
index a8dd8b8..2e63f98 100644
--- a/polygerrit-ui/app/services/checks/checks-service.ts
+++ b/polygerrit-ui/app/services/checks/checks-service.ts
@@ -23,6 +23,7 @@
withLatestFrom,
} from 'rxjs/operators';
import {
+ ChangeData,
ChecksApiConfig,
ChecksProvider,
FetchResponse,
@@ -77,13 +78,20 @@
runs: [],
});
}
- return from(
- this.providers[pluginName].fetch(change._number, patchNum)
- );
+ const data: ChangeData = {
+ changeNumber: change._number,
+ patchsetNumber: patchNum,
+ repo: change.project,
+ };
+ return from(this.providers[pluginName].fetch(data));
}
),
tap(response => {
- updateStateSetResults(pluginName, response.runs ?? []);
+ updateStateSetResults(
+ pluginName,
+ response.runs ?? [],
+ response.actions
+ );
})
)
.subscribe(() => {});
diff --git a/polygerrit-ui/app/services/checks/checks-util.ts b/polygerrit-ui/app/services/checks/checks-util.ts
index 30b82b6..176464f 100644
--- a/polygerrit-ui/app/services/checks/checks-util.ts
+++ b/polygerrit-ui/app/services/checks/checks-util.ts
@@ -135,3 +135,30 @@
return 2;
}
}
+
+export interface ActionTriggeredEventDetail {
+ action: Action;
+ run?: CheckRun;
+}
+
+export type ActionTriggeredEvent = CustomEvent<ActionTriggeredEventDetail>;
+
+declare global {
+ interface HTMLElementEventMap {
+ 'action-triggered': ActionTriggeredEvent;
+ }
+}
+
+export function fireActionTriggered(
+ target: EventTarget,
+ action: Action,
+ run?: CheckRun
+) {
+ target.dispatchEvent(
+ new CustomEvent('action-triggered', {
+ detail: {action, run},
+ composed: true,
+ bubbles: true,
+ })
+ );
+}