Browse Source

Updates focus view v2 more WIP

main
Keith Daulton 1 year ago
parent
commit
8df4af2913
6 changed files with 342 additions and 183 deletions
  1. +202
    -0
      src/webviews/apps/plus/focus/components/focus-app.ts
  2. +37
    -1
      src/webviews/apps/plus/focus/components/gk-issue-row.ts
  3. +57
    -2
      src/webviews/apps/plus/focus/components/gk-pull-request-row.ts
  4. +1
    -161
      src/webviews/apps/plus/focus/focus.html
  5. +23
    -5
      src/webviews/apps/plus/focus/focus.scss
  6. +22
    -14
      src/webviews/apps/plus/focus/focus.ts

+ 202
- 0
src/webviews/apps/plus/focus/components/focus-app.ts View File

@ -0,0 +1,202 @@
import { html, LitElement } from 'lit';
import { customElement, property, query, state } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js';
import { when } from 'lit/directives/when.js';
import type { State } from '../../../../../plus/webviews/focus/protocol';
import type { FeatureGate } from '../../../shared/components/feature-gate';
import type { FeatureGateBadge } from '../../../shared/components/feature-gate-badge';
@customElement('gl-focus-app')
export class GlFocusApp extends LitElement {
@query('#subscription-gate', true)
private subscriptionEl!: FeatureGate;
@query('#connection-gate', true)
private connectionEl!: FeatureGate;
@query('#subscription-gate-badge', true)
private subScriptionBadgeEl!: FeatureGateBadge;
@state()
private focusFilter?: string;
@state()
private loading = true;
@property({ type: Object })
state?: State;
get subscriptionState() {
return this.state?.access.subscription.current;
}
get showSubscriptionGate() {
return this.state?.access.allowed === false;
}
get showConnectionGate() {
return this.state?.access.allowed === true && !(this.state?.repos?.some(r => r.isConnected) ?? false);
}
get filteredItems() {
const items: { isPullrequest: boolean; rank: number; state: Record<string, any> }[] = [];
let rank = 0;
this.state?.pullRequests?.forEach(
({ pullRequest, reasons, isCurrentBranch, isCurrentWorktree, hasWorktree, hasLocalBranch }, i) => {
if (this.focusFilter == null || this.focusFilter === '' || reasons.includes(this.focusFilter)) {
items.push({
isPullrequest: true,
state: {
pullRequest: pullRequest,
// reasons: reasons,
isCurrentBranch: isCurrentBranch,
isCurrentWorktree: isCurrentWorktree,
hasWorktree: hasWorktree,
hasLocalBranch: hasLocalBranch,
},
rank: ++rank,
});
}
},
);
this.state?.issues?.forEach(({ issue, reasons }) => {
if (this.focusFilter == null || this.focusFilter === '' || reasons.includes(this.focusFilter)) {
items.push({
isPullrequest: false,
rank: ++rank,
state: {
issue: issue,
},
});
}
});
return items;
}
override render() {
if (this.state == null) {
return undefined;
}
return html`
<div class="app">
<header class="app__header">
<span class="badge">Preview</span>
<gk-feature-gate-badge
.subscription=${this.subscriptionState}
id="subscription-gate-badge"
></gk-feature-gate-badge>
<gk-button
appearance="toolbar"
href="https://github.com/gitkraken/vscode-gitlens/discussions/2535"
title="Focus View Feedback"
aria-label="Focus View Feedback"
><code-icon icon="feedback"></code-icon
></gk-button>
</header>
<div class="app__content" id="content">
<gk-feature-gate .state=${this.subscriptionState?.state} id="subscription-gate" class="scrollable"
><p slot="feature">
Brings all of your GitHub pull requests and issues into a unified actionable view to help to
you more easily juggle work in progress, pending work, reviews, and more. Quickly see if
anything requires your attention while keeping you focused.
</p></gk-feature-gate
>
<gk-feature-gate .visible=${this.showConnectionGate} id="connection-gate" class="scrollable">
<h3>No GitHub remotes are connected</h3>
<p>
This enables access to Pull Requests and Issues in the Focus View as well as provide
additional information inside hovers and the Commit Details view, such as auto-linked issues
and pull requests and avatars.
</p>
<gk-button appearance="alert" href="command:gitlens.connectRemoteProvider"
>Connect to GitHub</gk-button
>
</gk-feature-gate>
<main class="app__main">
<section class="focus-section app__section">
<header class="focus-section__header">
<div class="focus-section__header-group">
<nav class="tab-filter" id="filter-focus-items">
<button class="tab-filter__tab is-active" type="button" data-tab="">All</button>
<button class="tab-filter__tab" type="button" data-tab="authored">
Opened by Me
</button>
<button class="tab-filter__tab" type="button" data-tab="assigned">
Assigned to Me
</button>
<button class="tab-filter__tab" type="button" data-tab="review-requested">
Needs my Review
</button>
<button class="tab-filter__tab" type="button" data-tab="mentioned">
Mentions Me
</button>
</nav>
</div>
<div class="focus-section__header-group">
<gk-input
class="search"
label="Search field"
label-visibility="sr-only"
placeholder="Search"
>
<code-icon slot="prefix" icon="search"></code-icon>
</gk-input>
</div>
</header>
<div class="focus-section__content">
<gk-focus-container id="list-focus-items">
${when(
this.filteredItems.length > 0,
() => html`
${repeat(
this.filteredItems,
item => item.rank,
({ isPullrequest, rank, state }) =>
when(
isPullrequest,
() =>
html`<gk-pull-request-row
.rank=${rank}
.pullRequest=${state.pullRequest}
></gk-pull-request-row>`,
() =>
html`<gk-issue-row
.rank=${rank}
.issue=${state.issue}
></gk-issue-row>`,
),
)}
`,
() => html`
<div class="alert">
<span class="alert__content">None found</span>
</div>
`,
)}
</gk-focus-container>
<div class="alert" id="loading-focus-items">
<span class="alert__content"
><code-icon modifier="spin" icon="loading"></code-icon> Loading</span
>
</div>
<div class="alert" id="no-focus-items">
<span class="alert__content">None found</span>
</div>
</div>
</section>
</main>
</div>
</div>
`;
}
protected override createRenderRoot() {
return this;
}
}

+ 37
- 1
src/webviews/apps/plus/focus/components/gk-issue-row.ts View File

@ -31,6 +31,38 @@ export class GkIssueRow extends LitElement {
a:hover {
text-decoration: underline;
}
.actions {
}
.actions a {
box-sizing: border-box;
display: inline-flex;
justify-content: center;
align-items: center;
width: 3.2rem;
height: 3.2rem;
border-radius: 0.5rem;
color: inherit;
padding: 0.2rem;
vertical-align: text-bottom;
text-decoration: none;
cursor: pointer;
}
.actions a:focus {
outline: 1px solid var(--vscode-focusBorder);
outline-offset: -1px;
}
.actions a:hover {
background-color: var(--vscode-toolbar-hoverBackground);
}
.actions a:active {
background-color: var(--vscode-toolbar-activeBackground);
}
.actions a code-icon {
font-size: 1.6rem;
}
`,
];
@ -119,7 +151,11 @@ export class GkIssueRow extends LitElement {
<span slot="date">
<gk-date-from class="${this.dateStyle}" date="${this.lastUpdatedDate}"></gk-date-from>
</span>
<nav slot="actions"></nav>
<nav slot="actions" class="actions">
<a href="${this.issue.url}" title="Open issue on remote"
><code-icon icon="globe"></code-icon
></a>
</nav>
</gk-focus-item>
</gk-focus-row>
`;

+ 57
- 2
src/webviews/apps/plus/focus/components/gk-pull-request-row.ts View File

@ -1,4 +1,4 @@
import { css, html, LitElement } from 'lit';
import { css, html, LitElement, nothing } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js';
import { when } from 'lit/directives/when.js';
@ -31,6 +31,42 @@ export class GkPullRequestRow extends LitElement {
a:hover {
text-decoration: underline;
}
.actions {
}
.actions a {
box-sizing: border-box;
display: inline-flex;
justify-content: center;
align-items: center;
width: 3.2rem;
height: 3.2rem;
border-radius: 0.5rem;
color: inherit;
padding: 0.2rem;
vertical-align: text-bottom;
text-decoration: none;
cursor: pointer;
}
.actions a:focus {
outline: 1px solid var(--vscode-focusBorder);
outline-offset: -1px;
}
.actions a:hover {
background-color: var(--vscode-toolbar-hoverBackground);
}
.actions a:active {
background-color: var(--vscode-toolbar-activeBackground);
}
.actions a[tabindex='-1'] {
opacity: 0.5;
cursor: default;
}
.actions a code-icon {
font-size: 1.6rem;
}
`,
];
@ -132,9 +168,28 @@ export class GkPullRequestRow extends LitElement {
<span slot="date">
<gk-date-from class="${this.dateStyle}" date="${this.lastUpdatedDate}"></gk-date-from>
</span>
<nav slot="actions"><gk-button variant="ghost">Checkout branch</gk-button></nav>
<nav slot="actions" class="actions">
<a
href="#"
tabindex="${this.isCurrentWorktree || this.isCurrentBranch ? -1 : nothing}"
title="${this.isCurrentWorktree ? 'Already on this workree' : 'Open Worktree...'}"
aria-label="${this.isCurrentWorktree ? 'Already on this workree' : 'Open Worktree...'}"
@click="${this.onOpenWorktreeClick}"
><code-icon icon="gl-worktrees-view"></code-icon></a
><a
href="#"
tabindex="${this.hasWorktree || this.isCurrentBranch ? -1 : nothing}"
title="${this.isCurrentBranch ? 'Already on this branch' : 'Switch to Branch...'}"
aria-label="${this.isCurrentBranch ? 'Already on this branch' : 'Switch to Branch...'}"
@click="${this.onSwitchBranchClick}"
><code-icon icon="gl-switch"></code-icon
></a>
</nav>
</gk-focus-item>
</gk-focus-row>
`;
}
public onOpenWorktreeClick(e: MouseEvent) {}
public onSwitchBranchClick(e: MouseEvent) {}
}

+ 1
- 161
src/webviews/apps/plus/focus/focus.html View File

@ -21,167 +21,7 @@
</head>
<body class="preload" data-placement="#{placement}">
<div class="app">
<header class="app__header" id="header">
<span class="badge">Preview</span>
<gk-feature-gate-badge id="subscription-gate-badge"></gk-feature-gate-badge>
<gk-button
appearance="toolbar"
href="https://github.com/gitkraken/vscode-gitlens/discussions/2535"
title="Focus View Feedback"
aria-label="Focus View Feedback"
><code-icon icon="feedback"></code-icon
></gk-button>
</header>
<div class="app__content" id="content">
<gk-feature-gate id="subscription-gate" class="scrollable"
><p slot="feature">
Brings all of your GitHub pull requests and issues into a unified actionable view to help to you
more easily juggle work in progress, pending work, reviews, and more. Quickly see if anything
requires your attention while keeping you focused.
</p></gk-feature-gate
>
<gk-feature-gate id="connection-gate" class="scrollable" visible="false">
<h3>No GitHub remotes are connected</h3>
<p>
This enables access to Pull Requests and Issues in the Focus View as well as provide additional
information inside hovers and the Commit Details view, such as auto-linked issues and pull
requests and avatars.
</p>
<gk-button appearance="alert" href="command:gitlens.connectRemoteProvider"
>Connect to GitHub</gk-button
>
</gk-feature-gate>
<main class="app__main">
<section class="focus-section app__section">
<header class="focus-section__header">
<h2>Focus View</h2>
<nav class="tab-filter" id="filter-focus-items">
<button class="tab-filter__tab is-active" type="button" data-tab="">All</button>
<button class="tab-filter__tab" type="button" data-tab="authored">Opened by Me</button>
<button class="tab-filter__tab" type="button" data-tab="assigned">
Assigned to Me
</button>
<button class="tab-filter__tab" type="button" data-tab="review-requested">
Needs my Review
</button>
<button class="tab-filter__tab" type="button" data-tab="mentioned">Mentions Me</button>
</nav>
</header>
<div class="focus-section__content">
<gk-focus-container id="list-focus-items"></gk-focus-container>
<div class="alert" id="loading-focus-items">
<span class="alert__content"
><code-icon modifier="spin" icon="loading"></code-icon> Loading</span
>
</div>
<div class="alert" id="no-focus-items">
<span class="alert__content">None found</span>
</div>
</div>
</section>
<!-- <section class="focus-section app__section">
<header class="focus-section__header">
<h2>My Pull Requests</h2>
<nav class="tab-filter" id="pr-filter">
<button class="tab-filter__tab is-active" type="button" data-tab="">All</button>
<button class="tab-filter__tab" type="button" data-tab="authored">Opened by Me</button>
<button class="tab-filter__tab" type="button" data-tab="assigned">
Assigned to Me
</button>
<button class="tab-filter__tab" type="button" data-tab="review-requested">
Needs my Review
</button>
<button class="tab-filter__tab" type="button" data-tab="mentioned">Mentions Me</button>
</nav>
</header>
<div class="focus-section__content">
<table-container id="pull-requests">
<table-row slot="head">
<table-cell class="data-status" header="column" pinned title="PR status"
><code-icon icon="git-pull-request"></code-icon
></table-cell>
<table-cell class="data-time" header="column" pinned title="Last updated">
<code-icon icon="gl-clock"></code-icon>
</table-cell>
<table-cell class="data-body" header="column" pinned>Pull Request</table-cell>
<table-cell class="data-participants" header="column" pinned title="Participants">
<code-icon icon="organization"></code-icon>
</table-cell>
<table-cell class="data-comments" header="column" pinned title="Comments">
<code-icon icon="comment-discussion"></code-icon>
</table-cell>
<table-cell class="data-stats" header="column" pinned title="Change stats">
<code-icon icon="add"></code-icon>
<code-icon icon="dash"></code-icon>
</table-cell>
<table-cell class="data-actions" header="column" pinned
><code-icon icon="blank" title="actions"></code-icon
></table-cell>
</table-row>
</table-container>
<gk-focus-container id="share-pull-requests"></gk-focus-container>
<div class="alert" id="loading-pull-requests">
<span class="alert__content"
><code-icon modifier="spin" icon="loading"></code-icon> Loading</span
>
</div>
<div class="alert" id="no-pull-requests">
<span class="alert__content">No pull requests found</span>
</div>
</div>
</section>
<section class="focus-section app__section">
<header class="focus-section__header">
<h2>My Issues</h2>
<nav class="tab-filter" id="issue-filter">
<button class="tab-filter__tab is-active" type="button" data-tab="">All</button>
<button class="tab-filter__tab" type="button" data-tab="authored">Opened by Me</button>
<button class="tab-filter__tab" type="button" data-tab="assigned">
Assigned to Me
</button>
<button class="tab-filter__tab" type="button" data-tab="mentioned">Mentions Me</button>
</nav>
</header>
<div class="focus-section__content">
<table-container id="issues">
<table-row slot="head">
<table-cell class="data-status" header="column" pinned title="PR status">
<code-icon icon="issues"></code-icon>
</table-cell>
<table-cell class="data-time" header="column" pinned title="Last updated">
<code-icon icon="gl-clock"></code-icon>
</table-cell>
<table-cell header="column" pinned>Title</table-cell>
<table-cell class="data-participants" header="column" pinned title="Participants">
<code-icon icon="organization"></code-icon>
</table-cell>
<table-cell class="data-comments" header="column" pinned title="Comments">
<code-icon icon="comment-discussion"></code-icon>
</table-cell>
<table-cell class="data-checks" header="column" pinned title="Thumbs up">
<code-icon icon="thumbsup"></code-icon>
</table-cell>
<table-cell class="data-actions" header="column" pinned
><code-icon icon="blank" title="actions"></code-icon
></table-cell>
</table-row>
</table-container>
<div class="alert" id="loading-issues">
<span class="alert__content"
><code-icon modifier="spin" icon="loading"></code-icon> Loading</span
>
</div>
<div class="alert" id="no-issues" hidden>
<span class="alert__content">No issues found</span>
</div>
</div>
</section> -->
</main>
</div>
</div>
<gl-focus-app id="app"></gl-focus-app>
#{endOfBody}
</body>
</html>

+ 23
- 5
src/webviews/apps/plus/focus/focus.scss View File

@ -22,6 +22,9 @@ body {
--table-text: var(--color-foreground--65);
--table-pinned-background: var(--color-background);
--layout-gutter-outer: 20px;
--gk-input-background-color: var(--vscode-input-background);
--gk-input-border-color: var(--vscode-input-border);
--gk-input-color: var(--vscode-input-foreground);
}
.vscode-high-contrast,
@ -210,20 +213,27 @@ h3 {
.focus-section {
display: flex;
flex-direction: column;
gap: 0.8rem;
gap: 1.2rem;
&__header {
flex: none;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 0.4rem 0;
flex-direction: column;
gap: 1.6rem;
padding-top: 1.2rem;
h2 {
margin: 0;
font-size: 1.5rem;
}
&-group {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
gap: 0.4rem;
}
}
&__content {
@ -233,6 +243,14 @@ h3 {
}
}
.search {
flex: 1;
code-icon {
margin-right: 0.8rem;
}
}
.feedback-button {
position: relative;
appearance: none;

+ 22
- 14
src/webviews/apps/plus/focus/focus.ts View File

@ -12,6 +12,7 @@ import { App } from '../../shared/appBase';
import type { FeatureGate } from '../../shared/components/feature-gate';
import type { FeatureGateBadge } from '../../shared/components/feature-gate-badge';
import { DOM } from '../../shared/dom';
import type { GlFocusApp } from './components/focus-app';
import type { GkIssueRow } from './components/gk-issue-row';
import type { GkPullRequestRow } from './components/gk-pull-request-row';
// import type { IssueRow } from './components/issue-row';
@ -29,6 +30,7 @@ import '../../shared/components/feature-gate-badge';
// import './components/pull-request-row';
import './components/gk-pull-request-row';
import './components/gk-issue-row';
import './components/focus-app';
import './focus.scss';
import '@gitkraken/shared-web-components';
@ -43,6 +45,8 @@ export class FocusApp extends App {
override onInitialize() {
this.renderContent();
this.attachState();
}
protected override onBind() {
@ -78,6 +82,10 @@ export class FocusApp extends App {
return disposables;
}
attachState() {
(document.getElementById('app') as GlFocusApp)!.state = this.state;
}
private onSwitchBranch(e: CustomEvent<PullRequestShape>, _target: HTMLElement) {
if (e.detail?.refs?.head == null) return;
this.sendCommand(SwitchToBranchCommandType, { pullRequest: e.detail });
@ -104,20 +112,20 @@ export class FocusApp extends App {
}
renderContent() {
let $gate = document.getElementById('subscription-gate')! as FeatureGate;
if ($gate != null) {
$gate.state = this.state.access.subscription.current.state;
$gate.visible = this.state.access.allowed !== true;
}
$gate = document.getElementById('connection-gate')! as FeatureGate;
if ($gate != null) {
$gate.visible =
this.state.access.allowed === true && !(this.state.repos?.some(r => r.isConnected) ?? false);
}
const $badge = document.getElementById('subscription-gate-badge')! as FeatureGateBadge;
$badge.subscription = this.state.access.subscription.current;
// let $gate = document.getElementById('subscription-gate')! as FeatureGate;
// if ($gate != null) {
// $gate.state = this.state.access.subscription.current.state;
// $gate.visible = this.state.access.allowed !== true;
// }
// $gate = document.getElementById('connection-gate')! as FeatureGate;
// if ($gate != null) {
// $gate.visible =
// this.state.access.allowed === true && !(this.state.repos?.some(r => r.isConnected) ?? false);
// }
// const $badge = document.getElementById('subscription-gate-badge')! as FeatureGateBadge;
// $badge.subscription = this.state.access.subscription.current;
// this.renderPullRequests();
// this.renderIssues();

Loading…
Cancel
Save