From 4b413b63d49e2774b28e4d59cdc3cd45a9cfd3b6 Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Tue, 8 Aug 2023 20:39:20 -0400 Subject: [PATCH 01/14] Mirage response for docs awaiting review --- web/app/components/person/avatar.hbs | 18 ++++ web/app/components/person/avatar.ts | 20 ++++ web/app/styles/hds-overrides.scss | 9 ++ web/app/templates/authenticated/dashboard.hbs | 100 +++++++++++++----- web/mirage/config.ts | 32 ++++-- .../authenticated/dashboard-test.ts | 19 ++++ 6 files changed, 163 insertions(+), 35 deletions(-) create mode 100644 web/app/components/person/avatar.hbs create mode 100644 web/app/components/person/avatar.ts diff --git a/web/app/components/person/avatar.hbs b/web/app/components/person/avatar.hbs new file mode 100644 index 000000000..837edb852 --- /dev/null +++ b/web/app/components/person/avatar.hbs @@ -0,0 +1,18 @@ +
+ {{#if @imgURL}} + + {{else}} +
+ {{#if @email}} + + {{get-first-letter @email}} + + {{else}} + + {{/if}} +
+ {{/if}} +
diff --git a/web/app/components/person/avatar.ts b/web/app/components/person/avatar.ts new file mode 100644 index 000000000..afc6ecb1e --- /dev/null +++ b/web/app/components/person/avatar.ts @@ -0,0 +1,20 @@ +import Component from "@glimmer/component"; + +interface PersonAvatarComponentSignature { + Element: HTMLDivElement; + Args: { + imgURL?: string | null; + email: string; + }; + Blocks: { + default: []; + }; +} + +export default class PersonAvatarComponent extends Component {} + +declare module "@glint/environment-ember-loose/registry" { + export default interface Registry { + "Person::Avatar": typeof PersonAvatarComponent; + } +} diff --git a/web/app/styles/hds-overrides.scss b/web/app/styles/hds-overrides.scss index b64d0ff37..4e07666dc 100644 --- a/web/app/styles/hds-overrides.scss +++ b/web/app/styles/hds-overrides.scss @@ -38,3 +38,12 @@ @apply absolute right-1.5 top-1/2 -translate-y-1/2; } } + +.badge-count-highlight { + @apply border-transparent bg-red-500 rounded-l-full rounded-r-full bg-color-surface-highlight relative text-color-foreground-highlight text-body-200 mx-1.5 px-3 py-[2px] min-h-0; + + &::before { + content: ""; + @apply absolute -left-px -top-px -right-px -bottom-px rounded-l-full rounded-r-full border border-color-foreground-highlight opacity-60; + } +} diff --git a/web/app/templates/authenticated/dashboard.hbs b/web/app/templates/authenticated/dashboard.hbs index c9f02470e..245fa96ea 100644 --- a/web/app/templates/authenticated/dashboard.hbs +++ b/web/app/templates/authenticated/dashboard.hbs @@ -2,47 +2,91 @@
+{{! TODO: Move this into an index component }} +
-
-

Welcome back, {{this.authenticatedUser.info.given_name}}

-

Here’s all the latest updates across the organization.

-
+

+ Welcome back, + {{this.authenticatedUser.info.given_name}}! +

{{#if this.docsWaitingForReview}} -
-
- -

Documents waiting for your review

+ {{! TODO: Move this into a component }} +
+
+

+ You have + + {{this.docsWaitingForReview.length}} + + document{{if (gt 1 this.docsWaitingForReview.length) "s"}} + awaiting your review: +

-
- {{#each this.docsWaitingForReview as |doc index|}} - {{#if (lt index 4)}} - - {{/if}} +
+ {{#each this.docsWaitingForReview as |doc|}} + +
+
+ + {{! Avatar }} + + +
+ + {{! Title }} +
+ + + {{doc.docNumber}} + + {{doc.title}} + + + {{! Email }} +
+ + {{get doc.owners 0}} + +
+
+
+ + {{! Badges}} +
+ + +
+
+
+
{{/each}}
{{/if}} -
+

{{#each this.recentDocs.all as |r|}} { - return ( - doc.attrs.title.toLowerCase().includes(query.toLowerCase()) || - doc.attrs.product.toLowerCase().includes(query.toLowerCase()) - ); - }); - return new Response(200, {}, { hits: docMatches }); + let isDocsAwaitingReviewRequest = + requestBody.filters.includes("approvers:'testuser@example.com'") && + requestBody.filters.includes("AND status:In-Review"); + + if (isDocsAwaitingReviewRequest) { + let docsAwaitingReview = schema.document + .all() + .models.filter((doc) => { + return ( + doc.attrs.approvers.includes("testuser@example.com") && + doc.attrs.status.toLowerCase().includes("review") + ); + }); + return new Response(200, {}, { hits: docsAwaitingReview }); + } else { + // This is a regular search request. + // TODO: Handle these requests with more precision. + let docMatches = schema.document.all().models.filter((doc) => { + return ( + doc.attrs.title.toLowerCase().includes(query.toLowerCase()) || + doc.attrs.product.toLowerCase().includes(query.toLowerCase()) + ); + }); + return new Response(200, {}, { hits: docMatches }); + } } }; diff --git a/web/tests/acceptance/authenticated/dashboard-test.ts b/web/tests/acceptance/authenticated/dashboard-test.ts index d160e7f77..230589be2 100644 --- a/web/tests/acceptance/authenticated/dashboard-test.ts +++ b/web/tests/acceptance/authenticated/dashboard-test.ts @@ -19,4 +19,23 @@ module("Acceptance | authenticated/dashboard", function (hooks) { await visit("/dashboard"); assert.equal(getPageTitle(), "Dashboard | Hermes"); }); + + test("it shows a list of docs awaiting review", async function (this: AuthenticatedDashboardRouteTestContext, assert) { + this.server.create("document", { + title: "Document to review", + status: "In Review", + approvers: ["testuser@example.com"], + }); + + this.server.create("document", { + title: "Not a document to review", + status: "In Review", + approvers: ["foo@example.com"], + }); + // mirage server needs to return a search based on owners filter rather than product + + await visit("/dashboard"); + + await this.pauseTest(); + }); }); From c06361335f64831ac4f3a247a42f70b66df935dd Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Tue, 8 Aug 2023 21:28:21 -0400 Subject: [PATCH 02/14] Dashboard test --- web/app/components/person/avatar.hbs | 4 +- web/app/templates/authenticated/dashboard.hbs | 109 ++++++++++-------- web/mirage/factories/document.ts | 1 + .../authenticated/dashboard-test.ts | 84 +++++++++++++- 4 files changed, 144 insertions(+), 54 deletions(-) diff --git a/web/app/components/person/avatar.hbs b/web/app/components/person/avatar.hbs index 837edb852..f33150ae2 100644 --- a/web/app/components/person/avatar.hbs +++ b/web/app/components/person/avatar.hbs @@ -1,11 +1,11 @@
{{#if @imgURL}} {{else}} -
+
{{#if @email}} {{get-first-letter @email}} diff --git a/web/app/templates/authenticated/dashboard.hbs b/web/app/templates/authenticated/dashboard.hbs index 245fa96ea..c4eeca0cb 100644 --- a/web/app/templates/authenticated/dashboard.hbs +++ b/web/app/templates/authenticated/dashboard.hbs @@ -19,7 +19,10 @@

You have - + {{this.docsWaitingForReview.length}} document{{if (gt 1 this.docsWaitingForReview.length) "s"}} @@ -27,60 +30,74 @@

-
+
    {{#each this.docsWaitingForReview as |doc|}} - -
    -
    - - {{! Avatar }} - - -
    - - {{! Title }} -
    - - - {{doc.docNumber}} - - {{doc.title}} - - - {{! Email }} -
    - - {{get doc.owners 0}} +
  • + +
    +
    + + {{! Avatar }} + {{! TODO: Apply this to other avatar spots }} + + +
    + + {{! Title }} +
    + + + {{doc.docNumber}} + + {{doc.title}} + + {{! Email }} +
    + + {{get doc.owners 0}} + +
    -
    - {{! Badges}} -
    - - + {{! Badges}} +
    + + +
    -
  • - + + + {{/each}} -
    +
{{/if}} diff --git a/web/mirage/factories/document.ts b/web/mirage/factories/document.ts index c842d17aa..ba5a28734 100644 --- a/web/mirage/factories/document.ts +++ b/web/mirage/factories/document.ts @@ -39,5 +39,6 @@ export default Factory.extend({ value: "This is a test document", }, }, + approvers: [], owners: ["testuser@example.com"], }); diff --git a/web/tests/acceptance/authenticated/dashboard-test.ts b/web/tests/acceptance/authenticated/dashboard-test.ts index 230589be2..6c1ef209b 100644 --- a/web/tests/acceptance/authenticated/dashboard-test.ts +++ b/web/tests/acceptance/authenticated/dashboard-test.ts @@ -1,10 +1,28 @@ -import { visit } from "@ember/test-helpers"; +import { find, findAll, visit } from "@ember/test-helpers"; import { setupApplicationTest } from "ember-qunit"; import { module, test } 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 DOCS_AWAITING_REVIEW_COUNT_SELECTOR = + "[data-test-docs-awaiting-review-count]"; + +const DOC_AWAITING_REVIEW_LINK_SELECTOR = + "[data-test-doc-awaiting-review-link]"; + +const DOC_AWAITING_REVIEW_NUMBER_AND_TITLE_SELECTOR = + "[data-test-doc-awaiting-review-number-and-title]"; + +const DOC_AWAITING_REVIEW_OWNER_SELECTOR = + "[data-test-doc-awaiting-review-owner]"; + +const DOC_AWAITING_REVIEW_PRODUCT_BADGE_SELECTOR = + "[data-test-doc-awaiting-review-product-badge]"; + +const DOC_AWAITING_REVIEW_DOCTYPE_BADGE_SELECTOR = + "[data-test-doc-awaiting-review-doctype-badge]"; + interface AuthenticatedDashboardRouteTestContext extends MirageTestContext {} module("Acceptance | authenticated/dashboard", function (hooks) { @@ -22,20 +40,74 @@ module("Acceptance | authenticated/dashboard", function (hooks) { test("it shows a list of docs awaiting review", async function (this: AuthenticatedDashboardRouteTestContext, assert) { this.server.create("document", { - title: "Document to review", + objectID: 10, + title: "Foo", + product: "Cloud Platform", + status: "In Review", + docType: "PRFAQ", + owners: ["foo@example.com"], + approvers: ["testuser@example.com"], + }); + + this.server.create("document", { + objectID: 20, + title: "Bar", + product: "Test Product 0", status: "In Review", + docType: "PRD", + owners: ["bar@example.com"], approvers: ["testuser@example.com"], }); this.server.create("document", { - title: "Not a document to review", + title: "Baz", status: "In Review", - approvers: ["foo@example.com"], + approvers: ["not_testuser@example.com"], }); - // mirage server needs to return a search based on owners filter rather than product await visit("/dashboard"); - await this.pauseTest(); + // TODO: Move most of this to the component test + + assert.dom(DOCS_AWAITING_REVIEW_COUNT_SELECTOR).hasText("2"); + + assert.dom(DOC_AWAITING_REVIEW_LINK_SELECTOR).exists({ count: 2 }); + + assert + .dom(find(DOC_AWAITING_REVIEW_LINK_SELECTOR)) + .hasText("Foo") + .hasAttribute("href", "/documents/10", "Links to the correct doc"); + + assert + .dom( + find( + `${DOC_AWAITING_REVIEW_LINK_SELECTOR} ${DOC_AWAITING_REVIEW_NUMBER_AND_TITLE_SELECTOR}` + ) + ) + .hasText("TP0-001: Bar", "Shows the doc number and title"); + + assert + .dom( + find( + `${DOC_AWAITING_REVIEW_LINK_SELECTOR} ${DOC_AWAITING_REVIEW_OWNER_SELECTOR}` + ) + ) + .hasText("foo@example.com", "Shows the doc owner"); + + assert + .dom( + find( + `${DOC_AWAITING_REVIEW_LINK_SELECTOR} ${DOC_AWAITING_REVIEW_PRODUCT_BADGE_SELECTOR}` + ) + ) + .hasText("Cloud Platform", "Shows the product name"); + + assert + .dom( + find( + `${DOC_AWAITING_REVIEW_LINK_SELECTOR} ${DOC_AWAITING_REVIEW_DOCTYPE_BADGE_SELECTOR}` + ) + ) + .hasText("PRFAQ", "Shows the doc type"); }); }); From c47127d8531392c60487394ff2866c675eef3506 Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Tue, 8 Aug 2023 21:38:06 -0400 Subject: [PATCH 03/14] Update dashboard-test.ts --- web/tests/acceptance/authenticated/dashboard-test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/tests/acceptance/authenticated/dashboard-test.ts b/web/tests/acceptance/authenticated/dashboard-test.ts index 6c1ef209b..e98ad0c5f 100644 --- a/web/tests/acceptance/authenticated/dashboard-test.ts +++ b/web/tests/acceptance/authenticated/dashboard-test.ts @@ -75,7 +75,7 @@ module("Acceptance | authenticated/dashboard", function (hooks) { assert .dom(find(DOC_AWAITING_REVIEW_LINK_SELECTOR)) - .hasText("Foo") + .containsText("Foo") .hasAttribute("href", "/documents/10", "Links to the correct doc"); assert From 0fb7ccd361d5fd5673b25e48558bc18a41e8e6ab Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Wed, 9 Aug 2023 12:12:34 -0400 Subject: [PATCH 04/14] Componentize and test --- .../dashboard/docs-awaiting-review.hbs | 19 ++++ .../dashboard/docs-awaiting-review.ts | 20 ++++ .../dashboard/docs-awaiting-review/doc.hbs | 70 ++++++++++++++ .../dashboard/docs-awaiting-review/doc.ts | 20 ++++ web/app/components/truncated-text.hbs | 2 +- web/app/components/truncated-text.ts | 10 +- web/app/styles/hds-overrides.scss | 5 +- web/app/styles/typography.scss | 13 ++- web/app/templates/authenticated/dashboard.hbs | 88 +----------------- .../authenticated/dashboard-test.ts | 93 +------------------ .../dashboard/docs-awaiting-review-test.ts | 56 +++++++++++ .../docs-awaiting-review/doc-test.ts | 90 ++++++++++++++++++ .../components/truncated-text-test.ts | 12 +++ web/types/glint/index.d.ts | 2 + 14 files changed, 317 insertions(+), 183 deletions(-) create mode 100644 web/app/components/dashboard/docs-awaiting-review.hbs create mode 100644 web/app/components/dashboard/docs-awaiting-review.ts create mode 100644 web/app/components/dashboard/docs-awaiting-review/doc.hbs create mode 100644 web/app/components/dashboard/docs-awaiting-review/doc.ts create mode 100644 web/tests/integration/components/dashboard/docs-awaiting-review-test.ts create mode 100644 web/tests/integration/components/dashboard/docs-awaiting-review/doc-test.ts diff --git a/web/app/components/dashboard/docs-awaiting-review.hbs b/web/app/components/dashboard/docs-awaiting-review.hbs new file mode 100644 index 000000000..555182a22 --- /dev/null +++ b/web/app/components/dashboard/docs-awaiting-review.hbs @@ -0,0 +1,19 @@ +
+
+

+ You have + + {{@docs.length}} + + document{{if (gt @docs.length 1) "s"}} + awaiting your review: +

+
+ +
    + {{#each @docs as |doc|}} + + {{/each}} + +
+
diff --git a/web/app/components/dashboard/docs-awaiting-review.ts b/web/app/components/dashboard/docs-awaiting-review.ts new file mode 100644 index 000000000..0c3600a22 --- /dev/null +++ b/web/app/components/dashboard/docs-awaiting-review.ts @@ -0,0 +1,20 @@ +import Component from "@glimmer/component"; +import { HermesDocument } from "hermes/types/document"; + +interface DashboardDocsAwaitingReviewComponentSignature { + Element: null; + Args: { + docs: HermesDocument[]; + }; + Blocks: { + default: []; + }; +} + +export default class DashboardDocsAwaitingReviewComponent extends Component {} + +declare module "@glint/environment-ember-loose/registry" { + export default interface Registry { + "Dashboard::DocsAwaitingReview": typeof DashboardDocsAwaitingReviewComponent; + } +} diff --git a/web/app/components/dashboard/docs-awaiting-review/doc.hbs b/web/app/components/dashboard/docs-awaiting-review/doc.hbs new file mode 100644 index 000000000..bef8813f6 --- /dev/null +++ b/web/app/components/dashboard/docs-awaiting-review/doc.hbs @@ -0,0 +1,70 @@ +
  • + +
    +
    + + {{! Avatar }} + {{! TODO: Apply this to other avatar spots }} + + +
    + + {{! Title }} +
    + + + {{@doc.docNumber}} + + {{@doc.title}} + + + {{! Email }} +
    + + {{get @doc.owners 0}} + +
    +
    +
    + + {{! Badges}} +
    + + +
    +
    +
    +
    +
  • diff --git a/web/app/components/dashboard/docs-awaiting-review/doc.ts b/web/app/components/dashboard/docs-awaiting-review/doc.ts new file mode 100644 index 000000000..9ee68b596 --- /dev/null +++ b/web/app/components/dashboard/docs-awaiting-review/doc.ts @@ -0,0 +1,20 @@ +import Component from "@glimmer/component"; +import { HermesDocument } from "hermes/types/document"; + +interface DashboardDocsAwaitingReviewDocComponentSignature { + Element: null; + Args: { + doc: HermesDocument; + }; + Blocks: { + default: []; + }; +} + +export default class DashboardDocsAwaitingReviewDocComponent extends Component {} + +declare module "@glint/environment-ember-loose/registry" { + export default interface Registry { + "Dashboard::DocsAwaitingReview::Doc": typeof DashboardDocsAwaitingReviewDocComponent; + } +} diff --git a/web/app/components/truncated-text.hbs b/web/app/components/truncated-text.hbs index e816c14f1..7c120fb82 100644 --- a/web/app/components/truncated-text.hbs +++ b/web/app/components/truncated-text.hbs @@ -7,7 +7,7 @@ {{! @glint-ignore - element helper not yet typed }} {{#let (element (or @tagName "p")) as |Container|}} - + {{yield}} diff --git a/web/app/components/truncated-text.ts b/web/app/components/truncated-text.ts index c91fb01ea..28aff6c24 100644 --- a/web/app/components/truncated-text.ts +++ b/web/app/components/truncated-text.ts @@ -4,13 +4,21 @@ interface TruncatedTextComponentSignature { Element: HTMLSpanElement; Args: { tagName?: string; + startingBreakpoint?: "md"; }; Blocks: { default: []; }; } -export default class TruncatedTextComponent extends Component {} +export default class TruncatedTextComponent extends Component { + protected get class(): string { + if (this.args.startingBreakpoint === "md") { + return "starting-md"; + } + return "default"; + } +} declare module "@glint/environment-ember-loose/registry" { export default interface Registry { diff --git a/web/app/styles/hds-overrides.scss b/web/app/styles/hds-overrides.scss index 4e07666dc..bdded5efb 100644 --- a/web/app/styles/hds-overrides.scss +++ b/web/app/styles/hds-overrides.scss @@ -40,7 +40,10 @@ } .badge-count-highlight { - @apply border-transparent bg-red-500 rounded-l-full rounded-r-full bg-color-surface-highlight relative text-color-foreground-highlight text-body-200 mx-1.5 px-3 py-[2px] min-h-0; + @apply border-transparent rounded-l-full rounded-r-full bg-color-surface-highlight relative text-color-foreground-highlight text-body-200 inline-flex; + + @apply px-2 mx-0.5; + @apply md:px-3 md:py-[2px] md:mx-1.5; &::before { content: ""; diff --git a/web/app/styles/typography.scss b/web/app/styles/typography.scss index c688146a5..f12cfdf9d 100644 --- a/web/app/styles/typography.scss +++ b/web/app/styles/typography.scss @@ -15,5 +15,16 @@ } .truncated-text-container { - @apply truncate block font-regular text-body-100 text-color-foreground-faint; + @apply block font-regular text-body-100 text-color-foreground-faint; + + // These classes are applied by the TruncatedText component + // based on its optional `startingBreakpoint` argument: + + &.default { + @apply truncate; + } + + &.starting-md { + @apply md:truncate; + } } diff --git a/web/app/templates/authenticated/dashboard.hbs b/web/app/templates/authenticated/dashboard.hbs index c4eeca0cb..843f8fac6 100644 --- a/web/app/templates/authenticated/dashboard.hbs +++ b/web/app/templates/authenticated/dashboard.hbs @@ -2,8 +2,6 @@
    -{{! TODO: Move this into an index component }} -
    @@ -14,91 +12,7 @@

    {{#if this.docsWaitingForReview}} - {{! TODO: Move this into a component }} -
    -
    -

    - You have - - {{this.docsWaitingForReview.length}} - - document{{if (gt 1 this.docsWaitingForReview.length) "s"}} - awaiting your review: -

    -
    - -
      - {{#each this.docsWaitingForReview as |doc|}} -
    • - -
      -
      - - {{! Avatar }} - {{! TODO: Apply this to other avatar spots }} - - -
      - - {{! Title }} -
      - - - {{doc.docNumber}} - - {{doc.title}} - - - {{! Email }} -
      - - {{get doc.owners 0}} - -
      -
      -
      - - {{! Badges}} -
      - - -
      -
      -
      -
      -
    • - - {{/each}} - -
    -
    + {{/if}}
    ( + hbs`` + ); + + assert.dom(DOCS_AWAITING_REVIEW_COUNT_SELECTOR).containsText("2"); + assert.dom(DOC_AWAITING_REVIEW_LINK_SELECTOR).exists({ count: 2 }); + + assert.dom("h2").containsText("documents awaiting your review"); + + this.set("docs", [this.server.schema.document.first()]); + + assert.dom(DOCS_AWAITING_REVIEW_COUNT_SELECTOR).containsText("1"); + assert.dom(DOC_AWAITING_REVIEW_LINK_SELECTOR).exists({ count: 1 }); + + assert.dom("h2").containsText("document awaiting your review"); + }); + } +); diff --git a/web/tests/integration/components/dashboard/docs-awaiting-review/doc-test.ts b/web/tests/integration/components/dashboard/docs-awaiting-review/doc-test.ts new file mode 100644 index 000000000..997076def --- /dev/null +++ b/web/tests/integration/components/dashboard/docs-awaiting-review/doc-test.ts @@ -0,0 +1,90 @@ +import { module, test } from "qunit"; +import { setupRenderingTest } from "ember-qunit"; +import { MirageTestContext, setupMirage } from "ember-cli-mirage/test-support"; +import { find, render } from "@ember/test-helpers"; +import { hbs } from "ember-cli-htmlbars"; +import { HermesDocument } from "hermes/types/document"; + +const DOC_AWAITING_REVIEW_LINK_SELECTOR = + "[data-test-doc-awaiting-review-link]"; + +const DOC_AWAITING_REVIEW_NUMBER_AND_TITLE_SELECTOR = + "[data-test-doc-awaiting-review-number-and-title]"; + +const DOC_AWAITING_REVIEW_OWNER_SELECTOR = + "[data-test-doc-awaiting-review-owner]"; + +const DOC_AWAITING_REVIEW_PRODUCT_BADGE_SELECTOR = + "[data-test-doc-awaiting-review-product-badge]"; + +const DOC_AWAITING_REVIEW_DOCTYPE_BADGE_SELECTOR = + "[data-test-doc-awaiting-review-doctype-badge]"; + +interface DashboardDocsAwaitingReviewDocTestContext extends MirageTestContext { + doc: HermesDocument; +} + +module( + "Integration | Component | dashboard/docs-awaiting-review/doc", + function (hooks) { + setupRenderingTest(hooks); + setupMirage(hooks); + + test("it renders as expected", async function (this: DashboardDocsAwaitingReviewDocTestContext, assert) { + this.server.create("document", { + objectID: 10, + title: "Foo", + product: "Cloud Platform", + status: "In Review", + docType: "PRFAQ", + owners: ["foo@example.com"], + approvers: ["testuser@example.com"], + }); + + this.set("doc", this.server.schema.document.first()); + + await render(hbs` + + `); + + assert + .dom(DOC_AWAITING_REVIEW_LINK_SELECTOR) + .containsText("Foo") + .hasAttribute("href", "/documents/10"); + + assert + .dom( + find( + `${DOC_AWAITING_REVIEW_LINK_SELECTOR} ${DOC_AWAITING_REVIEW_NUMBER_AND_TITLE_SELECTOR}` + ) + ) + .hasText("TP0-001: Bar", "Shows the doc number and title"); + + assert + .dom( + find( + `${DOC_AWAITING_REVIEW_LINK_SELECTOR} ${DOC_AWAITING_REVIEW_OWNER_SELECTOR}` + ) + ) + .hasText("foo@example.com", "Shows the doc owner"); + + assert + .dom( + find( + `${DOC_AWAITING_REVIEW_LINK_SELECTOR} ${DOC_AWAITING_REVIEW_PRODUCT_BADGE_SELECTOR}` + ) + ) + .hasText("Cloud Platform", "Shows the product name"); + + assert + .dom( + find( + `${DOC_AWAITING_REVIEW_LINK_SELECTOR} ${DOC_AWAITING_REVIEW_DOCTYPE_BADGE_SELECTOR}` + ) + ) + .hasText("PRFAQ", "Shows the doc type"); + }); + } +); diff --git a/web/tests/integration/components/truncated-text-test.ts b/web/tests/integration/components/truncated-text-test.ts index 9499e1ccd..17b57f556 100644 --- a/web/tests/integration/components/truncated-text-test.ts +++ b/web/tests/integration/components/truncated-text-test.ts @@ -54,4 +54,16 @@ module("Integration | Component | truncated-text", function (hooks) { assert.dom(`h1${CONTAINER_SELECTOR}`).exists("renders a custom tag"); }); + + test("it truncates text with a custom breakpoint", async function (assert) { + await render(hbs` +
    + + This is a very long text that should be truncated + +
    + `); + + // TODO: use ember-window-mock to set the breakpoint to md + }); }); diff --git a/web/types/glint/index.d.ts b/web/types/glint/index.d.ts index 1b658895e..8b9ac30c6 100644 --- a/web/types/glint/index.d.ts +++ b/web/types/glint/index.d.ts @@ -7,6 +7,7 @@ import AndHelper from "ember-truth-helpers/helpers/and"; import EqHelper from "ember-truth-helpers/helpers/eq"; import IsEmptyHelper from "ember-truth-helpers/helpers/is-empty"; import LtHelper from "ember-truth-helpers/helpers/lt"; +import GtHelper from "ember-truth-helpers/helpers/gt"; import NotHelper from "ember-truth-helpers/helpers/not"; import OrHelper from "ember-truth-helpers/helpers/or"; import { FlightIconComponent } from "hds/flight-icon"; @@ -56,6 +57,7 @@ declare module "@glint/environment-ember-loose/registry" { and: typeof AndHelper; not: typeof NotHelper; lt: typeof LtHelper; + gt: typeof GtHelper; "is-empty": IsEmptyHelper; FlashMessage: FlashMessageComponent; FlightIcon: FlightIconComponent; From 7280de43e22ea95274045b9a3f90a5b21e164473 Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Wed, 9 Aug 2023 15:29:19 -0400 Subject: [PATCH 05/14] Fix tests, convert files to TS --- .../components/dashboard/latest-updates.ts | 4 +- .../controllers/authenticated/dashboard.js | 15 ---- .../controllers/authenticated/dashboard.ts | 10 +++ .../{dashboard.js => dashboard.ts} | 76 ++++++++----------- web/app/templates/authenticated/dashboard.hbs | 4 - web/mirage/config.ts | 43 ++++++----- web/tests/acceptance/application-test.ts | 10 +++ .../docs-awaiting-review/doc-test.ts | 4 +- .../components/truncated-text-test.ts | 2 + 9 files changed, 83 insertions(+), 85 deletions(-) delete mode 100644 web/app/controllers/authenticated/dashboard.js create mode 100644 web/app/controllers/authenticated/dashboard.ts rename web/app/routes/authenticated/{dashboard.js => dashboard.ts} (58%) diff --git a/web/app/components/dashboard/latest-updates.ts b/web/app/components/dashboard/latest-updates.ts index 779c34b7d..2a54a0cc5 100644 --- a/web/app/components/dashboard/latest-updates.ts +++ b/web/app/components/dashboard/latest-updates.ts @@ -76,12 +76,14 @@ export default class DashboardLatestUpdatesComponent extends Component { // Add modifiedAgo for each doc. for (const hit of result.hits) { + console.log("shit", hit); this.fetchSvc .fetch("/api/v1/documents/" + hit.objectID) - .then((resp) => resp.json()) + .then((resp) => resp?.json()) .then((doc) => { + console.log("doc"); if (doc.modifiedTime) { const modifiedDate = new Date(doc.modifiedTime * 1000); + // @ts-ignore hit.modifiedAgo = `Modified ${timeAgo(modifiedDate)}`; } }) @@ -67,31 +56,28 @@ export default class DashboardRoute extends Route { return result.hits; }); - await this.recentDocs.fetchAll.perform(); - if (this.recentDocs.all === null) { - try { - await this.recentDocs.fetchAll.perform(); - } catch { - /** - * This tells our template to show the error state. - */ - this.recentDocs.all = null; - } + try { + await this.recentDocs.fetchAll.perform(); + } catch { + /** + * This tells our template to show the error state. + */ + this.recentDocs.all = null; } - return RSVP.hash({ - docsWaitingForReview: docsWaitingForReview, - }); + return docsAwaitingReview; } /** * Builds a parent query string for searching for Google files. The folders * parameter is an array of all folder ID strings to search. */ + // @ts-ignore - Not yet typed buildParentsQuery(folders) { let parentsQuery = ""; if (folders.length > 0) { parentsQuery += " and ("; + // @ts-ignore - Not yet typed folders.forEach((folder, index) => { if (index == 0) { parentsQuery += `'${folder}' in parents`; diff --git a/web/app/templates/authenticated/dashboard.hbs b/web/app/templates/authenticated/dashboard.hbs index 843f8fac6..0919e9d87 100644 --- a/web/app/templates/authenticated/dashboard.hbs +++ b/web/app/templates/authenticated/dashboard.hbs @@ -11,10 +11,6 @@ {{this.authenticatedUser.info.given_name}}! - {{#if this.docsWaitingForReview}} - - {{/if}} -
    diff --git a/web/mirage/config.ts b/web/mirage/config.ts index 10dbf799b..f2e2cf619 100644 --- a/web/mirage/config.ts +++ b/web/mirage/config.ts @@ -59,6 +59,15 @@ export default function (mirageConfig) { let docMatches = []; let idsToExclude: string[] = []; + const setDefaultDocMatches = () => { + docMatches = schema.document.all().models.filter((doc) => { + return ( + doc.attrs.title.toLowerCase().includes(query.toLowerCase()) || + doc.attrs.product.toLowerCase().includes(query.toLowerCase()) + ); + }); + }; + const filters = requestBody.filters; if (filters?.includes("NOT objectID")) { @@ -77,11 +86,6 @@ export default function (mirageConfig) { const optionalFilters = requestBody.optionalFilters; - const requestIsForDocsAwaitingReview = - requestBody.filters.includes( - "approvers:'testuser@example.com'" - ) && requestBody.filters.includes("AND status:In-Review"); - if (optionalFilters?.includes("docNumber")) { const docNumber = optionalFilters .split('docNumber:"')[1] @@ -93,20 +97,23 @@ export default function (mirageConfig) { // Duplicates are detected in the front end return new Response(200, {}, { hits: docMatches }); - } else if (requestIsForDocsAwaitingReview) { - docMatches = schema.document.all().models.filter((doc) => { - return ( - doc.attrs.approvers.includes("testuser@example.com") && - doc.attrs.status.toLowerCase().includes("review") - ); - }); + } else if (filters) { + const requestIsForDocsAwaitingReview = + filters.includes("approvers:'testuser@example.com'") && + requestBody.filters.includes("AND status:In-Review"); + if (requestIsForDocsAwaitingReview) { + docMatches = schema.document.all().models.filter((doc) => { + return ( + doc.attrs.approvers.includes("testuser@example.com") && + doc.attrs.status.toLowerCase().includes("review") + ); + }); + } else { + // This + setDefaultDocMatches(); + } } else { - docMatches = schema.document.all().models.filter((doc) => { - return ( - doc.attrs.title.toLowerCase().includes(query.toLowerCase()) || - doc.attrs.product.toLowerCase().includes(query.toLowerCase()) - ); - }); + setDefaultDocMatches(); } if (idsToExclude) { diff --git a/web/tests/acceptance/application-test.ts b/web/tests/acceptance/application-test.ts index c98a74fb1..1f4c6ffb2 100644 --- a/web/tests/acceptance/application-test.ts +++ b/web/tests/acceptance/application-test.ts @@ -190,5 +190,15 @@ module("Acceptance | application", function (hooks) { assert .dom("[data-test-user-menu-support") .hasAttribute("href", TEST_SUPPORT_URL); + + /** + * FIXME: Investigate unresolved promises + * + * For reasons not yet clear, this test has unresolved promises + * that prevent it from completing naturally. Because of this, + * we handle teardown manually. + * + */ + teardownContext(this); }); }); diff --git a/web/tests/integration/components/dashboard/docs-awaiting-review/doc-test.ts b/web/tests/integration/components/dashboard/docs-awaiting-review/doc-test.ts index 997076def..af3960e6f 100644 --- a/web/tests/integration/components/dashboard/docs-awaiting-review/doc-test.ts +++ b/web/tests/integration/components/dashboard/docs-awaiting-review/doc-test.ts @@ -52,7 +52,7 @@ module( assert .dom(DOC_AWAITING_REVIEW_LINK_SELECTOR) .containsText("Foo") - .hasAttribute("href", "/documents/10"); + .hasAttribute("href", "/document/10"); assert .dom( @@ -60,7 +60,7 @@ module( `${DOC_AWAITING_REVIEW_LINK_SELECTOR} ${DOC_AWAITING_REVIEW_NUMBER_AND_TITLE_SELECTOR}` ) ) - .hasText("TP0-001: Bar", "Shows the doc number and title"); + .hasText("HCP-001 Foo", "Shows the doc number and title"); assert .dom( diff --git a/web/tests/integration/components/truncated-text-test.ts b/web/tests/integration/components/truncated-text-test.ts index 17b57f556..7d8ca1f5a 100644 --- a/web/tests/integration/components/truncated-text-test.ts +++ b/web/tests/integration/components/truncated-text-test.ts @@ -64,6 +64,8 @@ module("Integration | Component | truncated-text", function (hooks) {
    `); + assert.true(true, "TODO: implement this test"); + // TODO: use ember-window-mock to set the breakpoint to md }); }); From b4bd07db90bf0cdb39e30906b806dc8e48fd0059 Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Wed, 9 Aug 2023 15:44:43 -0400 Subject: [PATCH 06/14] Apply Avatar to component --- .../dashboard/docs-awaiting-review/doc.hbs | 3 ++- web/app/components/person/avatar.hbs | 5 ++++- web/app/components/person/avatar.ts | 16 ++++++++++++++- web/app/components/person/index.hbs | 20 +------------------ 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/web/app/components/dashboard/docs-awaiting-review/doc.hbs b/web/app/components/dashboard/docs-awaiting-review/doc.hbs index bef8813f6..b58867726 100644 --- a/web/app/components/dashboard/docs-awaiting-review/doc.hbs +++ b/web/app/components/dashboard/docs-awaiting-review/doc.hbs @@ -16,7 +16,8 @@ data-test-doc-awaiting-review-owner-avatar @email={{or (get @doc.owners 0) "Unknown"}} @imgURL={{get @doc.ownerPhotos 0}} - class="!w-7 !h-7 rounded-full border border-white group-hover:border-color-surface-faint shrink-0" + @size="medium" + class="shrink-0" />
    diff --git a/web/app/components/person/avatar.hbs b/web/app/components/person/avatar.hbs index f33150ae2..4a7ac8be0 100644 --- a/web/app/components/person/avatar.hbs +++ b/web/app/components/person/avatar.hbs @@ -1,5 +1,8 @@
    {{#if @imgURL}} diff --git a/web/app/components/person/avatar.ts b/web/app/components/person/avatar.ts index afc6ecb1e..88fb3aa8f 100644 --- a/web/app/components/person/avatar.ts +++ b/web/app/components/person/avatar.ts @@ -1,17 +1,31 @@ import Component from "@glimmer/component"; +enum HermesAvatarSize { + Small = "small", + Medium = "medium", +} + interface PersonAvatarComponentSignature { Element: HTMLDivElement; Args: { imgURL?: string | null; email: string; + size: `${HermesAvatarSize}`; }; Blocks: { default: []; }; } -export default class PersonAvatarComponent extends Component {} +export default class PersonAvatarComponent extends Component { + protected get sizeIsSmall(): boolean { + return this.args.size === HermesAvatarSize.Small; + } + + protected get sizeIsMedium(): boolean { + return this.args.size === HermesAvatarSize.Medium; + } +} declare module "@glint/environment-ember-loose/registry" { export default interface Registry { diff --git a/web/app/components/person/index.hbs b/web/app/components/person/index.hbs index 22f3f4ec4..bb6dc554d 100644 --- a/web/app/components/person/index.hbs +++ b/web/app/components/person/index.hbs @@ -13,25 +13,7 @@ />
    {{/if}} -
    - {{#if @imgURL}} - - {{else}} -
    - {{#if @email}} - - {{get-first-letter @email}} - - {{else}} - - {{/if}} -
    - {{/if}} -
    +
    Date: Wed, 9 Aug 2023 15:45:54 -0400 Subject: [PATCH 07/14] Comment cleanup --- web/app/components/dashboard/docs-awaiting-review/doc.hbs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/web/app/components/dashboard/docs-awaiting-review/doc.hbs b/web/app/components/dashboard/docs-awaiting-review/doc.hbs index b58867726..e83d5e4c6 100644 --- a/web/app/components/dashboard/docs-awaiting-review/doc.hbs +++ b/web/app/components/dashboard/docs-awaiting-review/doc.hbs @@ -11,7 +11,6 @@ > {{! Avatar }} - {{! TODO: Apply this to other avatar spots }} - {{! Title }} + {{! DocNumber & Title }}
    - {{! Badges}} + {{! Product & DocType }}
    From e4a9dcdf2f1bb363f8b826b4c39560fd37e01d7c Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Wed, 9 Aug 2023 15:47:08 -0400 Subject: [PATCH 08/14] Revert LatestUpdates changes --- web/app/components/dashboard/latest-updates.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/web/app/components/dashboard/latest-updates.ts b/web/app/components/dashboard/latest-updates.ts index 2a54a0cc5..779c34b7d 100644 --- a/web/app/components/dashboard/latest-updates.ts +++ b/web/app/components/dashboard/latest-updates.ts @@ -76,14 +76,12 @@ export default class DashboardLatestUpdatesComponent extends Component Date: Wed, 9 Aug 2023 16:19:25 -0400 Subject: [PATCH 09/14] WIP Pending test --- .../components/truncated-text-test.ts | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/web/tests/integration/components/truncated-text-test.ts b/web/tests/integration/components/truncated-text-test.ts index 7d8ca1f5a..69f57bead 100644 --- a/web/tests/integration/components/truncated-text-test.ts +++ b/web/tests/integration/components/truncated-text-test.ts @@ -3,11 +3,14 @@ import { setupRenderingTest } from "ember-qunit"; import { find, render } from "@ember/test-helpers"; import { hbs } from "ember-cli-htmlbars"; import { assert as emberAssert } from "@ember/debug"; +import window from "ember-window-mock"; +import { setupWindowMock } from "ember-window-mock/test-support"; const CONTAINER_SELECTOR = ".truncated-text-container"; module("Integration | Component | truncated-text", function (hooks) { setupRenderingTest(hooks); + setupWindowMock(hooks); test("it truncates text", async function (assert) { await render(hbs` @@ -18,8 +21,6 @@ module("Integration | Component | truncated-text", function (hooks) {
    `); - // TODO: Take Percy screenshot - //

    tag is used if no `tagName` is provided const container = find(`p${CONTAINER_SELECTOR}`); const text = find(`${CONTAINER_SELECTOR} > span`); @@ -43,29 +44,45 @@ module("Integration | Component | truncated-text", function (hooks) { assert.equal(textFontSize, "28px"); }); - test("it truncates text with a custom tag", async function (assert) { + test("it can truncate starting at a specific endpoint", async function (assert) { await render(hbs`

    - + This is a very long text that should be truncated
    `); - assert.dom(`h1${CONTAINER_SELECTOR}`).exists("renders a custom tag"); + //

    tag is used if no `tagName` is provided + const container = find(`p${CONTAINER_SELECTOR}`) as HTMLElement; + const text = find(`${CONTAINER_SELECTOR} > span`) as HTMLElement; + + let containerWidth = container.offsetWidth; + let textWidth = text.offsetWidth; + + assert.equal(containerWidth, 275); + assert.true(containerWidth < textWidth); + + // TODO: Get this working + + // @ts-ignore + window.screen.width = "200px"; + + containerWidth = container.offsetWidth; + textWidth = text.offsetWidth; + + assert.true(containerWidth > textWidth); }); - test("it truncates text with a custom breakpoint", async function (assert) { + test("it truncates text with a custom tag", async function (assert) { await render(hbs`

    - + This is a very long text that should be truncated
    `); - assert.true(true, "TODO: implement this test"); - - // TODO: use ember-window-mock to set the breakpoint to md + assert.dom(`h1${CONTAINER_SELECTOR}`).exists("renders a custom tag"); }); }); From 1f3c1a61caa1ae5dececb70fe27f033170b1df15 Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Wed, 9 Aug 2023 17:20:59 -0400 Subject: [PATCH 10/14] Test breakpoint class --- web/app/components/truncated-text.ts | 2 +- web/app/styles/app.scss | 7 ++++--- web/app/styles/hermes/variables | 0 web/app/styles/typography.scss | 14 ++++++++----- web/app/styles/variables.scss | 6 ++++++ .../components/truncated-text-test.ts | 20 +------------------ 6 files changed, 21 insertions(+), 28 deletions(-) create mode 100644 web/app/styles/hermes/variables create mode 100644 web/app/styles/variables.scss diff --git a/web/app/components/truncated-text.ts b/web/app/components/truncated-text.ts index 28aff6c24..1222e7950 100644 --- a/web/app/components/truncated-text.ts +++ b/web/app/components/truncated-text.ts @@ -14,7 +14,7 @@ interface TruncatedTextComponentSignature { export default class TruncatedTextComponent extends Component { protected get class(): string { if (this.args.startingBreakpoint === "md") { - return "starting-md"; + return "starting-breakpoint-md"; } return "default"; } diff --git a/web/app/styles/app.scss b/web/app/styles/app.scss index d086ff9e0..70b665eb4 100644 --- a/web/app/styles/app.scss +++ b/web/app/styles/app.scss @@ -1,9 +1,10 @@ @use "@hashicorp/design-system-components"; +@use "./variables"; + @use "./animations"; @use "./typography"; - @use "components/action"; @use "components/toolbar"; @use "components/tooltip"; @@ -86,11 +87,11 @@ ol { } .x-container { - @apply w-full max-w-screen-lg mx-auto px-8; + @apply mx-auto w-full max-w-screen-lg px-8; } h1 { - @apply text-display-500 font-bold text-color-foreground-strong mb-1.5; + @apply mb-1.5 text-display-500 font-bold text-color-foreground-strong; + p { @apply text-body-300; diff --git a/web/app/styles/hermes/variables b/web/app/styles/hermes/variables new file mode 100644 index 000000000..e69de29bb diff --git a/web/app/styles/typography.scss b/web/app/styles/typography.scss index f12cfdf9d..6a73424e2 100644 --- a/web/app/styles/typography.scss +++ b/web/app/styles/typography.scss @@ -1,5 +1,7 @@ +@use "variables" as v; + .hermes-form-label { - @apply text-body-200 font-semibold flex text-color-foreground-strong; + @apply flex text-body-200 font-semibold text-color-foreground-strong; + .hermes-form-helper-text { @apply mt-1; @@ -11,11 +13,11 @@ } .hermes-h4 { - @apply text-color-foreground-faint uppercase tracking-wide font-medium text-body-100; + @apply text-body-100 font-medium uppercase tracking-wide text-color-foreground-faint; } .truncated-text-container { - @apply block font-regular text-body-100 text-color-foreground-faint; + @apply block text-body-100 font-regular text-color-foreground-faint; // These classes are applied by the TruncatedText component // based on its optional `startingBreakpoint` argument: @@ -24,7 +26,9 @@ @apply truncate; } - &.starting-md { - @apply md:truncate; + &.starting-breakpoint-md { + @media (min-width: v.$screen-md) { + @apply truncate; + } } } diff --git a/web/app/styles/variables.scss b/web/app/styles/variables.scss new file mode 100644 index 000000000..3326f59eb --- /dev/null +++ b/web/app/styles/variables.scss @@ -0,0 +1,6 @@ +// Breakpoints +$screen-sm: 640px; +$screen-md: 768px; +$screen-lg: 1024px; +$screen-xl: 1280px; +$screen-2xl: 1536px; diff --git a/web/tests/integration/components/truncated-text-test.ts b/web/tests/integration/components/truncated-text-test.ts index 69f57bead..b5241e046 100644 --- a/web/tests/integration/components/truncated-text-test.ts +++ b/web/tests/integration/components/truncated-text-test.ts @@ -53,25 +53,7 @@ module("Integration | Component | truncated-text", function (hooks) {
    `); - //

    tag is used if no `tagName` is provided - const container = find(`p${CONTAINER_SELECTOR}`) as HTMLElement; - const text = find(`${CONTAINER_SELECTOR} > span`) as HTMLElement; - - let containerWidth = container.offsetWidth; - let textWidth = text.offsetWidth; - - assert.equal(containerWidth, 275); - assert.true(containerWidth < textWidth); - - // TODO: Get this working - - // @ts-ignore - window.screen.width = "200px"; - - containerWidth = container.offsetWidth; - textWidth = text.offsetWidth; - - assert.true(containerWidth > textWidth); + assert.dom(CONTAINER_SELECTOR).hasClass("starting-breakpoint-md"); }); test("it truncates text with a custom tag", async function (assert) { From aeed54e1d8450b49461f96ea5324196bd2af2941 Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Wed, 9 Aug 2023 19:49:16 -0400 Subject: [PATCH 11/14] Type cleanup --- web/app/routes/authenticated/dashboard.ts | 7 +++---- web/app/templates/authenticated/dashboard.hbs | 12 ++++++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/web/app/routes/authenticated/dashboard.ts b/web/app/routes/authenticated/dashboard.ts index 918e75c90..0b4eef039 100644 --- a/web/app/routes/authenticated/dashboard.ts +++ b/web/app/routes/authenticated/dashboard.ts @@ -9,6 +9,7 @@ import AuthenticatedUserService from "hermes/services/authenticated-user"; // @ts-ignore - Not yet typed import timeAgo from "hermes/utils/time-ago"; +import { HermesDocument } from "hermes/types/document"; export default class DashboardRoute extends Route { @service declare algolia: AlgoliaService; @@ -19,7 +20,7 @@ export default class DashboardRoute extends Route { @service declare session: SessionService; @service declare authenticatedUser: AuthenticatedUserService; - async model() { + async model(): Promise { const userInfo = this.authenticatedUser.info; const docsAwaitingReview = await this.algolia.searchIndex @@ -34,12 +35,10 @@ export default class DashboardRoute extends Route { .then((result) => { // Add modifiedAgo for each doc. for (const hit of result.hits) { - console.log("shit", hit); this.fetchSvc .fetch("/api/v1/documents/" + hit.objectID) .then((resp) => resp?.json()) .then((doc) => { - console.log("doc"); if (doc.modifiedTime) { const modifiedDate = new Date(doc.modifiedTime * 1000); // @ts-ignore @@ -53,7 +52,7 @@ export default class DashboardRoute extends Route { ); }); } - return result.hits; + return result.hits as HermesDocument[]; }); try { diff --git a/web/app/templates/authenticated/dashboard.hbs b/web/app/templates/authenticated/dashboard.hbs index 0919e9d87..60c71cf87 100644 --- a/web/app/templates/authenticated/dashboard.hbs +++ b/web/app/templates/authenticated/dashboard.hbs @@ -11,10 +11,14 @@ {{this.authenticatedUser.info.given_name}}! + {{#if @model}} + + {{/if}} +

    -
    +

    {{else if (eq this.recentDocs.all null)}}
    -

    +

    Error fetching documents.

    -
    +
    From d17813ba5019fe63c16e4c06c6e59cd886c52456 Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Tue, 15 Aug 2023 10:23:18 -0400 Subject: [PATCH 12/14] Add and test truncation/collapse toggling --- .../dashboard/docs-awaiting-review.hbs | 35 +++++++++---- .../dashboard/docs-awaiting-review.ts | 40 ++++++++++++++- web/app/styles/hds-overrides.scss | 14 +++--- .../dashboard/docs-awaiting-review-test.ts | 50 ++++++++++++++++++- 4 files changed, 121 insertions(+), 18 deletions(-) diff --git a/web/app/components/dashboard/docs-awaiting-review.hbs b/web/app/components/dashboard/docs-awaiting-review.hbs index 555182a22..08636387c 100644 --- a/web/app/components/dashboard/docs-awaiting-review.hbs +++ b/web/app/components/dashboard/docs-awaiting-review.hbs @@ -1,19 +1,36 @@ -
    -
    -

    +
    +
    +

    You have - - {{@docs.length}} - + document{{if (gt @docs.length 1) "s"}} awaiting your review:

    +
    -
      - {{#each @docs as |doc|}} +
        + {{#each this.docsToShow as |doc|}} {{/each}} -
      + {{#if this.toggleButtonIsShown}} + + + {{if this.isCollapsed "Show all" "Show fewer"}} + + {{/if}}
    diff --git a/web/app/components/dashboard/docs-awaiting-review.ts b/web/app/components/dashboard/docs-awaiting-review.ts index 0c3600a22..4f6901c77 100644 --- a/web/app/components/dashboard/docs-awaiting-review.ts +++ b/web/app/components/dashboard/docs-awaiting-review.ts @@ -1,4 +1,6 @@ +import { action } from "@ember/object"; import Component from "@glimmer/component"; +import { tracked } from "@glimmer/tracking"; import { HermesDocument } from "hermes/types/document"; interface DashboardDocsAwaitingReviewComponentSignature { @@ -11,7 +13,43 @@ interface DashboardDocsAwaitingReviewComponentSignature { }; } -export default class DashboardDocsAwaitingReviewComponent extends Component {} +export default class DashboardDocsAwaitingReviewComponent extends Component { + /** + * Whether the list is considered collapsed. Determines which docs to show, + * as well as the text and icon of the toggle button. + */ + @tracked protected isCollapsed = true; + + /** + * (Up to) the first four docs. The default documents shown. + */ + private get firstFourDocs() { + return this.args.docs.slice(0, 4); + } + + /** + * Whether the toggle button should be shown. + * True if there are more than four docs. + */ + protected get toggleButtonIsShown() { + return this.args.docs.length > 4; + } + + /** + * The docs to show in the list. If the list is collapsed, + * we show the first four docs. Otherwise, we show all docs. + */ + protected get docsToShow() { + return this.isCollapsed ? this.firstFourDocs : this.args.docs; + } + + /** + * The action to take when the toggle button is clicked. + */ + @action protected toggleCollapsed() { + this.isCollapsed = !this.isCollapsed; + } +} declare module "@glint/environment-ember-loose/registry" { export default interface Registry { diff --git a/web/app/styles/hds-overrides.scss b/web/app/styles/hds-overrides.scss index bdded5efb..90b9bec04 100644 --- a/web/app/styles/hds-overrides.scss +++ b/web/app/styles/hds-overrides.scss @@ -40,13 +40,13 @@ } .badge-count-highlight { - @apply border-transparent rounded-l-full rounded-r-full bg-color-surface-highlight relative text-color-foreground-highlight text-body-200 inline-flex; + @apply relative inline-flex rounded-l-full rounded-r-full border-transparent bg-color-foreground-faint text-body-200 text-color-page-primary; - @apply px-2 mx-0.5; - @apply md:px-3 md:py-[2px] md:mx-1.5; + @apply mx-0.5 px-2; + @apply md:mx-1.5 md:px-2.5 md:py-[1px]; - &::before { - content: ""; - @apply absolute -left-px -top-px -right-px -bottom-px rounded-l-full rounded-r-full border border-color-foreground-highlight opacity-60; - } + // &::before { + // content: ""; + // @apply absolute -left-px -top-px -right-px -bottom-px rounded-l-full rounded-r-full border border-color-foreground-highlight opacity-60; + // } } diff --git a/web/tests/integration/components/dashboard/docs-awaiting-review-test.ts b/web/tests/integration/components/dashboard/docs-awaiting-review-test.ts index a10a614c3..c27646a48 100644 --- a/web/tests/integration/components/dashboard/docs-awaiting-review-test.ts +++ b/web/tests/integration/components/dashboard/docs-awaiting-review-test.ts @@ -1,7 +1,7 @@ import { module, test } from "qunit"; import { setupRenderingTest } from "ember-qunit"; import { MirageTestContext, setupMirage } from "ember-cli-mirage/test-support"; -import { render } from "@ember/test-helpers"; +import { click, render } from "@ember/test-helpers"; import { hbs } from "ember-cli-htmlbars"; import { HermesDocument } from "hermes/types/document"; @@ -11,6 +11,10 @@ const DOCS_AWAITING_REVIEW_COUNT_SELECTOR = const DOC_AWAITING_REVIEW_LINK_SELECTOR = "[data-test-doc-awaiting-review-link]"; +const TOGGLE_SELECTOR = "[data-test-docs-awaiting-review-toggle]"; + +const TOGGLE_ICON = "[data-test-docs-awaiting-review-toggle-icon]"; + interface DashboardDocsAwaitingReviewTestContext extends MirageTestContext { docs: HermesDocument[]; } @@ -52,5 +56,49 @@ module( assert.dom("h2").containsText("document awaiting your review"); }); + + test("it shows a toggle button when there are more than 4 docs awaiting review", async function (this: DashboardDocsAwaitingReviewTestContext, assert) { + const docTitles = ["Foo", "Bar", "Baz", "Oof", "Zab"]; + + docTitles.forEach((title) => { + this.server.create("document", { + title, + status: "In Review", + approvers: ["testuser@example.com"], + }); + }); + + this.set("docs", this.server.schema.document.all().models); + + await render( + hbs`` + ); + + assert.dom(DOCS_AWAITING_REVIEW_COUNT_SELECTOR).containsText("5"); + assert.dom(DOC_AWAITING_REVIEW_LINK_SELECTOR).exists({ count: 4 }); + + assert.dom(TOGGLE_SELECTOR).hasText("Show all"); + assert.dom(TOGGLE_ICON).hasAttribute("data-test-icon", "plus"); + + await click(TOGGLE_SELECTOR); + + assert.dom(TOGGLE_SELECTOR).hasText("Show fewer"); + assert.dom(TOGGLE_ICON).hasAttribute("data-test-icon", "minus"); + + assert.dom(DOC_AWAITING_REVIEW_LINK_SELECTOR).exists({ count: 5 }); + + await click(TOGGLE_SELECTOR); + + assert.dom(TOGGLE_SELECTOR).hasText("Show all"); + assert.dom(TOGGLE_ICON).hasAttribute("data-test-icon", "plus"); + assert.dom(DOC_AWAITING_REVIEW_LINK_SELECTOR).exists({ count: 4 }); + + // Set the count to 1 to remove the need for the toggle + this.set("docs", [this.server.schema.document.first()]); + + assert + .dom(TOGGLE_SELECTOR) + .doesNotExist("toggle not shown when there's fewer than 4 docs"); + }); } ); From 8b09606e82e82936f0bdfad6327ae84994524207 Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Tue, 15 Aug 2023 10:23:44 -0400 Subject: [PATCH 13/14] Remove unused class --- web/app/styles/hds-overrides.scss | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/web/app/styles/hds-overrides.scss b/web/app/styles/hds-overrides.scss index 90b9bec04..b64d0ff37 100644 --- a/web/app/styles/hds-overrides.scss +++ b/web/app/styles/hds-overrides.scss @@ -38,15 +38,3 @@ @apply absolute right-1.5 top-1/2 -translate-y-1/2; } } - -.badge-count-highlight { - @apply relative inline-flex rounded-l-full rounded-r-full border-transparent bg-color-foreground-faint text-body-200 text-color-page-primary; - - @apply mx-0.5 px-2; - @apply md:mx-1.5 md:px-2.5 md:py-[1px]; - - // &::before { - // content: ""; - // @apply absolute -left-px -top-px -right-px -bottom-px rounded-l-full rounded-r-full border border-color-foreground-highlight opacity-60; - // } -} From 1023f5ab7116fe3ec0735d30656ae75e1d1bc9d6 Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Tue, 15 Aug 2023 10:50:36 -0400 Subject: [PATCH 14/14] Remove 4-item limit from Algolia request --- web/app/components/dashboard/docs-awaiting-review.hbs | 4 ++-- web/app/routes/authenticated/dashboard.ts | 1 - web/tests/acceptance/application-test.ts | 10 ---------- 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/web/app/components/dashboard/docs-awaiting-review.hbs b/web/app/components/dashboard/docs-awaiting-review.hbs index 08636387c..23b8055a9 100644 --- a/web/app/components/dashboard/docs-awaiting-review.hbs +++ b/web/app/components/dashboard/docs-awaiting-review.hbs @@ -1,12 +1,12 @@
    -

    +

    You have document{{if (gt @docs.length 1) "s"}} awaiting your review: diff --git a/web/app/routes/authenticated/dashboard.ts b/web/app/routes/authenticated/dashboard.ts index 0b4eef039..77b944963 100644 --- a/web/app/routes/authenticated/dashboard.ts +++ b/web/app/routes/authenticated/dashboard.ts @@ -30,7 +30,6 @@ export default class DashboardRoute extends Route { ` AND NOT approvedBy:'${userInfo.email}'` + " AND appCreated:true" + " AND status:In-Review", - hitsPerPage: 4, }) .then((result) => { // Add modifiedAgo for each doc. diff --git a/web/tests/acceptance/application-test.ts b/web/tests/acceptance/application-test.ts index ac526e78f..1cb8f7937 100644 --- a/web/tests/acceptance/application-test.ts +++ b/web/tests/acceptance/application-test.ts @@ -150,15 +150,5 @@ module("Acceptance | application", function (hooks) { assert .dom("[data-test-user-menu-support") .hasAttribute("href", TEST_SUPPORT_URL); - - /** - * FIXME: Investigate unresolved promises - * - * For reasons not yet clear, this test has unresolved promises - * that prevent it from completing naturally. Because of this, - * we handle teardown manually. - * - */ - teardownContext(this); }); });