Browse Source

Adds basic focus view component WIP

main
Keith Daulton 1 year ago
parent
commit
6294f565a6
6 changed files with 375 additions and 12 deletions
  1. +112
    -0
      src/webviews/apps/plus/focus/components/gk-issue-row.ts
  2. +125
    -0
      src/webviews/apps/plus/focus/components/gk-pull-request-row.ts
  3. +13
    -4
      src/webviews/apps/plus/focus/components/pull-request-row.ts
  4. +29
    -5
      src/webviews/apps/plus/focus/focus.html
  5. +7
    -0
      src/webviews/apps/plus/focus/focus.scss
  6. +89
    -3
      src/webviews/apps/plus/focus/focus.ts

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

@ -0,0 +1,112 @@
import { css, html, LitElement } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js';
import { when } from 'lit/directives/when.js';
import type { IssueMember, IssueShape } from '../../../../../git/models/issue';
import { elementBase } from '../../../shared/components/styles/lit/base.css';
import '@gitkraken/shared-web-components';
@customElement('gk-issue-row')
export class GkIssueRow extends LitElement {
static override styles = [
elementBase,
css`
:host {
--gk-avatar-background-color: var(--background-10);
--color-background: var(--vscode-editor-background);
display: block;
}
p {
margin: 0;
}
a {
color: var(--vscode-textLink-foreground);
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
`,
];
@property({ type: Number })
public rank?: number;
@property({ type: Object })
public issue?: IssueShape;
get lastUpdatedDate() {
return new Date(this.issue!.date);
}
get assignees() {
const assignees = this.issue?.assignees;
if (assignees == null) {
return [];
}
const author: IssueMember | undefined = this.issue!.author;
if (author != null) {
return assignees.filter(assignee => assignee.name !== author.name);
}
return assignees;
}
override render() {
if (!this.issue) return undefined;
return html`
<gk-focus-row>
<span slot="rank">${this.rank}</span>
<gk-focus-item>
<span slot="type"
><code-icon icon="${this.issue.closed === true ? 'pass' : 'issues'}"></code-icon
></span>
<p>
<strong>${this.issue.title} <a href="${this.issue.url}">#${this.issue.id}</a></strong>
<!-- &nbsp;
<gk-badge>pending suggestions</gk-badge> -->
</p>
<p>
<gk-tag>
<span slot="prefix"><code-icon icon="repo"></code-icon></span>
${this.issue.repository.repo}
</gk-tag>
<gk-tag>
<span slot="prefix"><code-icon icon="comment-discussion"></code-icon></span>
${this.issue.commentsCount}
</gk-tag>
<gk-tag>
<span slot="prefix"><code-icon icon="thumbsup"></code-icon></span>
${this.issue.thumbsUpCount}
</gk-tag>
</p>
<span slot="people">
<gk-avatar-group>
${when(
this.issue.author != null,
() => html`<gk-avatar src="${this.issue!.author.avatarUrl}"></gk-avatar>`,
)}
${when(
this.assignees.length > 0,
() => html`
${repeat(
this.assignees,
item => item.url,
(item, index) => html`<gk-avatar src="${item.avatarUrl}"></gk-avatar>`,
)}
`,
)}
</gk-avatar-group>
</span>
<span slot="date">
<gk-date-from date="${this.lastUpdatedDate}"></gk-date-from>
</span>
<nav slot="actions"></nav>
</gk-focus-item>
</gk-focus-row>
`;
}
}

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

@ -0,0 +1,125 @@
import { css, html, LitElement } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js';
import { when } from 'lit/directives/when.js';
import type { PullRequestMember, PullRequestShape } from '../../../../../git/models/pullRequest';
import { elementBase } from '../../../shared/components/styles/lit/base.css';
import '@gitkraken/shared-web-components';
@customElement('gk-pull-request-row')
export class GkPullRequestRow extends LitElement {
static override styles = [
elementBase,
css`
:host {
--gk-avatar-background-color: var(--background-10);
--color-background: var(--vscode-editor-background);
display: block;
}
p {
margin: 0;
}
a {
color: var(--vscode-textLink-foreground);
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
`,
];
@property({ type: Number })
public rank?: number;
@property({ type: Object })
public pullRequest?: PullRequestShape;
@property({ type: Boolean })
public isCurrentBranch = false;
@property({ type: Boolean })
public isCurrentWorktree = false;
@property({ type: Boolean })
public hasWorktree = false;
@property({ type: Boolean })
public hasLocalBranch = false;
get lastUpdatedDate() {
return new Date(this.pullRequest!.date);
}
get assignees() {
const assignees = this.pullRequest?.assignees;
if (assignees == null) {
return [];
}
const author: PullRequestMember | undefined = this.pullRequest!.author;
if (author != null) {
return assignees.filter(assignee => assignee.name !== author.name);
}
return assignees;
}
override render() {
if (!this.pullRequest) return undefined;
return html`
<gk-focus-row>
<span slot="rank">${this.rank}</span>
<gk-focus-item>
<span slot="type"><code-icon icon="git-pull-request"></code-icon></span>
<p>
<strong
>${this.pullRequest.title}
<a href="${this.pullRequest.url}">#${this.pullRequest.id}</a></strong
>
<!-- &nbsp;
<gk-badge>pending suggestions</gk-badge> -->
</p>
<p>
<gk-tag>
<span slot="prefix"><code-icon icon="source-control"></code-icon></span>
${this.pullRequest.refs?.base.branch}
</gk-tag>
<gk-tag>
<span slot="prefix"><code-icon icon="repo"></code-icon></span>
${this.pullRequest.refs?.base.repo}
</gk-tag>
<gk-additions-deletions>
<span slot="additions">${this.pullRequest.additions}</span>
<span slot="deletions">${this.pullRequest.deletions}</span>
</gk-additions-deletions>
</p>
<span slot="people">
<gk-avatar-group>
${when(
this.pullRequest.author != null,
() => html`<gk-avatar src="${this.pullRequest!.author.avatarUrl}"></gk-avatar>`,
)}
${when(
this.assignees.length > 0,
() => html`
${repeat(
this.assignees,
item => item.url,
(item, index) => html`<gk-avatar src="${item.avatarUrl}"></gk-avatar>`,
)}
`,
)}
</gk-avatar-group>
</span>
<span slot="date">
<gk-date-from date="${this.lastUpdatedDate}"></gk-date-from>
</span>
<nav slot="actions"><gkc-button variant="ghost">Checkout branch</gkc-button></nav>
</gk-focus-item>
</gk-focus-row>
`;
}
}

+ 13
- 4
src/webviews/apps/plus/focus/components/pull-request-row.ts View File

@ -14,11 +14,11 @@ const template = html`
<template role="row">
<table-cell class="status">
${when(
x => x.pullRequest!.isDraft === true,
x => x.pullRequest?.isDraft === true,
html`<code-icon icon="git-pull-request-draft" title="draft"></code-icon>`,
)}
${when(
x => x.pullRequest!.isDraft !== true,
x => x.pullRequest?.isDraft !== true,
html`<code-icon class="pull-request-draft" icon="git-pull-request" title="open"></code-icon>`,
)}
${when(
@ -295,27 +295,36 @@ export class PullRequestRow extends FASTElement {
@volatile
get lastUpdatedDate() {
return new Date(this.pullRequest!.date);
return this.pullRequest ? new Date(this.pullRequest.date) : undefined;
}
@volatile
get lastUpdatedState() {
if (!this.lastUpdatedDate) {
return;
}
return fromDateRange(this.lastUpdatedDate);
}
@volatile
get lastUpdated() {
if (!this.lastUpdatedDate) {
return;
}
return fromNow(this.lastUpdatedDate, true);
}
@volatile
get lastUpdatedLabel() {
if (!this.lastUpdatedDate) {
return;
}
return fromNow(this.lastUpdatedDate);
}
@volatile
get lastUpdatedClass() {
switch (this.lastUpdatedState.status) {
switch (this.lastUpdatedState?.status) {
case 'danger':
return 'indicator-error';
case 'warning':

+ 29
- 5
src/webviews/apps/plus/focus/focus.html View File

@ -57,6 +57,33 @@
<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>
@ -80,8 +107,6 @@
<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-author" header="column" pinned>Author</table-cell>
<table-cell class="data-assigned" header="column" pinned>Assigned</table-cell> -->
<table-cell class="data-participants" header="column" pinned title="Participants">
<code-icon icon="organization"></code-icon>
</table-cell>
@ -97,6 +122,7 @@
></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
@ -129,8 +155,6 @@
<code-icon icon="gl-clock"></code-icon>
</table-cell>
<table-cell header="column" pinned>Title</table-cell>
<!-- <table-cell class="data-author" header="column" pinned>Author</table-cell>
<table-cell class="data-assigned" header="column" pinned>Assigned</table-cell> -->
<table-cell class="data-participants" header="column" pinned title="Participants">
<code-icon icon="organization"></code-icon>
</table-cell>
@ -154,7 +178,7 @@
<span class="alert__content">No issues found</span>
</div>
</div>
</section>
</section> -->
</main>
</div>
</div>

+ 7
- 0
src/webviews/apps/plus/focus/focus.scss View File

@ -22,6 +22,8 @@ body {
--table-text: var(--color-foreground--65);
--table-pinned-background: var(--color-background);
--layout-gutter-outer: 20px;
--gk-color-primary: var(--vscode-errorForeground);
}
.vscode-high-contrast,
@ -259,6 +261,11 @@ h3 {
}
}
gk-focus-view::part(base) {
font-size: 1.5rem;
font-weight: bold;
}
.app {
display: flex;
flex-direction: column;

+ 89
- 3
src/webviews/apps/plus/focus/focus.ts View File

@ -1,3 +1,4 @@
// import { FocusView } from '@gitkraken/shared-web-components';
import type { PullRequestShape } from '../../../../git/models/pullRequest';
import type { State } from '../../../../plus/webviews/focus/protocol';
import {
@ -11,6 +12,8 @@ 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 { GkIssueRow } from './components/gk-issue-row';
import type { GkPullRequestRow } from './components/gk-pull-request-row';
import type { IssueRow } from './components/issue-row';
import type { PullRequestRow } from './components/pull-request-row';
import '../../shared/components/button';
@ -24,13 +27,17 @@ import '../../shared/components/table/table-cell';
import '../../shared/components/feature-gate-badge';
import './components/issue-row';
import './components/pull-request-row';
import './components/gk-pull-request-row';
import './components/gk-issue-row';
import './focus.scss';
import '@gitkraken/shared-web-components';
export class FocusApp extends App<State> {
constructor() {
super('FocusApp');
}
private _focusFilter?: string;
private _prFilter?: string;
private _issueFilter?: string;
@ -54,6 +61,12 @@ export class FocusApp extends App {
this.renderIssues();
}),
),
DOM.on('#focus-filter [data-tab]', 'click', e =>
this.onSelectTab(e, val => {
this._focusFilter = val;
this.renderIssues();
}),
),
DOM.on<PullRequestRow, PullRequestShape>('pull-request-row', 'open-worktree', (e, target: HTMLElement) =>
this.onOpenWorktree(e, target),
),
@ -106,13 +119,65 @@ export class FocusApp extends App {
const $badge = document.getElementById('subscription-gate-badge')! as FeatureGateBadge;
$badge.subscription = this.state.access.subscription.current;
this.renderPullRequests();
this.renderIssues();
// this.renderPullRequests();
// this.renderIssues();
this.renderFocusList();
}
renderFocusList() {
const tableEl = document.getElementById('list-focus-items');
if (tableEl == null) return;
tableEl.innerHTML = '';
const noneEl = document.getElementById('no-focus-items')!;
const loadingEl = document.getElementById('loading-focus-items')!;
if (this.state.access.allowed !== true || (this.state.pullRequests == null && this.state.issues == null)) {
noneEl.setAttribute('hidden', 'true');
loadingEl.removeAttribute('hidden');
} else if (
(this.state.pullRequests == null || this.state.pullRequests.length === 0) &&
(this.state.issues == null || this.state.issues.length === 0)
) {
noneEl.removeAttribute('hidden');
loadingEl.setAttribute('hidden', 'true');
} else {
noneEl.setAttribute('hidden', 'true');
loadingEl.setAttribute('hidden', 'true');
let rank = 0;
this.state.pullRequests?.forEach(
({ pullRequest, reasons, isCurrentBranch, isCurrentWorktree, hasWorktree, hasLocalBranch }, i) => {
if (this._focusFilter == null || this._focusFilter === '' || reasons.includes(this._focusFilter)) {
const rowEl = document.createElement('gk-pull-request-row') as GkPullRequestRow;
rowEl.pullRequest = pullRequest;
rowEl.rank = ++rank;
// rowEl2.reasons = reasons;
rowEl.isCurrentBranch = isCurrentBranch;
rowEl.isCurrentWorktree = isCurrentWorktree;
rowEl.hasWorktree = hasWorktree;
rowEl.hasLocalBranch = hasLocalBranch;
tableEl.append(rowEl);
}
},
);
this.state.issues?.forEach(({ issue, reasons }) => {
if (this._focusFilter == null || this._focusFilter === '' || reasons.includes(this._focusFilter)) {
const rowEl = document.createElement('gk-issue-row') as GkIssueRow;
rowEl.rank = ++rank;
rowEl.issue = issue;
tableEl.append(rowEl);
}
});
}
}
renderPullRequests() {
const tableEl = document.getElementById('pull-requests');
if (tableEl == null) return;
const tableEl2 = document.getElementById('share-pull-requests')!;
const rowEls = tableEl.querySelectorAll('pull-request-row');
rowEls.forEach(el => el.remove());
@ -128,8 +193,9 @@ export class FocusApp extends App {
} else {
noneEl.setAttribute('hidden', 'true');
loadingEl.setAttribute('hidden', 'true');
tableEl2.innerHTML = '';
this.state.pullRequests.forEach(
({ pullRequest, reasons, isCurrentBranch, isCurrentWorktree, hasWorktree, hasLocalBranch }) => {
({ pullRequest, reasons, isCurrentBranch, isCurrentWorktree, hasWorktree, hasLocalBranch }, i) => {
if (this._prFilter == null || this._prFilter === '' || reasons.includes(this._prFilter)) {
const rowEl = document.createElement('pull-request-row') as PullRequestRow;
rowEl.pullRequest = pullRequest;
@ -140,6 +206,17 @@ export class FocusApp extends App {
rowEl.hasLocalBranch = hasLocalBranch;
tableEl.append(rowEl);
const rowEl2 = document.createElement('gk-pull-request-row') as GkPullRequestRow;
rowEl2.pullRequest = pullRequest;
rowEl2.rank = i + 1;
// rowEl2.reasons = reasons;
rowEl2.isCurrentBranch = isCurrentBranch;
rowEl2.isCurrentWorktree = isCurrentWorktree;
rowEl2.hasWorktree = hasWorktree;
rowEl2.hasLocalBranch = hasLocalBranch;
tableEl2.append(rowEl2);
}
},
);
@ -151,6 +228,7 @@ export class FocusApp extends App {
const rowEls = tableEl.querySelectorAll('issue-row');
rowEls.forEach(el => el.remove());
const tableEl2 = document.getElementById('share-pull-requests')!;
const noneEl = document.getElementById('no-issues')!;
const loadingEl = document.getElementById('loading-issues')!;
@ -170,6 +248,11 @@ export class FocusApp extends App {
rowEl.reasons = reasons;
tableEl.append(rowEl);
const rowEl2 = document.createElement('gk-issue-row') as GkIssueRow;
rowEl2.issue = issue;
tableEl2.append(rowEl2);
}
});
}
@ -191,4 +274,7 @@ export class FocusApp extends App {
}
}
// customElements.define(FocusView.tag, FocusView);
// FocusView.define();
new FocusApp();

||||||
x
 
000:0
Loading…
Cancel
Save