Skip to content

Commit

Permalink
Add ProductArea route (#462)
Browse files Browse the repository at this point in the history
* Set up productAreas route

* Fix bug

* Conditionally add avatars

* Componentize project document

* Remove old code

* Update thumbnail.scss

* Add avatar-loading logic

* Update template to use TileMedium

* Design tweaks

* Improve disabled link

* Component-ize toggle

* Update subscription list

* Fix broken tests

* Update route nesting

* Tests and improved Algolia requests

* Show folder icon if ProductColors is disabled

* Cleanup

* Switch from `facetFilters` → `filters`

* Revert AlgoliaService changes

* Revert change

* Remove unused imports
  • Loading branch information
jeffdaley authored Dec 6, 2023
1 parent c8be5a0 commit 1740dbe
Show file tree
Hide file tree
Showing 23 changed files with 394 additions and 40 deletions.
82 changes: 82 additions & 0 deletions web/app/components/product-area/index.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<div class="mb-24 w-full">
{{! Avatar }}
<Product::Avatar
@product={{@productArea}}
@size="xl"
class="mx-auto mt-0.5"
/>

<div class="text-center">
{{! Name }}
<h1 class="mt-5 text-display-600">
{{@productArea}}
</h1>

{{! Subscription button }}
<Product::SubscriptionToggle
@product={{@productArea}}
@hasTooltip={{true}}
class="mt-6"
/>

<div class="relative mt-12 text-center">
{{! Horizontal line behind doc count}}
<div
class="-translate-y-1.2 absolute left-0 top-1/2 h-px w-full bg-color-border-faint"
aria-hidden="true"
/>
{{#if @docs.length}}
{{! Doc count }}
<h3
data-test-documents-header
class="hermes-h4 relative inline-flex bg-color-page-primary px-6"
>
{{@nbHits}}
Documents
</h3>
{{/if}}
</div>
</div>

<div class="relative mx-auto mt-7 max-w-3xl">
{{#if @docs.length}}
{{! Doc list }}
<ol class="divided-list">
{{#each @docs as |doc|}}
<li data-test-product-area-document class="group relative">
<Doc::TileMedium @doc={{doc}} />
</li>
{{/each}}
</ol>
{{#if this.seeMoreButtonIsShown}}
<div class="mt-7">
<Hds::Button
data-test-see-more-button
@route="authenticated.documents"
@icon="arrow-right"
@iconPosition="trailing"
@query={{hash
product=(array @productArea)
status=(array)
docType=(array)
owners=(array)
page=2
}}
@color="secondary"
@isFullWidth={{true}}
@text="See more {{@productArea}} documents"
/>
</div>
{{/if}}
{{else}}
<div
class="mt-24 grid h-56 place-items-center text-center text-display-300 text-color-foreground-disabled"
data-test-product-area-empty-state
>
No documents found
</div>
{{/if}}

</div>

</div>
23 changes: 23 additions & 0 deletions web/app/components/product-area/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Component from "@glimmer/component";
import { HITS_PER_PAGE } from "hermes/services/algolia";
import { HermesDocument } from "hermes/types/document";

interface ProductAreaIndexComponentSignature {
Args: {
productArea: string;
docs: HermesDocument[];
nbHits: number;
};
}

export default class ProductAreaIndexComponent extends Component<ProductAreaIndexComponentSignature> {
protected get seeMoreButtonIsShown() {
return this.args.nbHits > HITS_PER_PAGE;
}
}

declare module "@glint/environment-ember-loose/registry" {
export default interface Registry {
ProductArea: typeof ProductAreaIndexComponent;
}
}
4 changes: 2 additions & 2 deletions web/app/components/product-link.hbs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<LinkTo
@route="authenticated.documents"
@query={{this.query}}
@route="authenticated.product-areas.product-area"
@model={{dasherize @product}}
class="product-link"
...attributes
>
Expand Down
12 changes: 10 additions & 2 deletions web/app/components/product/avatar.gts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ interface ProductAvatarComponentSignature {
Args: {
product?: string;
icon?: string;
size?: `${Exclude<HermesSize, HermesSize.XL>}`;
size?: `${HermesSize}`;
};
Blocks: {
default: [];
Expand All @@ -37,6 +37,10 @@ export default class ProductAvatarComponent extends Component<ProductAvatarCompo
return this.size === HermesSize.Small;
}

private get sizeIsXL() {
return this.size === HermesSize.XL;
}

private get colorStyles() {
if (!this.flags.productColors) return;
if (this.productID) return;
Expand Down Expand Up @@ -83,7 +87,11 @@ export default class ProductAvatarComponent extends Component<ProductAvatarCompo
{{#if this.iconIsShown}}
<FlightIcon
@name={{or this.productID "folder"}}
class={{if this.sizeIsSmall "h-3 w-3" "h-4 w-4"}}
class={{if
this.sizeIsSmall
"h-3 w-3"
(if this.sizeIsXL "h-8 w-8" "h-4 w-4")
}}
/>
{{else if this.abbreviation}}
<span
Expand Down
4 changes: 2 additions & 2 deletions web/app/components/project/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
{{! Title }}
<div class="mt-7 flex">
<EditableField
class="project-title"
class="project-title text-display-600"
data-test-project-title
@value={{this.title}}
@tag="h1"
Expand Down Expand Up @@ -184,7 +184,7 @@
<Action
data-test-add-jira-button
{{on "click" this.addJiraIssue}}
class="text-body-100 text-color-foreground-disabled underline decoration-color-palette-neutral-200 underline-offset-[3px]"
class="underlined-link text-body-100 text-color-foreground-disabled decoration-color-palette-neutral-200"
>
+ Add Jira link
</Action>
Expand Down
9 changes: 2 additions & 7 deletions web/app/components/settings/subscription-list-item.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,8 @@
>
<LinkTo
data-test-subscription-list-item-link
@route="authenticated.documents"
@query={{hash
product=(array @productArea)
status=(array)
docType=(array)
owners=(array)
}}
@route="authenticated.product-areas.product-area"
@model={{dasherize @productArea}}
class="flex items-center gap-3"
>
<Product::Avatar @product={{@productArea}} @size="small" />
Expand Down
5 changes: 1 addition & 4 deletions web/app/components/table/row.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,7 @@
</td>
<td class="product">
<div class="inner">
<ProductLink
@product={{@doc.product}}
class="decoration-color-palette-neutral-300 underline-offset-[3px] hover:underline"
>
<ProductLink @product={{@doc.product}} class="underlined-link">
{{get-product-label @doc.product}}
</ProductLink>
</div>
Expand Down
10 changes: 10 additions & 0 deletions web/app/controllers/authenticated/product-areas/product-area.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Controller from "@ember/controller";
import AuthenticatedProductAreasProductAreaRoute from "hermes/routes/authenticated/product-areas/product-area";
import { ModelFrom } from "hermes/types/route-models";

export default class AuthenticatedProductAreasProductAreaController extends Controller {
queryParams = ["product"];
product = [];

declare model: ModelFrom<AuthenticatedProductAreasProductAreaRoute>;
}
7 changes: 4 additions & 3 deletions web/app/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ export default class Router extends EmberRouter {
rootURL = config.rootURL;
}

const showProjectRoutes =
config.environment === "development" || config.environment === "test";

Router.map(function () {
this.route("authenticated", { path: "/" }, function () {
this.route("dashboard");
Expand All @@ -31,6 +28,10 @@ Router.map(function () {
this.route("projects", function () {
this.route("project", { path: "/:project_id" });
});

this.route("product-areas", function () {
this.route("product-area", { path: "/:product_area_id" });
});
});
this.route("authenticate");
this.route("404", { path: "/*path" });
Expand Down
27 changes: 27 additions & 0 deletions web/app/routes/authenticated/product-areas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Route from "@ember/routing/route";
import RouterService from "@ember/routing/router-service";
import Transition from "@ember/routing/transition";
import { inject as service } from "@ember/service";
import HermesFlashMessagesService from "hermes/services/flash-messages";

export default class AuthenticatedProductAreasRoute extends Route {
@service declare flashMessages: HermesFlashMessagesService;
@service declare router: RouterService;

beforeModel(transition: Transition) {
// @ts-ignore - `intent` not defined in `Transition` type
const transitionTo = transition.intent.url ?? transition.to.name;
if (
transitionTo === "/product-areas" ||
transitionTo === "/product-areas/" ||
transitionTo === "authenticated.product-areas" ||
transitionTo === "authenticated.product-areas.index"
) {
this.flashMessages.critical("The URL must specify a product area", {
title: "Invalid URL",
});

this.router.transitionTo("authenticated.dashboard");
}
}
}
57 changes: 57 additions & 0 deletions web/app/routes/authenticated/product-areas/product-area.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import Route from "@ember/routing/route";
import RouterService from "@ember/routing/router-service";
import { inject as service } from "@ember/service";
import { dasherize } from "@ember/string";
import AlgoliaService from "hermes/services/algolia";
import AuthenticatedUserService from "hermes/services/authenticated-user";
import ConfigService from "hermes/services/config";
import HermesFlashMessagesService from "hermes/services/flash-messages";
import ProductAreasService from "hermes/services/product-areas";
import { HermesDocument } from "hermes/types/document";
import { SearchResponse } from "instantsearch.js";

export default class AuthenticatedProductAreasProductAreaRoute extends Route {
@service("config") declare configSvc: ConfigService;
@service declare router: RouterService;
@service declare algolia: AlgoliaService;
@service declare authenticatedUser: AuthenticatedUserService;
@service declare flashMessages: HermesFlashMessagesService;
@service declare productAreas: ProductAreasService;

async model(params: { product_area_id: string }) {
const searchIndex =
this.configSvc.config.algolia_docs_index_name + "_createdTime_desc";

if (this.authenticatedUser.subscriptions) {
void this.authenticatedUser.fetchSubscriptions.perform();
} else {
await this.authenticatedUser.fetchSubscriptions.perform();
}

let productArea = Object.keys(this.productAreas.index).find((product) => {
return dasherize(product) === params.product_area_id;
});

if (!productArea) {
this.flashMessages.critical(
`"${params.product_area_id}" is not a valid product area.`,
{
title: "Product area not found",
},
);
this.router.transitionTo("authenticated.dashboard");
} else {
const searchResponse = (await this.algolia.getDocResults.perform(
searchIndex,
{
filters: `product:"${productArea}"`,
},
)) as SearchResponse<unknown>;

const docs = searchResponse.hits as HermesDocument[];
const { nbHits } = searchResponse;

return { docs, productArea, nbHits };
}
}
}
1 change: 1 addition & 0 deletions web/app/services/algolia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ export default class AlgoliaService extends Service {
hitsPerPage: params.hitsPerPage ?? HITS_PER_PAGE,
maxValuesPerFacet: MAX_VALUES_PER_FACET,
page: params.page ? params.page - 1 : 0,
filters: params.filters,
});
} catch (e: unknown) {
console.error(e);
Expand Down
4 changes: 4 additions & 0 deletions web/app/styles/components/doc/tile.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,9 @@

a {
@apply pointer-events-auto;

&[disabled] {
@apply pointer-events-none;
}
}
}
2 changes: 1 addition & 1 deletion web/app/styles/components/project.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
.project-title {
.field-toggle,
textarea {
@apply py-0.5 text-[45px] font-bold leading-[55px] text-color-foreground-strong;
@apply py-0.5 text-display-600 font-bold text-color-foreground-strong;
}
}

Expand Down
32 changes: 20 additions & 12 deletions web/app/styles/hermes/avatar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,6 @@
}
}

&.large,
&.xl {
.product-abbreviation {
&.letter-count-2 {
@apply text-[13px];
}
&.letter-count-3 {
@apply text-[11px] font-semibold;
}
}
}

&.small {
@apply h-5 w-5;

Expand All @@ -44,10 +32,30 @@

&.large {
@apply h-9 w-9;

.product-abbreviation {
&.letter-count-2 {
@apply text-[13px];
}
&.letter-count-3 {
@apply text-[11px] font-semibold;
}
}
}

&.xl {
@apply h-16 w-16;

.product-abbreviation {
@apply text-[32px] tracking-tight;

&.letter-count-2 {
@apply text-[24px];
}
&.letter-count-3 {
@apply text-[18px];
}
}
}
}

Expand Down
1 change: 1 addition & 0 deletions web/app/templates/authenticated/product-areas.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{outlet}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{{page-title this.model.productArea}}

<ProductArea
@productArea={{this.model.productArea}}
@nbHits={{this.model.nbHits}}
@docs={{this.model.docs}}
/>
Loading

0 comments on commit 1740dbe

Please sign in to comment.