diff --git a/web/app/components/doc/row.hbs b/web/app/components/doc/row.hbs index 159bdcd54..602d79305 100644 --- a/web/app/components/doc/row.hbs +++ b/web/app/components/doc/row.hbs @@ -24,11 +24,9 @@ - + + + diff --git a/web/app/components/doc/row.ts b/web/app/components/doc/row.ts index c6d681e83..55d748c60 100644 --- a/web/app/components/doc/row.ts +++ b/web/app/components/doc/row.ts @@ -17,15 +17,7 @@ interface DocRowComponentSignature { }; } -export default class DocRowComponent extends Component { - get productAreaName() { - if (this.args.productArea === "Cloud Platform") { - return "HCP"; - } else { - return this.args.productArea; - } - } -} +export default class DocRowComponent extends Component {} declare module "@glint/environment-ember-loose/registry" { export default interface Registry { diff --git a/web/app/components/doc/snippet.ts b/web/app/components/doc/snippet.ts index ed8cbf1c6..ddff3dc04 100644 --- a/web/app/components/doc/snippet.ts +++ b/web/app/components/doc/snippet.ts @@ -3,7 +3,7 @@ import Component from "@glimmer/component"; interface DocSnippetComponentSignature { Element: HTMLParagraphElement; Args: { - snippet: string; + snippet?: string; }; } diff --git a/web/app/components/doc/tile.hbs b/web/app/components/doc/tile.hbs index bc969bb09..07aeda44f 100644 --- a/web/app/components/doc/tile.hbs +++ b/web/app/components/doc/tile.hbs @@ -1,44 +1,56 @@ - -
- - -
+
+ + {{! + We create a click area that extends beyond the edges of its relative container. + This makes the parent div clickable without having to wrap itself in a link, + and lets us nest interactive elements (e.g., ProductBadgeLink) in a way that improves the mouse experience without sacrificing accessibility. + }} + -
-

- {{@title}} -

- {{#if (not (is-empty @docNumber))}} - - {{@docNumber}} - - {{/if}} -
+
+
+ + +
+
+

+ {{@title}} +

+ {{#if @docNumber}} + + {{@docNumber}} + + {{/if}} +
+
+ + {{#if @modifiedAgo}} +

+ {{@modifiedAgo}} +

+ {{/if}} +
+ {{#if (and @isResult @snippet)}} + + {{/if}} +
+
-
- - {{#if (not (is-empty @modifiedAgo))}} -

- {{@modifiedAgo}} -

- {{/if}} -
- - - - {{#if (and @isResult @snippet)}} - - {{/if}} - + +
diff --git a/web/app/components/doc/tile.ts b/web/app/components/doc/tile.ts index f45f11f2a..43ba277bf 100644 --- a/web/app/components/doc/tile.ts +++ b/web/app/components/doc/tile.ts @@ -7,7 +7,8 @@ interface DocTileComponentSignature { docNumber?: string; isOwner?: boolean; isResult?: boolean; - modifiedAge?: string; + isDraft?: boolean; + modifiedAgo?: string; owner?: string; productArea?: string; snippet?: string; @@ -17,16 +18,7 @@ interface DocTileComponentSignature { }; } -export default class DocTileComponent extends Component { - protected get productAreaName(): string | undefined { - switch (this.args.productArea) { - case "Cloud Platform": - return "HCP"; - default: - return this.args.productArea; - } - } -} +export default class DocTileComponent extends Component {} declare module "@glint/environment-ember-loose/registry" { export default interface Registry { diff --git a/web/app/components/document/sidebar.hbs b/web/app/components/document/sidebar.hbs index 0560904aa..cead9508d 100644 --- a/web/app/components/document/sidebar.hbs +++ b/web/app/components/document/sidebar.hbs @@ -209,10 +209,9 @@ /> {{else}} - {{/if}} diff --git a/web/app/components/product-badge-link.hbs b/web/app/components/product-badge-link.hbs new file mode 100644 index 000000000..3c4fbf1f7 --- /dev/null +++ b/web/app/components/product-badge-link.hbs @@ -0,0 +1,12 @@ + + + diff --git a/web/app/components/product-badge-link.ts b/web/app/components/product-badge-link.ts new file mode 100644 index 000000000..cd3ba5683 --- /dev/null +++ b/web/app/components/product-badge-link.ts @@ -0,0 +1,59 @@ +import RouterService from "@ember/routing/router-service"; +import { inject as service } from "@ember/service"; +import Component from "@glimmer/component"; + +interface ProductBadgeLinkComponentSignature { + Element: HTMLAnchorElement; + Args: { + productArea?: string; + }; + Blocks: { + default: []; + }; +} + +export default class ProductBadgeLinkComponent extends Component { + @service declare router: RouterService; + + protected get productAreaName(): string { + switch (this.args.productArea) { + case "Cloud Platform": + return "HCP"; + default: + return this.args.productArea || "Unknown"; + } + } + + protected get query() { + if (this.args.productArea) { + return { + product: [this.args.productArea], + }; + } else { + return {}; + } + } + + /** + * The route the badge should link to. + * If on the /drafts or /my screen, stay there. + * In all other cases, link to the /all screen. + */ + protected get route() { + const { currentRouteName } = this.router; + + switch (currentRouteName) { + case "authenticated.drafts": + case "authenticated.my": + return currentRouteName; + default: + return "authenticated.all"; + } + } +} + +declare module "@glint/environment-ember-loose/registry" { + export default interface Registry { + ProductBadgeLink: typeof ProductBadgeLinkComponent; + } +} diff --git a/web/app/styles/app.scss b/web/app/styles/app.scss index d086ff9e0..2f6d1e09b 100644 --- a/web/app/styles/app.scss +++ b/web/app/styles/app.scss @@ -34,6 +34,7 @@ @use "components/sidebar"; @use "components/document/related-resources"; @use "components/hds-badge"; +@use "components/product-badge-link"; @use "components/header/facet-dropdown"; @use "components/floating-u-i/content"; @use "components/settings/subscription-list-item"; diff --git a/web/app/styles/components/product-badge-link.scss b/web/app/styles/components/product-badge-link.scss new file mode 100644 index 000000000..dfb9412d2 --- /dev/null +++ b/web/app/styles/components/product-badge-link.scss @@ -0,0 +1,5 @@ +.product-badge-link { + &:hover .hds-badge--color-neutral { + @apply bg-color-palette-neutral-200; + } +} diff --git a/web/mirage/config.ts b/web/mirage/config.ts index 5a9e1aab1..315b8ecaf 100644 --- a/web/mirage/config.ts +++ b/web/mirage/config.ts @@ -397,12 +397,17 @@ export default function (mirageConfig) { * a list of facets and draft results. */ this.get("/drafts", () => { + const allDocs = this.schema.document.all().models; + const drafts = allDocs.filter((doc) => { + return doc.attrs.isDraft; + }); + return new Response( 200, {}, { facets: [], - Hits: [], + Hits: drafts, params: "", page: 0, } diff --git a/web/mirage/factories/document.ts b/web/mirage/factories/document.ts index c842d17aa..486081b3f 100644 --- a/web/mirage/factories/document.ts +++ b/web/mirage/factories/document.ts @@ -29,6 +29,7 @@ export default Factory.extend({ modifiedAgo: 1000000000, modifiedTime: 1, appCreated: true, + isDraft: true, docNumber() { // @ts-ignore - Mirage types are wrong // See discussion at https://github.com/miragejs/miragejs/pull/525 diff --git a/web/tests/acceptance/authenticated/all-test.ts b/web/tests/acceptance/authenticated/all-test.ts index 51b21cd0e..402b1530b 100644 --- a/web/tests/acceptance/authenticated/all-test.ts +++ b/web/tests/acceptance/authenticated/all-test.ts @@ -1,10 +1,12 @@ import { visit } from "@ember/test-helpers"; import { setupApplicationTest } from "ember-qunit"; -import { module, test } from "qunit"; +import { module, test, todo } from "qunit"; import { authenticateSession } from "ember-simple-auth/test-support"; import { MirageTestContext, setupMirage } from "ember-cli-mirage/test-support"; import { getPageTitle } from "ember-page-title/test-support"; +const PRODUCT_BADGE_LINK_SELECTOR = ".product-badge-link"; + interface AuthenticatedAllRouteTestContext extends MirageTestContext {} module("Acceptance | authenticated/all", function (hooks) { @@ -19,4 +21,18 @@ module("Acceptance | authenticated/all", function (hooks) { await visit("/all"); assert.equal(getPageTitle(), "All Docs | Hermes"); }); + + test("product badges have the correct hrefs", async function (this: AuthenticatedAllRouteTestContext, assert) { + // Note: "Vault" is the default product area in the Mirage factory. + + this.server.create("document", { + product: "Labs", + }); + + await visit("/all"); + + assert + .dom(PRODUCT_BADGE_LINK_SELECTOR) + .hasAttribute("href", "/all?product=%5B%22Labs%22%5D"); + }); }); diff --git a/web/tests/acceptance/authenticated/drafts-test.ts b/web/tests/acceptance/authenticated/drafts-test.ts index 9e437c997..22313744d 100644 --- a/web/tests/acceptance/authenticated/drafts-test.ts +++ b/web/tests/acceptance/authenticated/drafts-test.ts @@ -1,6 +1,6 @@ import { visit } from "@ember/test-helpers"; import { setupApplicationTest } from "ember-qunit"; -import { module, test } from "qunit"; +import { module, test, todo } from "qunit"; import { authenticateSession } from "ember-simple-auth/test-support"; import { MirageTestContext, setupMirage } from "ember-cli-mirage/test-support"; import { getPageTitle } from "ember-page-title/test-support"; @@ -19,4 +19,16 @@ module("Acceptance | authenticated/drafts", function (hooks) { await visit("/drafts"); assert.equal(getPageTitle(), "My Drafts | Hermes"); }); + + test("product badges have the correct hrefs", async function (this: AuthenticatedDraftRouteTestContext, assert) { + this.server.create("document", { + product: "Security", + }); + + await visit("/drafts"); + + assert + .dom(".product-badge-link") + .hasAttribute("href", "/drafts?product=%5B%22Security%22%5D"); + }); }); diff --git a/web/tests/acceptance/authenticated/my-test.ts b/web/tests/acceptance/authenticated/my-test.ts index 61a8c8e85..fbd92d3b5 100644 --- a/web/tests/acceptance/authenticated/my-test.ts +++ b/web/tests/acceptance/authenticated/my-test.ts @@ -5,6 +5,8 @@ import { authenticateSession } from "ember-simple-auth/test-support"; import { MirageTestContext, setupMirage } from "ember-cli-mirage/test-support"; import { getPageTitle } from "ember-page-title/test-support"; +const PRODUCT_BADGE_LINK_SELECTOR = ".product-badge-link"; + interface AuthenticatedMyRouteTestContext extends MirageTestContext {} module("Acceptance | authenticated/my", function (hooks) { @@ -19,4 +21,16 @@ module("Acceptance | authenticated/my", function (hooks) { await visit("/my"); assert.equal(getPageTitle(), "My Docs | Hermes"); }); + + test("product badges have the correct hrefs", async function (this: AuthenticatedMyRouteTestContext, assert) { + this.server.create("document", { + product: "Terraform", + }); + + await visit("/my"); + + assert + .dom(PRODUCT_BADGE_LINK_SELECTOR) + .hasAttribute("href", "/my?product=%5B%22Terraform%22%5D"); + }); }); diff --git a/web/tests/acceptance/authenticated/results-test.ts b/web/tests/acceptance/authenticated/results-test.ts index e7c09115d..a34139e0e 100644 --- a/web/tests/acceptance/authenticated/results-test.ts +++ b/web/tests/acceptance/authenticated/results-test.ts @@ -19,4 +19,14 @@ module("Acceptance | authenticated/results", function (hooks) { await visit("/results"); assert.equal(getPageTitle(), "Search Results | Hermes"); }); + + test("product badges have the correct hrefs", async function (this: AuthenticatedResultsRouteTestContext, assert) { + this.server.createList("document", 10); + + await visit("/results"); + + assert + .dom(".product-badge-link") + .hasAttribute("href", "/all?product=%5B%22Vault%22%5D"); + }); }); diff --git a/web/tests/integration/components/document/sidebar/header-test.ts b/web/tests/integration/components/document/sidebar/header-test.ts index 843d2842e..d5b36bd8c 100644 --- a/web/tests/integration/components/document/sidebar/header-test.ts +++ b/web/tests/integration/components/document/sidebar/header-test.ts @@ -32,6 +32,7 @@ module("Integration | Component | document/sidebar/header", function (hooks) { objectID: "400", status: "in-review", docNumber: "001", + isDraft: false, }); this.set("document", this.server.schema.document.first().attrs); @@ -131,7 +132,11 @@ module("Integration | Component | document/sidebar/header", function (hooks) { }); test("it populates the correct share link (with ShortLinkBaseURL)", async function (this: DocumentSidebarHeaderTestContext, assert) { - this.server.create("document", { docType: "PRD", docNumber: "TST-001" }); + this.server.create("document", { + docType: "PRD", + docNumber: "TST-001", + isDraft: false, + }); this.set("document", this.server.schema.document.first().attrs); let configService = this.owner.lookup("service:config") as ConfigService; diff --git a/web/tests/integration/components/product-badge-link-test.ts b/web/tests/integration/components/product-badge-link-test.ts new file mode 100644 index 000000000..72c129957 --- /dev/null +++ b/web/tests/integration/components/product-badge-link-test.ts @@ -0,0 +1,30 @@ +import { module, test } from "qunit"; +import { setupRenderingTest } from "ember-qunit"; +import { TestContext, render } from "@ember/test-helpers"; +import { hbs } from "ember-cli-htmlbars"; + +interface ProductBadgeLinkComponentTestContext extends TestContext {} + +module("Integration | Component | product-badge-link", function (hooks) { + setupRenderingTest(hooks); + + test("it renders with the correct attributes", async function (this: ProductBadgeLinkComponentTestContext, assert) { + await render(hbs` + + + + `); + + assert + .dom(".foo") + .hasAttribute("href", "/all?product=%5B%22Cloud%20Platform%22%5D") + .hasText("HCP"); + + assert + .dom(".bar") + .hasAttribute("href", "/all?product=%5B%22Terraform%22%5D") + .hasText("Terraform"); + + assert.dom(".baz").hasAttribute("href", "/all").hasText("Unknown"); + }); +});