Introduce diff page sidebar for plugins
Demo: https://imgur.com/a/GiTHlVY
Dark: https://imgur.com/a/6GDffto
A plugin must register to 2 endpoints:
1. 'sidebarTrigger', typically a button or icon, placed in the headerbar
pluginApi.registerCustomComponent(
'sidebarTrigger', 'my-sidebar-trigger');
The trigger component recives an onTrigger function to call with the
plugin name when triggered:
this.onTrigger(this.plugin.getPluginName());
2. 'sidebarContent', arbitrary content appearing in the sidebar
The trigger endpoint must be registered dynamically.
pluginApi.registerDynamicCustomComponent(
'sidebarContent', 'my-sidebar-content');
Release-Notes: Add diff page sidebar for plugins
Change-Id: I3aba40fec65a2d7617034b5614ec52ab45cc812c
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
index 93cb124..1eef413 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
@@ -5,6 +5,8 @@
*/
import '@polymer/iron-dropdown/iron-dropdown';
import '@polymer/iron-input/iron-input';
+import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator';
+import '../../plugins/gr-endpoint-param/gr-endpoint-param';
import '../../../styles/gr-a11y-styles';
import '../../../styles/shared-styles';
import '../../shared/gr-button/gr-button';
@@ -139,6 +141,11 @@
@query('#diffPreferencesDialog')
diffPreferencesDialog?: GrDiffPreferencesDialog;
+ @query('.sidebarAnchor')
+ sidebarAnchor?: HTMLDivElement;
+
+ @state() private sidebarHeight = 0;
+
// Private but used in tests.
@state()
get patchRange(): PatchRange | undefined {
@@ -182,6 +189,8 @@
@state() path?: string;
+ @state() private shownSidebar?: string;
+
/** Allows us to react when the user switches to the DIFF view. */
// Private but used in tests.
@state() isActiveChildView = false;
@@ -650,6 +659,31 @@
:host(.hideComments) {
--gr-comment-thread-display: none;
}
+ .sidebarTriggerContainer {
+ display: inline-block;
+ }
+ .sidebarAnchor {
+ height: 0;
+ width: 0;
+ overflow: visible;
+ }
+ .sidebarContents {
+ background: var(--background-color-secondary);
+ width: max-content;
+ padding: var(--spacing-l);
+ border: var(--spacing-xs) solid var(--border-color);
+ border-left: 0;
+ overflow-y: auto;
+ animation: slide-in 50ms;
+ }
+ @keyframes slide-in {
+ 0% {
+ transform: translateX(-100%);
+ }
+ 100% {
+ transform: translateX(0);
+ }
+ }
`,
];
}
@@ -663,10 +697,14 @@
// TODO(newdiff-cleanup): Remove once newdiff migration is completed.
this.cursor = isNewDiff() ? new GrDiffCursorNew() : new GrDiffCursor();
if (this.diffHost) this.reInitCursor();
+ window.addEventListener('scroll', this.updateSidebarHeight);
+ window.addEventListener('resize', this.updateSidebarHeight);
}
override disconnectedCallback() {
this.cursor?.dispose();
+ window.removeEventListener('scroll', this.updateSidebarHeight);
+ window.removeEventListener('resize', this.updateSidebarHeight);
super.disconnectedCallback();
}
@@ -676,6 +714,13 @@
this.cursor?.reInitCursor();
}
+ private readonly updateSidebarHeight = () => {
+ if (this.sidebarAnchor) {
+ this.sidebarHeight =
+ window.innerHeight - this.sidebarAnchor.getBoundingClientRect().bottom;
+ }
+ };
+
protected override updated(changedProperties: PropertyValues): void {
super.updated(changedProperties);
if (
@@ -720,6 +765,7 @@
});
}
}
+ this.updateSidebarHeight();
}
override render() {
@@ -774,6 +820,7 @@
>></a
>
</div>
+ ${this.renderSidebarContent()}
</div>`;
}
@@ -805,6 +852,7 @@
@value-change=${this.handleFileChange}
></gr-dropdown-list>
</div>
+ ${this.renderSidebarTriggers()}
</div>
<div class="navLinks desktop">
<span class="fileNum ${ifDefined(fileNumClass)}">
@@ -843,6 +891,55 @@
</div>`;
}
+ private renderSidebarTriggers() {
+ return html`
+ <div class="sidebarTriggerContainer">
+ <gr-endpoint-decorator name="sidebarTrigger">
+ <gr-endpoint-param
+ name="onTrigger"
+ .value=${(pluginName: string) =>
+ (this.shownSidebar =
+ this.shownSidebar === pluginName ? undefined : pluginName)}
+ ></gr-endpoint-param>
+ </gr-endpoint-decorator>
+ </div>
+ `;
+ }
+
+ private renderSidebarContent() {
+ // Always renders the 0x0px .sidebarAnchor div for scroll measurements.
+ return html`
+ <div class="sidebarAnchor">
+ ${when(
+ this.shownSidebar !== undefined,
+ () => html`
+ <div
+ class="sidebarContents"
+ style=${`height: ${this.sidebarHeight}px`}
+ >
+ <gr-endpoint-decorator
+ name=${`sidebarContent-${this.shownSidebar}`}
+ >
+ <gr-endpoint-param
+ name="change"
+ .value=${this.change}
+ ></gr-endpoint-param>
+ <gr-endpoint-param
+ name="path"
+ .value=${this.path}
+ ></gr-endpoint-param>
+ <gr-endpoint-param
+ name="patchNum"
+ .value=${this.patchNum}
+ ></gr-endpoint-param>
+ </gr-endpoint-decorator>
+ </div>
+ `
+ )}
+ </div>
+ `;
+ }
+
private renderPatchRangeLeft() {
return html` <div class="patchRangeLeft">
<gr-patch-range-select
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.ts b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.ts
index c085953..8562741 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.ts
@@ -227,6 +227,11 @@
<gr-dropdown-list id="dropdown" show-copy-for-trigger-text="">
</gr-dropdown-list>
</div>
+ <div class="sidebarTriggerContainer">
+ <gr-endpoint-decorator name="sidebarTrigger">
+ <gr-endpoint-param name="onTrigger"></gr-endpoint-param>
+ </gr-endpoint-decorator>
+ </div>
</div>
<div class="desktop navLinks">
<span class="fileNum show">
@@ -348,6 +353,7 @@
>
</a>
</div>
+ <div class="sidebarAnchor"></div>
</div>
<h2 class="assistive-tech-only">Diff view</h2>
<gr-diff-host id="diffHost"> </gr-diff-host>