diff --git a/src/system/iterable.ts b/src/system/iterable.ts index bfbb8fad12bbf..565e72d9a375e 100644 --- a/src/system/iterable.ts +++ b/src/system/iterable.ts @@ -16,6 +16,12 @@ export function* chunk(source: T[], size: number): Iterable { } } +export const IterUtils = { + notNull: function (x: T | null | undefined): x is T { + return Boolean(x); + }, +}; + export function* chunkByStringLength(source: string[], maxLength: number): Iterable { let chunk: string[] = []; diff --git a/src/webviews/apps/home/home.ts b/src/webviews/apps/home/home.ts index 2b24d502413c1..eb45819249f7a 100644 --- a/src/webviews/apps/home/home.ts +++ b/src/webviews/apps/home/home.ts @@ -5,7 +5,7 @@ import { html } from 'lit'; import { customElement, query } from 'lit/decorators.js'; import { when } from 'lit/directives/when.js'; import type { State } from '../../home/protocol'; -import { DidFocusAccount } from '../../home/protocol'; +import { DidChangeOverviewFilter, DidFocusAccount } from '../../home/protocol'; import { OverviewState, overviewStateContext } from '../plus/home/components/overviewState'; import type { GLHomeAccountContent } from '../plus/shared/components/home-account-content'; import { GlApp } from '../shared/app'; @@ -51,6 +51,11 @@ export class GlHomeApp extends GlApp { case DidFocusAccount.is(msg): this.accountContentEl.show(); break; + case DidChangeOverviewFilter.is(msg): + this._overviewState.filter.recent = msg.params.filter.recent; + this._overviewState.filter.stale = msg.params.filter.stale; + this._overviewState.run(true); + break; } }); } diff --git a/src/webviews/apps/plus/home/components/branch-section.ts b/src/webviews/apps/plus/home/components/branch-section.ts index eec445b244b32..251c643bbf4aa 100644 --- a/src/webviews/apps/plus/home/components/branch-section.ts +++ b/src/webviews/apps/plus/home/components/branch-section.ts @@ -21,6 +21,11 @@ export const sectionHeadingStyles = css` margin-block: 0 0.8rem; text-transform: uppercase; } + .section-heading.with-actions { + display: flex; + justify-content: space-between; + gap: 8px; + } `; @customElement('gl-branch-section') @@ -40,7 +45,9 @@ export class GlBranchSection extends LitElement { override render() { return html`
-

${this.label}

+

+ ${this.label} +

${this.branches.map(branch => html``)}
diff --git a/src/webviews/apps/plus/home/components/branch-threshold-filter.ts b/src/webviews/apps/plus/home/components/branch-threshold-filter.ts new file mode 100644 index 0000000000000..04f674f02e4ca --- /dev/null +++ b/src/webviews/apps/plus/home/components/branch-threshold-filter.ts @@ -0,0 +1,71 @@ +import { css, html } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import { repeat } from 'lit/directives/repeat.js'; +import type { OverviewRecentThreshold, OverviewStaleThreshold } from '../../../../home/protocol'; +import '../../../shared/components/checkbox/checkbox'; +import '../../../shared/components/code-icon'; +import { GlElement } from '../../../shared/components/element'; +import '../../../shared/components/menu/index'; +import '../../../shared/components/menu/menu-item'; +import '../../../shared/components/menu/menu-list'; +import '../../../shared/components/overlays/popover'; + +@customElement('gl-branch-threshold-filter') +export class GlBranchThresholdFilter extends GlElement { + static override readonly styles = [ + css` + .date-select { + background: none; + outline: none; + border: none; + cursor: pointer; + color: var(--vscode-disabledForeground); + text-decoration: none !important; + font-weight: 500; + } + .date-select option { + color: var(--vscode-foreground); + background-color: var(--vscode-dropdown-background); + } + .date-select:focus { + outline: 1px solid var(--vscode-disabledForeground); + } + .date-select:hover { + color: var(--vscode-foreground); + text-decoration: underline !important; + } + `, + ]; + + @property({ type: String }) value: OverviewRecentThreshold | OverviewStaleThreshold | undefined; + @property({ type: Array }) options!: { value: OverviewRecentThreshold | OverviewStaleThreshold; label: string }[]; + private selectDateFilter(threshold: OverviewRecentThreshold | OverviewStaleThreshold) { + const event = new CustomEvent('gl-change', { + detail: { threshold: threshold }, + }); + this.dispatchEvent(event); + } + + override render() { + if (!this.options) { + return; + } + return html` + + `; + } +} diff --git a/src/webviews/apps/plus/home/components/overview.ts b/src/webviews/apps/plus/home/components/overview.ts index 75ef2c77ae16f..e2d182b21e3e5 100644 --- a/src/webviews/apps/plus/home/components/overview.ts +++ b/src/webviews/apps/plus/home/components/overview.ts @@ -2,11 +2,15 @@ import { consume } from '@lit/context'; import { SignalWatcher } from '@lit-labs/signals'; import { css, html, LitElement, nothing } from 'lit'; import { customElement } from 'lit/decorators.js'; -import type { GetOverviewResponse } from '../../../../home/protocol'; +import type { GetOverviewResponse, OverviewRecentThreshold } from '../../../../home/protocol'; +import { SetOverviewFilter } from '../../../../home/protocol'; +import { ipcContext } from '../../../shared/context'; +import type { HostIpc } from '../../../shared/ipc'; import { sectionHeadingStyles } from './branch-section'; import type { OverviewState } from './overviewState'; import { overviewStateContext } from './overviewState'; import '../../../shared/components/skeleton-loader'; +import './branch-threshold-filter'; type Overview = GetOverviewResponse; @@ -51,16 +55,42 @@ export class GlOverview extends SignalWatcher(LitElement) { `; } + @consume({ context: ipcContext }) + private readonly _ipc!: HostIpc; + + private onChangeRecentThresholdFilter(e: CustomEvent<{ threshold: OverviewRecentThreshold }>) { + if (!this._overviewState.filter.stale || !this._overviewState.filter.recent) { + return; + } + this._ipc.sendCommand(SetOverviewFilter, { + stale: this._overviewState.filter.stale, + recent: { ...this._overviewState.filter.recent, threshold: e.detail.threshold }, + }); + } + private renderComplete(overview: Overview) { if (overview == null) return nothing; - const { repository } = overview; return html`
+ > + +