Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP - Revised My Docs screen #307

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion web/app/components/doc/row.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
@route="authenticated.document"
@model="{{@docID}}"
@query={{hash draft=@isDraft}}
class="flex space-x-4 items-start"
class="flex items-start space-x-4"
>
<Doc::Thumbnail @status={{@status}} @product={{@productArea}} />
<div>
Expand Down
7 changes: 2 additions & 5 deletions web/app/components/header/index.hbs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
<header class="bg-color-page-faint border-b border-b-color-border-faint mb-7">
<header class="mb-7 border-b border-b-color-border-faint bg-color-page-faint">
<Header::Nav />
</header>

<Header::Toolbar
@facets={{@facets}}
@sortControlIsHidden={{@sortControlIsHidden}}
/>
<Header::Toolbar @facets={{@facets}} />
1 change: 0 additions & 1 deletion web/app/components/header/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { FacetDropdownGroups } from "hermes/types/facets";
interface HeaderComponentSignature {
Args: {
facets: FacetDropdownGroups;
sortControlIsHidden?: boolean;
};
}

Expand Down
11 changes: 1 addition & 10 deletions web/app/components/header/nav.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,15 @@
@current-when="authenticated.all"
@query={{this.defaultBrowseScreenQueryParams}}
>
All Docs
Explore
</LinkTo>
<LinkTo
data-test-nav-link="my"
@route="authenticated.my"
@current-when="authenticated.my"
@query={{this.defaultBrowseScreenQueryParams}}
>
My Docs
</LinkTo>
<LinkTo
data-test-nav-link="drafts"
@route="authenticated.drafts"
@current-when="authenticated.drafts"
@query={{this.defaultBrowseScreenQueryParams}}
>
My Drafts
</LinkTo>
</div>

<Header::Search class="global-search" />
Expand Down
27 changes: 27 additions & 0 deletions web/app/components/maybe-sortable-table-header.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{{#if this.isReadOnly}}
{{yield}}
{{else}}
{{#if @changeSort}}
<Action
class="sortable-table-header {{if this.isActive 'active'}}"
{{on "click" this.changeSort}}
...attributes
>
<div class="sort-icon">
<FlightIcon @name={{this.iconName}} />
</div>
{{yield}}
</Action>
{{else}}
<LinkTo
@route={{this.currentRoute}}
@query={{@queryParam}}
class="sortable-table-header {{if this.isActive 'active'}}"
>
<div class="sort-icon">
<FlightIcon @name={{this.iconName}} />
</div>
{{yield}}
</LinkTo>
{{/if}}
{{/if}}
80 changes: 80 additions & 0 deletions web/app/components/maybe-sortable-table-header.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import Component from "@glimmer/component";
import { action } from "@ember/object";
import { SortAttribute, SortDirection } from "./my-docs";
import { assert } from "@ember/debug";
import { inject as service } from "@ember/service";
import RouterService from "@ember/routing/router-service";

interface MaybeSortableTableHeaderComponentSignature {
Element: HTMLButtonElement;
Args: {
sortAttribute: `${SortAttribute}`;
sortDirection: SortDirection;
attribute: `${SortAttribute}`;
changeSort?: (
attribute: SortAttribute,
defaultSortDirection?: SortDirection
) => void;
defaultSortDirection?: `${SortDirection}`;
queryParam?: Record<string, unknown>;
};
Blocks: {
default: [];
};
}

export default class MaybeSortableTableHeaderComponent extends Component<MaybeSortableTableHeaderComponentSignature> {
@service declare router: RouterService;

protected get currentRoute() {
return this.router.currentRouteName;
}

protected get iconName() {
if (this.args.sortAttribute === this.args.attribute) {
if (this.args.sortDirection === SortDirection.Asc) {
return "arrow-up";
} else {
return "arrow-down";
}
} else {
return "swap-vertical";
}
}

private get sortDirection() {
if (!this.isActive) {
return (
(this.args.defaultSortDirection as SortDirection) ?? SortDirection.Asc
);
}
}

protected get isReadOnly() {
// CreatedTime is always interactive
if (this.args.attribute === SortAttribute.CreatedTime) {
return false;
}

// Unless we're on the /my route, all other headers are read-only
return !this.router.currentRouteName.startsWith("authenticated.my");
}

protected get isActive() {
return this.args.sortAttribute === this.args.attribute;
}

@action protected changeSort() {
assert("this.args.changeSort must exists", this.args.changeSort);
this.args.changeSort(
this.args.attribute as SortAttribute,
this.sortDirection
);
}
}

declare module "@glint/environment-ember-loose/registry" {
export default interface Registry {
MaybeSortableTableHeader: typeof MaybeSortableTableHeaderComponent;
}
}
68 changes: 68 additions & 0 deletions web/app/components/my-docs/index.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<Header />

<div class="x-container">
<div class="mb-4 flex w-full items-center justify-between">

<div class="relative flex items-center">
<LinkTo @route="authenticated.my">
<Person::Avatar
@imgURL={{this.authenticatedUser.info.picture}}
@email={{this.authenticatedUser.info.name}}
@size="large"
class="mr-5 -ml-1"
/>
</LinkTo>
<div>
<h1 class="mb-0 text-display-300">
{{this.authenticatedUser.info.name}}
</h1>
<p class="text-body-200 text-color-foreground-faint">
{{this.authenticatedUser.info.email}}
</p>
</div>
</div>
{{! make this more like the product overview screen }}

<div class="secondary-nav">
<LinkTo
{{on "click" this.resetLocalProperties}}
@route="authenticated.my"
@current-when="authenticated.my.index"
>
All Docs
</LinkTo>
<LinkTo
{{on "click" this.resetLocalProperties}}
@route="authenticated.my.in-review"
@current-when="authenticated.my.in-review"
>
In Review
</LinkTo>
<LinkTo
{{on "click" this.resetLocalProperties}}
@route="authenticated.my.approved"
@current-when="authenticated.my.approved"
>
Approved
</LinkTo>
<LinkTo
{{on "click" this.resetLocalProperties}}
@route="authenticated.my.drafts"
@current-when="authenticated.my.drafts"
>
Drafts
</LinkTo>
</div>
</div>
</div>

{{#if this.docsToShow}}
<RowResults
@changeSort={{this.changeSort}}
@sortAttribute={{this.sortAttribute}}
@sortDirection={{this.sortDirection}}
@docs={{this.sortedDocs}}
@isCollapsed={{this.isCollapsed}}
@toggleCollapsed={{this.toggleCollapsed}}
/>
{{/if}}
153 changes: 153 additions & 0 deletions web/app/components/my-docs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import { assert } from "@ember/debug";
import { action } from "@ember/object";
import { sort } from "@ember/object/computed";
import RouterService from "@ember/routing/router-service";
import { inject as service } from "@ember/service";
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import AuthenticatedUserService from "hermes/services/authenticated-user";
import { HermesDocument } from "hermes/types/document";

interface MyDocsIndexComponentSignature {
Element: null;
Args: {
allDocs: HermesDocument[];
inReviewDocs: HermesDocument[];
approvedDocs: HermesDocument[];
drafts: HermesDocument[];
};
Blocks: {
default: [];
};
}

export enum SortDirection {
Asc = "asc",
Desc = "desc",
}

export enum SortAttribute {
CreatedTime = "createdTime",
ModifiedTime = "modifiedTime", // currently unused
Owner = "owners",
Product = "product",
Status = "status",
DocType = "docType",
Name = "title",
}

export default class MyDocsIndexComponent extends Component<MyDocsIndexComponentSignature> {
@service declare router: RouterService;
@service declare authenticatedUser: AuthenticatedUserService;

@tracked sortAttribute = SortAttribute.CreatedTime;
@tracked sortDirection = SortDirection.Desc;

@tracked isCollapsed = true;

get currentRoute() {
return this.router.currentRouteName;
}

get docsToShow() {
switch (this.currentRoute) {
case "authenticated.my.drafts":
return this.args.drafts;
case "authenticated.my.index":
return this.args.allDocs;
case "authenticated.my.approved":
return this.args.approvedDocs;
case "authenticated.my.in-review":
return this.args.inReviewDocs;
}
}

protected get sortedDocs() {
assert("docsToShow must exist", this.docsToShow);
// this only applies to the /my routes
if (this.router.currentRouteName.startsWith("authenticated.my")) {
return this.docsToShow.slice().sort((a, b) => {
const aProp = a[this.sortAttribute];
const bProp = b[this.sortAttribute];

if (aProp === undefined || bProp === undefined) {
return 0;
}

if (this.sortDirection === SortDirection.Asc) {
// if the attribute is a number, sort by number
// otherwise, sort by string or the first item in the array

if (typeof a[this.sortAttribute] === "number") {
// @ts-ignore
return a[this.sortAttribute] - b[this.sortAttribute];
}

if (typeof a[this.sortAttribute] === "string") {
// @ts-ignore
return a[this.sortAttribute].localeCompare(b[this.sortAttribute]);
}

if (Array.isArray(a[this.sortAttribute])) {
// @ts-ignore
return a[this.sortAttribute][0].localeCompare(
// @ts-ignore
b[this.sortAttribute][0]
);
}
} else {
if (typeof a[this.sortAttribute] === "number") {
// @ts-ignore
return b[this.sortAttribute] - a[this.sortAttribute];
}

if (typeof a[this.sortAttribute] === "string") {
// @ts-ignore
return b[this.sortAttribute].localeCompare(a[this.sortAttribute]);
}

if (Array.isArray(a[this.sortAttribute])) {
// @ts-ignore
return b[this.sortAttribute][0].localeCompare(
// @ts-ignore
a[this.sortAttribute][0]
);
}
}
});
}
return this.docsToShow;
}

@action protected changeSort(
attribute: SortAttribute,
sortDirection?: SortDirection
) {
if (this.sortAttribute === attribute) {
if (this.sortDirection === SortDirection.Asc) {
this.sortDirection = SortDirection.Desc;
} else {
this.sortDirection = SortDirection.Asc;
}
} else {
this.sortAttribute = attribute;
this.sortDirection = sortDirection ?? SortDirection.Asc;
}
}

@action protected toggleCollapsed() {
this.isCollapsed = !this.isCollapsed;
}

@action resetLocalProperties() {
this.sortAttribute = SortAttribute.CreatedTime;
this.sortDirection = SortDirection.Desc;
this.isCollapsed = true;
}
}

declare module "@glint/environment-ember-loose/registry" {
export default interface Registry {
MyDocs: typeof MyDocsIndexComponent;
}
}
Loading