From 029c507b4e97b3d619e037956f7a50e6fd9faebf Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Wed, 1 Mar 2023 13:57:43 -0500 Subject: [PATCH 001/340] Basic prototype of document search --- web/app/components/inputs/document-select.hbs | 54 +++++++++++++++++++ web/app/components/inputs/document-select.ts | 51 ++++++++++++++++++ web/app/templates/authenticated/dashboard.hbs | 2 + 3 files changed, 107 insertions(+) create mode 100644 web/app/components/inputs/document-select.hbs create mode 100644 web/app/components/inputs/document-select.ts diff --git a/web/app/components/inputs/document-select.hbs b/web/app/components/inputs/document-select.hbs new file mode 100644 index 000000000..87508c1f5 --- /dev/null +++ b/web/app/components/inputs/document-select.hbs @@ -0,0 +1,54 @@ +{{! should search be scoped to the current product/area? }} + + <:default> + {{#if this.selectedDocument}} + {{this.selectedDocument.docNumber}} + {{this.selectedDocument.title}} + + + Remove + + {{else}} + Search PRDs + {{/if}} + + <:editing as |F|> + + {{! popover }} +
+ {{#if this.shownDocuments}} +
    + {{#each this.shownDocuments as |document|}} +
  • + + {{document.objectID}} + {{document.docNumber}} + {{document.title}} + {{document.product}} + +
  • + {{/each}} +
+ {{else}} +

+ {{if + this.userHasSearched + "No matches" + "Enter a title or document number" + }} +

+ {{/if}} +
+ + +
diff --git a/web/app/components/inputs/document-select.ts b/web/app/components/inputs/document-select.ts new file mode 100644 index 000000000..99047fc47 --- /dev/null +++ b/web/app/components/inputs/document-select.ts @@ -0,0 +1,51 @@ +import { action } from "@ember/object"; +import Component from "@glimmer/component"; +import { tracked } from "@glimmer/tracking"; +import { restartableTask } from "ember-concurrency"; +import { inject as service } from "@ember/service"; +import AlgoliaService from "hermes/services/algolia"; +import ConfigService from "hermes/services/config"; +import { HermesDocument } from "hermes/types/document"; + +interface InputsDocumentSelectSignature { + Args: { + productArea: string; + }; +} + +export default class InputsDocumentSelect extends Component { + @service declare algolia: AlgoliaService; + @service declare configSvc: ConfigService; + + @tracked shownDocuments: HermesDocument[] | null = null; + @tracked query = ""; + @tracked selectedDocument: HermesDocument | null = null; + + @action onChange(document: HermesDocument) { + this.selectedDocument = document; + } + + protected search = restartableTask(async (inputEvent: InputEvent) => { + const input = inputEvent.target as HTMLInputElement; + this.query = input.value; + + if (this.query === "") { + this.shownDocuments = null; + return; + } + + // can this be scoped to title searches? + // is there a need to search the body? + + let algoliaResponse = await this.algolia.search.perform(this.query, { + hitsPerPage: 5, + attributesToRetrieve: ["title", 'product', 'docNumber'], + // give extra ranking to docs in the same product area + optionalFilters: ["product:" + this.args.productArea], + }); + + if (algoliaResponse) { + this.shownDocuments = algoliaResponse.hits as HermesDocument[]; + } + }); +} diff --git a/web/app/templates/authenticated/dashboard.hbs b/web/app/templates/authenticated/dashboard.hbs index 8de3dffdd..9aa257a45 100644 --- a/web/app/templates/authenticated/dashboard.hbs +++ b/web/app/templates/authenticated/dashboard.hbs @@ -10,6 +10,8 @@ + + {{#if this.docsWaitingForReview}}
Date: Wed, 1 Mar 2023 15:37:46 -0500 Subject: [PATCH 002/340] Improved prototype --- web/app/components/document/sidebar.hbs | 12 +++++- web/app/components/document/sidebar.js | 16 +++++++- web/app/components/inputs/document-select.hbs | 39 +++++++++---------- web/app/components/inputs/document-select.ts | 20 ++++++---- web/app/templates/authenticated/dashboard.hbs | 2 - 5 files changed, 56 insertions(+), 33 deletions(-) diff --git a/web/app/components/document/sidebar.hbs b/web/app/components/document/sidebar.hbs index 1795d885a..27387bffa 100644 --- a/web/app/components/document/sidebar.hbs +++ b/web/app/components/document/sidebar.hbs @@ -308,6 +308,17 @@

{{@document.lastModified}}

+
+ + PRD + + +
+ {{#each-in this.customEditableFields as |field attributes|}} {{#if (or @@ -621,7 +632,6 @@ @onChange={{this.updateApprovers}} @disabled={{this.requestReview.isRunning}} class="mb-0" - /> Add approvers diff --git a/web/app/components/document/sidebar.js b/web/app/components/document/sidebar.js index 1127b2d0d..81d33d222 100644 --- a/web/app/components/document/sidebar.js +++ b/web/app/components/document/sidebar.js @@ -23,6 +23,19 @@ export default class DocumentSidebar extends Component { @tracked errorTitle = null; @tracked errorDescription = null; + @tracked linkedRFC = null; + + @task *saveLinkedRFC(rfc) { + this.linkedRFC = rfc; + if (this.linkedRFC) { + // FIXME: need the full URL + const rfcURL = `documents/${this.linkedRFC.objectID}`; + yield this.save.perform("prd", rfcURL); + } else { + yield this.save.perform("prd", null); + } + } + get modalContainer() { return document.querySelector(".ember-application"); } @@ -201,7 +214,6 @@ export default class DocumentSidebar extends Component { } } - @action refreshRoute() { // We force refresh due to a bug with `refreshModel: true` // See: https://github.com/emberjs/ember.js/issues/19260 @@ -210,7 +222,7 @@ export default class DocumentSidebar extends Component { @task *save(field, val) { - if (field && val) { + if (field) { const oldVal = this[field]; this[field] = val; diff --git a/web/app/components/inputs/document-select.hbs b/web/app/components/inputs/document-select.hbs index 87508c1f5..9de8f95cb 100644 --- a/web/app/components/inputs/document-select.hbs +++ b/web/app/components/inputs/document-select.hbs @@ -1,20 +1,25 @@ -{{! should search be scoped to the current product/area? }} - <:default> - {{#if this.selectedDocument}} - {{this.selectedDocument.docNumber}} - {{this.selectedDocument.title}} + <:default as |F|> + {{#if @selectedDocument}} + + {{@selectedDocument.title}} + - + Remove {{else}} - Search PRDs + {{/if}} <:editing as |F|> @@ -24,29 +29,21 @@ type="text" placeholder="Search PRDs" /> - {{! popover }} -
+ {{! TODO: add dismissible modifier }} +
{{#if this.shownDocuments}}
    {{#each this.shownDocuments as |document|}}
  • - {{document.objectID}} {{document.docNumber}} {{document.title}} - {{document.product}}
  • {{/each}}
- {{else}} -

- {{if - this.userHasSearched - "No matches" - "Enter a title or document number" - }} -

+ {{else if this.userHasSearched}} +

No matches

{{/if}}
diff --git a/web/app/components/inputs/document-select.ts b/web/app/components/inputs/document-select.ts index 99047fc47..2da8a9b46 100644 --- a/web/app/components/inputs/document-select.ts +++ b/web/app/components/inputs/document-select.ts @@ -10,6 +10,8 @@ import { HermesDocument } from "hermes/types/document"; interface InputsDocumentSelectSignature { Args: { productArea: string; + selectedDocument: HermesDocument | null; + onChange: (document: HermesDocument | null) => void; }; } @@ -19,10 +21,17 @@ export default class InputsDocumentSelect extends Component { @@ -34,12 +43,9 @@ export default class InputsDocumentSelect extends Component - - {{#if this.docsWaitingForReview}}
Date: Fri, 3 Mar 2023 13:59:29 -0500 Subject: [PATCH 003/340] Fix "remove" function --- web/app/components/document/sidebar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/app/components/document/sidebar.js b/web/app/components/document/sidebar.js index 81d33d222..f5c672322 100644 --- a/web/app/components/document/sidebar.js +++ b/web/app/components/document/sidebar.js @@ -32,7 +32,7 @@ export default class DocumentSidebar extends Component { const rfcURL = `documents/${this.linkedRFC.objectID}`; yield this.save.perform("prd", rfcURL); } else { - yield this.save.perform("prd", null); + yield this.save.perform("prd", ""); } } From 3f43b177477a15ff9a4addf5ba725fad315d56f4 Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Wed, 15 Mar 2023 11:29:11 -0400 Subject: [PATCH 004/340] Set up Grass route --- web/app/components/document/sidebar.hbs | 11 ----------- web/app/components/inputs/document-select.hbs | 6 ++++-- web/app/router.js | 1 + web/app/routes/grass.ts | 12 ++++++++++++ web/app/templates/grass.hbs | 14 ++++++++++++++ 5 files changed, 31 insertions(+), 13 deletions(-) create mode 100644 web/app/routes/grass.ts create mode 100644 web/app/templates/grass.hbs diff --git a/web/app/components/document/sidebar.hbs b/web/app/components/document/sidebar.hbs index 886752a5d..7191ab257 100644 --- a/web/app/components/document/sidebar.hbs +++ b/web/app/components/document/sidebar.hbs @@ -306,17 +306,6 @@

{{@document.lastModified}}

-
- - PRD - - -
- {{#each-in this.customEditableFields as |field attributes|}} {{#if (or diff --git a/web/app/components/inputs/document-select.hbs b/web/app/components/inputs/document-select.hbs index 9de8f95cb..63f50f02f 100644 --- a/web/app/components/inputs/document-select.hbs +++ b/web/app/components/inputs/document-select.hbs @@ -12,14 +12,16 @@ @model={{@selectedDocument.objectID}} class="flex" > - {{@selectedDocument.title}} + {{@selectedDocument.title}} Remove {{else}} - + + Search docs or enter a URL... + {{/if}} <:editing as |F|> diff --git a/web/app/router.js b/web/app/router.js index e1dfa25e0..bfd4b1c9b 100644 --- a/web/app/router.js +++ b/web/app/router.js @@ -20,4 +20,5 @@ Router.map(function () { }); }); this.route("authenticate"); + this.route("grass"); }); diff --git a/web/app/routes/grass.ts b/web/app/routes/grass.ts new file mode 100644 index 000000000..8f6f0d867 --- /dev/null +++ b/web/app/routes/grass.ts @@ -0,0 +1,12 @@ +import { action } from "@ember/object"; +import Route from "@ember/routing/route"; +import { tracked } from "@glimmer/tracking"; +import { HermesDocument } from "hermes/types/document"; + +export default class GrassRoute extends Route { + @tracked linkedDocument: HermesDocument | null = null; + + @action noop() { + return; + } +} diff --git a/web/app/templates/grass.hbs b/web/app/templates/grass.hbs new file mode 100644 index 000000000..46fc7f474 --- /dev/null +++ b/web/app/templates/grass.hbs @@ -0,0 +1,14 @@ +{{page-title "Grass"}} + +
+
+
+ Related resources +
+ +
+
From 4d0aefbe2b1e9c4140e32fb7b53c076e073a9c75 Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Wed, 15 Mar 2023 16:00:15 -0400 Subject: [PATCH 005/340] Basic "add a URL" function --- web/app/components/inputs/document-select.hbs | 6 +- web/app/controllers/grass.ts | 53 ++++++++++++++++++ web/app/routes/grass.ts | 11 +--- web/app/styles/app.scss | 1 + web/app/styles/grass.scss | 21 +++++++ web/app/templates/grass.hbs | 56 ++++++++++++++++--- web/tailwind.config.js | 3 + 7 files changed, 128 insertions(+), 23 deletions(-) create mode 100644 web/app/controllers/grass.ts create mode 100644 web/app/styles/grass.scss diff --git a/web/app/components/inputs/document-select.hbs b/web/app/components/inputs/document-select.hbs index 63f50f02f..9de8f95cb 100644 --- a/web/app/components/inputs/document-select.hbs +++ b/web/app/components/inputs/document-select.hbs @@ -12,16 +12,14 @@ @model={{@selectedDocument.objectID}} class="flex" > - {{@selectedDocument.title}} + {{@selectedDocument.title}} Remove {{else}} - - Search docs or enter a URL... - + {{/if}} <:editing as |F|> diff --git a/web/app/controllers/grass.ts b/web/app/controllers/grass.ts new file mode 100644 index 000000000..52e187e22 --- /dev/null +++ b/web/app/controllers/grass.ts @@ -0,0 +1,53 @@ +import { A } from "@ember/array"; +import NativeArray from "@ember/array/-private/native-array"; +import Controller from "@ember/controller"; +import { action } from "@ember/object"; +import { tracked } from "@glimmer/tracking"; +import { restartableTask } from "ember-concurrency"; + +export default class GrassController extends Controller { + @tracked relatedResources = A(); + + @tracked inputValue = ""; + + @tracked inputValueIsValid = false; + + get searchButtonIsShown() { + return this.inputValue.length === 0; + } + + checkURL = restartableTask(async () => { + const url = this.inputValue; + try { + this.inputValueIsValid = Boolean(new URL(url)); + } catch (e) { + this.inputValueIsValid = false; + } + }); + + @action addResource() { + this.relatedResources.pushObject(this.inputValue); + this.clearSearch(); + } + + @action noop() { + return; + } + + @action onKeydown(event: KeyboardEvent) { + if (event.key === "Enter") { + if (this.inputValueIsValid) { + this.addResource(); + } + } + } + + @action onInput(event: Event) { + this.inputValue = (event.target as HTMLInputElement).value; + this.checkURL.perform(); + } + + @action clearSearch() { + this.inputValue = ""; + } +} diff --git a/web/app/routes/grass.ts b/web/app/routes/grass.ts index 8f6f0d867..e06b46b06 100644 --- a/web/app/routes/grass.ts +++ b/web/app/routes/grass.ts @@ -1,12 +1,3 @@ -import { action } from "@ember/object"; import Route from "@ember/routing/route"; -import { tracked } from "@glimmer/tracking"; -import { HermesDocument } from "hermes/types/document"; -export default class GrassRoute extends Route { - @tracked linkedDocument: HermesDocument | null = null; - - @action noop() { - return; - } -} +export default class GrassRoute extends Route {} diff --git a/web/app/styles/app.scss b/web/app/styles/app.scss index e3f2cf52f..30caf1519 100644 --- a/web/app/styles/app.scss +++ b/web/app/styles/app.scss @@ -26,6 +26,7 @@ @use "@hashicorp/design-system-components"; @use "./hds-overrides"; +@use "./grass"; @use "tailwindcss/base"; @use "tailwindcss/components"; diff --git a/web/app/styles/grass.scss b/web/app/styles/grass.scss new file mode 100644 index 000000000..3b4d729ad --- /dev/null +++ b/web/app/styles/grass.scss @@ -0,0 +1,21 @@ +.grass { + .related-resources-button { + @apply h-full rounded-[3px] px-2 border border-transparent items-center flex justify-center; + + &.primary { + @apply bg-color-foreground-action text-color-foreground-high-contrast; + } + + &:disabled { + @apply bg-alpha-200 text-color-foreground-faint; + } + + &:hover { + @apply border-color-border-strong; + } + } +} + +.clear-input-button { + @apply text-color-foreground-faint px-1 flex items-center mr-1; +} diff --git a/web/app/templates/grass.hbs b/web/app/templates/grass.hbs index 46fc7f474..36ca3fbc2 100644 --- a/web/app/templates/grass.hbs +++ b/web/app/templates/grass.hbs @@ -1,14 +1,52 @@ {{page-title "Grass"}} +{{set-body-class "grass"}} -
-
-
- Related resources -
- +
+ Related resources +
+
+ + +
+ {{#if this.searchButtonIsShown}} + + + + + {{else}} +
+ {{! REMEMBER: mostly this will be pasted }} + + + + + + + Add + +
+ + {{/if}} +
+ +{{log}} + +{{#each this.relatedResources as |resource|}} + {{resource}} ❎ +{{/each}} diff --git a/web/tailwind.config.js b/web/tailwind.config.js index bdba0badc..ebdde4a0d 100644 --- a/web/tailwind.config.js +++ b/web/tailwind.config.js @@ -164,6 +164,9 @@ module.exports = { "color-palette-neutral-600": "var(--token-color-palette-neutral-600)", "color-palette-neutral-700": "var(--token-color-palette-neutral-700)", + // Alpha + "alpha-200": "var(--token-color-palette-alpha-200)", + // Non-Semantic Color "color-palette-blue-200": "var(--token-color-palette-blue-200)", "color-palette-green-200": "var(--token-color-palette-green-200)", From 8e907475cfb24708f4ca2f33fec402339d08ab5d Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Thu, 16 Mar 2023 11:28:33 -0400 Subject: [PATCH 006/340] Design tweaks --- web/app/controllers/grass.ts | 84 +++++++++++++++++++++++++++++------- web/app/styles/grass.scss | 4 -- web/app/templates/grass.hbs | 61 +++++++++++++++++++++++--- 3 files changed, 124 insertions(+), 25 deletions(-) diff --git a/web/app/controllers/grass.ts b/web/app/controllers/grass.ts index 52e187e22..2cfaa831a 100644 --- a/web/app/controllers/grass.ts +++ b/web/app/controllers/grass.ts @@ -3,42 +3,64 @@ import NativeArray from "@ember/array/-private/native-array"; import Controller from "@ember/controller"; import { action } from "@ember/object"; import { tracked } from "@glimmer/tracking"; +import { inject as service } from "@ember/service"; +import AlgoliaService from "hermes/services/algolia"; +import { HermesDocument } from "hermes/types/document"; + import { restartableTask } from "ember-concurrency"; export default class GrassController extends Controller { + @service declare algolia: AlgoliaService; + @tracked relatedResources = A(); @tracked inputValue = ""; + @tracked query = ""; @tracked inputValueIsValid = false; + @tracked popoverIsShown = false; + @tracked popoverTrigger: HTMLElement | null = null; + @tracked shownDocuments: HermesDocument[] | null = null; + + @tracked searchInput: HTMLInputElement | null = null; get searchButtonIsShown() { return this.inputValue.length === 0; } - checkURL = restartableTask(async () => { - const url = this.inputValue; - try { - this.inputValueIsValid = Boolean(new URL(url)); - } catch (e) { - this.inputValueIsValid = false; + @action maybeAddResource() { + if (!this.inputValueIsValid) { + alert("invalid url"); + } else { + this.relatedResources.pushObject(this.inputValue); + this.clearSearch(); } - }); + } + + @action togglePopover() { + this.popoverIsShown = !this.popoverIsShown; + } + + @action hidePopover() { + this.popoverIsShown = false; + } - @action addResource() { - this.relatedResources.pushObject(this.inputValue); - this.clearSearch(); + @action registerPopoverTrigger(e: HTMLElement) { + this.popoverTrigger = e; } - @action noop() { - return; + @action registerAndFocusSearchInput(e: HTMLInputElement) { + this.searchInput = e; + this.searchInput.focus(); } @action onKeydown(event: KeyboardEvent) { if (event.key === "Enter") { - if (this.inputValueIsValid) { - this.addResource(); - } + this.maybeAddResource(); + } + + if (event.key === "Escape") { + this.clearSearch(); } } @@ -50,4 +72,36 @@ export default class GrassController extends Controller { @action clearSearch() { this.inputValue = ""; } + + protected search = restartableTask(async (inputEvent: InputEvent) => { + const input = inputEvent.target as HTMLInputElement; + this.query = input.value; + + if (this.query === "") { + this.shownDocuments = null; + return; + } + + let algoliaResponse = await this.algolia.search.perform(this.query, { + hitsPerPage: 5, + attributesToRetrieve: ["title", "product", "docNumber"], + // give extra ranking to docs in the same product area + // optionalFilters: ["product:" + this.args.productArea], + }); + + if (algoliaResponse) { + this.shownDocuments = algoliaResponse.hits as HermesDocument[]; + } + }); + + + protected checkURL = restartableTask(async () => { + const url = this.inputValue; + try { + this.inputValueIsValid = Boolean(new URL(url)); + } catch (e) { + this.inputValueIsValid = false; + } + }); + } diff --git a/web/app/styles/grass.scss b/web/app/styles/grass.scss index 3b4d729ad..b7b7087c9 100644 --- a/web/app/styles/grass.scss +++ b/web/app/styles/grass.scss @@ -6,10 +6,6 @@ @apply bg-color-foreground-action text-color-foreground-high-contrast; } - &:disabled { - @apply bg-alpha-200 text-color-foreground-faint; - } - &:hover { @apply border-color-border-strong; } diff --git a/web/app/templates/grass.hbs b/web/app/templates/grass.hbs index 36ca3fbc2..6317f5061 100644 --- a/web/app/templates/grass.hbs +++ b/web/app/templates/grass.hbs @@ -3,10 +3,9 @@
- Related resources + Related docs
- + {{#if (and this.searchButtonIsShown this.popoverIsShown)}} +
+
+ +
+
+ {{#if this.shownDocuments}} +
    + {{#each this.shownDocuments as |d|}} +
  • + + + +
  • + {{/each}} +
+ {{else if this.userHasSearched}} +

No matches

+ {{else}} + Recent docs in "Consul" +
list of docs. + {{/if}} +
+
+ {{/if}}
{{#if this.searchButtonIsShown}} - + Add @@ -48,5 +94,8 @@ {{log}} {{#each this.relatedResources as |resource|}} - {{resource}} ❎ + {{! either linkTos or external links }} + {{resource}} + {{! button to delete it from the document }} + ❎ {{/each}} From ca9dd51a925df193ee52c41caca85bbeb1477063 Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Thu, 16 Mar 2023 13:53:50 -0400 Subject: [PATCH 007/340] Smarter reactions to input --- .../components/inputs/document-select1.hbs | 94 +++++++++++++++ .../inputs/document-select1.ts} | 9 +- .../components/inputs/document-select2.hbs | 66 ++++++++++ web/app/components/inputs/document-select2.ts | 113 ++++++++++++++++++ web/app/templates/grass.hbs | 99 +-------------- 5 files changed, 281 insertions(+), 100 deletions(-) create mode 100644 web/app/components/inputs/document-select1.hbs rename web/app/{controllers/grass.ts => components/inputs/document-select1.ts} (92%) create mode 100644 web/app/components/inputs/document-select2.hbs create mode 100644 web/app/components/inputs/document-select2.ts diff --git a/web/app/components/inputs/document-select1.hbs b/web/app/components/inputs/document-select1.hbs new file mode 100644 index 000000000..3614efbb5 --- /dev/null +++ b/web/app/components/inputs/document-select1.hbs @@ -0,0 +1,94 @@ +
+ Related docs +
+
+ + {{#if (and this.searchButtonIsShown this.popoverIsShown)}} +
+
+ +
+
+ {{#if this.shownDocuments}} +
    + {{#each this.shownDocuments as |d|}} +
  • + + + +
  • + {{/each}} +
+ {{else if this.userHasSearched}} +

No matches

+ {{else}} + Recent docs in "Consul" +
list of docs. + {{/if}} +
+
+ {{/if}} +
+ {{#if this.searchButtonIsShown}} + + + + + {{else}} +
+ {{! REMEMBER: mostly this will be pasted }} + + + + + + + Add + +
+ + {{/if}} +
+
+ +{{#each this.relatedResources as |resource|}} + {{! either linkTos or external links }} + {{resource}} + {{! button to delete it from the document }} + ❎ +{{/each}} diff --git a/web/app/controllers/grass.ts b/web/app/components/inputs/document-select1.ts similarity index 92% rename from web/app/controllers/grass.ts rename to web/app/components/inputs/document-select1.ts index 2cfaa831a..0d7a2c585 100644 --- a/web/app/controllers/grass.ts +++ b/web/app/components/inputs/document-select1.ts @@ -1,6 +1,5 @@ +import Component from "@glimmer/component"; import { A } from "@ember/array"; -import NativeArray from "@ember/array/-private/native-array"; -import Controller from "@ember/controller"; import { action } from "@ember/object"; import { tracked } from "@glimmer/tracking"; import { inject as service } from "@ember/service"; @@ -8,8 +7,11 @@ import AlgoliaService from "hermes/services/algolia"; import { HermesDocument } from "hermes/types/document"; import { restartableTask } from "ember-concurrency"; +interface InputsDocumentSelect1ComponentSignature { + Args: {}; +} -export default class GrassController extends Controller { +export default class InputsDocumentSelect1Component extends Component { @service declare algolia: AlgoliaService; @tracked relatedResources = A(); @@ -103,5 +105,4 @@ export default class GrassController extends Controller { this.inputValueIsValid = false; } }); - } diff --git a/web/app/components/inputs/document-select2.hbs b/web/app/components/inputs/document-select2.hbs new file mode 100644 index 000000000..441279dff --- /dev/null +++ b/web/app/components/inputs/document-select2.hbs @@ -0,0 +1,66 @@ +
+ Related docs +
+
+ + {{#if this.popoverIsShown}} +
+ + {{#if this.userHasSearched}} + {{#if this.inputValueIsValid}} + URL! Knew it! + {{else if this.shownDocuments}} +
    + {{#each this.shownDocuments as |d|}} +
  • + + + +
  • + {{/each}} +
+ {{else if this.search.isRunning}} + Searching... + {{else}} + No mattress + {{/if}} + {{else}} +
+
+ + Paste a URL or search for documents... +
+
+ {{/if}} +
+ {{/if}} +
+ +{{#each this.relatedResources as |resource|}} + {{! either linkTos or external links }} + {{resource}} + {{! button to delete it from the document }} + ❎ +{{/each}} diff --git a/web/app/components/inputs/document-select2.ts b/web/app/components/inputs/document-select2.ts new file mode 100644 index 000000000..80c67959f --- /dev/null +++ b/web/app/components/inputs/document-select2.ts @@ -0,0 +1,113 @@ +import Component from "@glimmer/component"; +import { A } from "@ember/array"; +import { action } from "@ember/object"; +import { tracked } from "@glimmer/tracking"; +import { inject as service } from "@ember/service"; +import AlgoliaService from "hermes/services/algolia"; +import { HermesDocument } from "hermes/types/document"; + +import { restartableTask } from "ember-concurrency"; +interface InputsDocumentSelect2ComponentSignature { + Args: {}; +} + +export default class InputsDocumentSelect2Component extends Component { + @service declare algolia: AlgoliaService; + + @tracked relatedResources = A(); + + @tracked inputValue = ""; + @tracked query = ""; + + @tracked inputValueIsValid = false; + @tracked popoverIsShown = false; + @tracked popoverTrigger: HTMLElement | null = null; + @tracked shownDocuments: HermesDocument[] | null = null; + + @tracked searchInput: HTMLInputElement | null = null; + + get userHasSearched() { + return this.query.length > 0; + } + + get searchButtonIsShown() { + return this.inputValue.length === 0; + } + + @action maybeAddResource() { + if (!this.inputValueIsValid) { + alert("invalid url"); + } else { + this.relatedResources.pushObject(this.inputValue); + this.clearSearch(); + } + } + + @action togglePopover() { + this.popoverIsShown = !this.popoverIsShown; + } + + @action hidePopover() { + this.popoverIsShown = false; + } + + @action onInputFocusin(e: FocusEvent) { + const input = e.target as HTMLInputElement; + input.placeholder = ""; + + this.popoverIsShown = true; + } + + @action registerPopoverTrigger(e: HTMLElement) { + this.popoverTrigger = e; + } + + @action onKeydown(event: KeyboardEvent) { + if (event.key === "Enter") { + this.maybeAddResource(); + } + + if (event.key === "Escape") { + this.clearSearch(); + } + } + + @action onInput(event: Event) { + this.inputValue = (event.target as HTMLInputElement).value; + this.checkURL.perform(); + } + + @action clearSearch() { + this.inputValue = ""; + } + + protected search = restartableTask(async (inputEvent: InputEvent) => { + const input = inputEvent.target as HTMLInputElement; + this.query = input.value; + + if (this.query === "") { + this.shownDocuments = null; + return; + } + + let algoliaResponse = await this.algolia.search.perform(this.query, { + hitsPerPage: 5, + attributesToRetrieve: ["title", "product", "docNumber"], + // give extra ranking to docs in the same product area + // optionalFilters: ["product:" + this.args.productArea], + }); + + if (algoliaResponse) { + this.shownDocuments = algoliaResponse.hits as HermesDocument[]; + } + }); + + protected checkURL = restartableTask(async () => { + const url = this.inputValue; + try { + this.inputValueIsValid = Boolean(new URL(url)); + } catch (e) { + this.inputValueIsValid = false; + } + }); +} diff --git a/web/app/templates/grass.hbs b/web/app/templates/grass.hbs index 6317f5061..d5541ded3 100644 --- a/web/app/templates/grass.hbs +++ b/web/app/templates/grass.hbs @@ -2,100 +2,7 @@ {{set-body-class "grass"}}
-
- Related docs -
-
- - {{#if (and this.searchButtonIsShown this.popoverIsShown)}} -
-
- -
-
- {{#if this.shownDocuments}} -
    - {{#each this.shownDocuments as |d|}} -
  • - - - -
  • - {{/each}} -
- {{else if this.userHasSearched}} -

No matches

- {{else}} - Recent docs in "Consul" -
list of docs. - {{/if}} -
-
- {{/if}} -
- {{#if this.searchButtonIsShown}} - - - - - {{else}} -
- {{! REMEMBER: mostly this will be pasted }} - - - - - - - Add - -
- - {{/if}} -
-
+ +
+
- -{{log}} - -{{#each this.relatedResources as |resource|}} - {{! either linkTos or external links }} - {{resource}} - {{! button to delete it from the document }} - ❎ -{{/each}} From ca904ddb9a1671156affe6d8295c53f65d0b7c6e Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Thu, 16 Mar 2023 15:58:43 -0400 Subject: [PATCH 008/340] Start of favicon logic --- .../components/inputs/document-select2.hbs | 26 +++++++++------ web/app/components/inputs/document-select2.ts | 32 +++++++++++++++++++ 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/web/app/components/inputs/document-select2.hbs b/web/app/components/inputs/document-select2.hbs index 441279dff..6a8dbcea3 100644 --- a/web/app/components/inputs/document-select2.hbs +++ b/web/app/components/inputs/document-select2.hbs @@ -21,21 +21,29 @@ {{#if this.userHasSearched}} {{#if this.inputValueIsValid}} - URL! Knew it! + It's a URL + {{#if this.faviconIsShown}} + {{#if this.maybeLoadFavicon.isRunning}} + 🌀 + {{else}} + 🟤 + + {{/if}} + {{/if}} {{else if this.shownDocuments}}
    {{#each this.shownDocuments as |d|}}
  • diff --git a/web/app/components/inputs/document-select2.ts b/web/app/components/inputs/document-select2.ts index 80c67959f..83b506d69 100644 --- a/web/app/components/inputs/document-select2.ts +++ b/web/app/components/inputs/document-select2.ts @@ -7,12 +7,17 @@ import AlgoliaService from "hermes/services/algolia"; import { HermesDocument } from "hermes/types/document"; import { restartableTask } from "ember-concurrency"; +import FetchService from "hermes/services/fetch"; interface InputsDocumentSelect2ComponentSignature { Args: {}; } +const GOOGLE_FAVICON_URL_PREFIX = + "https://s2.googleusercontent.com/s2/favicons?domain="; + export default class InputsDocumentSelect2Component extends Component { @service declare algolia: AlgoliaService; + @service("fetch") declare fetchSvc: FetchService; @tracked relatedResources = A(); @@ -26,6 +31,12 @@ export default class InputsDocumentSelect2Component extends Component 0; } @@ -81,6 +92,23 @@ export default class InputsDocumentSelect2Component extends Component { + const maybeFaviconURL = GOOGLE_FAVICON_URL_PREFIX + this.inputValue; + try { + const response = await this.fetchSvc.fetch(maybeFaviconURL); + if (response?.ok) { + this.faviconURL = maybeFaviconURL; + } + if (response?.status === 404) { + this.faviconURL = null; + console.log("nothing"); + } + } catch (e) { + this.faviconURL = null; + console.error(e); + } + }); + protected search = restartableTask(async (inputEvent: InputEvent) => { const input = inputEvent.target as HTMLInputElement; this.query = input.value; @@ -108,6 +136,10 @@ export default class InputsDocumentSelect2Component extends Component Date: Mon, 20 Mar 2023 09:09:25 -0400 Subject: [PATCH 009/340] Start of v3 --- .../document/related-resources-list-item.hbs | 16 +++ .../document/related-resources-list-item.ts | 19 ++++ .../components/inputs/document-select1.hbs | 1 - .../components/inputs/document-select2.hbs | 46 +++++--- web/app/components/inputs/document-select2.ts | 71 +++++++++--- .../components/inputs/document-select3.hbs | 46 ++++++++ web/app/components/inputs/document-select3.ts | 104 ++++++++++++++++++ web/app/templates/grass.hbs | 2 + 8 files changed, 276 insertions(+), 29 deletions(-) create mode 100644 web/app/components/document/related-resources-list-item.hbs create mode 100644 web/app/components/document/related-resources-list-item.ts create mode 100644 web/app/components/inputs/document-select3.hbs create mode 100644 web/app/components/inputs/document-select3.ts diff --git a/web/app/components/document/related-resources-list-item.hbs b/web/app/components/document/related-resources-list-item.hbs new file mode 100644 index 000000000..aa123181f --- /dev/null +++ b/web/app/components/document/related-resources-list-item.hbs @@ -0,0 +1,16 @@ +{{! either linkTos or external links }} + +
    +
    + + + {{! LinkTo or External Link }} + + {{@resource}} + +
    + {{! button to delete it from the document }} + + + +
    diff --git a/web/app/components/document/related-resources-list-item.ts b/web/app/components/document/related-resources-list-item.ts new file mode 100644 index 000000000..b1f963f95 --- /dev/null +++ b/web/app/components/document/related-resources-list-item.ts @@ -0,0 +1,19 @@ +import { action } from "@ember/object"; +import Component from "@glimmer/component"; + +interface DocumentRelatedResourcesListItemSignature { + Args: { + resource: string; + removeResource: (resource: string) => void; + }; +} + +export default class DocumentRelatedResourcesListItem extends Component { + @action removeResource() { + this.args.removeResource(this.args.resource); + } + + get faviconURL() { + return "https://www.google.com/s2/favicons?domain=" + this.args.resource; + } +} diff --git a/web/app/components/inputs/document-select1.hbs b/web/app/components/inputs/document-select1.hbs index 3614efbb5..c107587d4 100644 --- a/web/app/components/inputs/document-select1.hbs +++ b/web/app/components/inputs/document-select1.hbs @@ -21,7 +21,6 @@ {{did-insert this.registerAndFocusSearchInput}} type="text" placeholder="Search Hermes..." - {{! TODO: autofocus input }} />
diff --git a/web/app/components/inputs/document-select2.hbs b/web/app/components/inputs/document-select2.hbs index 6a8dbcea3..49277af5e 100644 --- a/web/app/components/inputs/document-select2.hbs +++ b/web/app/components/inputs/document-select2.hbs @@ -1,7 +1,7 @@
Related docs
-
+
{{#if this.popoverIsShown}}
{{#if this.userHasSearched}} {{#if this.inputValueIsValid}} - It's a URL - {{#if this.faviconIsShown}} - {{#if this.maybeLoadFavicon.isRunning}} - 🌀 +
+ + {{#if this.fetchURLInfo.isRunning}} + {{else}} - 🟤 - +
+
+ + + + + There will be a title here + +
+ +
{{/if}} - {{/if}} +
{{else if this.shownDocuments}}
    {{#each this.shownDocuments as |d|}}
  • + {{! this needs to not be a link-to }} @@ -65,10 +81,12 @@
{{/if}}
+
{{#each this.relatedResources as |resource|}} - {{! either linkTos or external links }} - {{resource}} - {{! button to delete it from the document }} - ❎ + {{/each}} +
diff --git a/web/app/components/inputs/document-select2.ts b/web/app/components/inputs/document-select2.ts index 83b506d69..c0bd51985 100644 --- a/web/app/components/inputs/document-select2.ts +++ b/web/app/components/inputs/document-select2.ts @@ -7,16 +7,36 @@ import AlgoliaService from "hermes/services/algolia"; import { HermesDocument } from "hermes/types/document"; import { restartableTask } from "ember-concurrency"; +import SessionService from "hermes/services/session"; import FetchService from "hermes/services/fetch"; +import { assert } from "@ember/debug"; +import { Response, createServer } from "miragejs"; +import config from "hermes/config/environment"; + interface InputsDocumentSelect2ComponentSignature { Args: {}; } const GOOGLE_FAVICON_URL_PREFIX = - "https://s2.googleusercontent.com/s2/favicons?domain="; + "https://s2.googleusercontent.com/s2/favicons"; + +createServer({ + routes() { + this.get(GOOGLE_FAVICON_URL_PREFIX, (schema, request) => { + // let url = request.queryParams["url"]; + + // need to respond + return new Response(200, {}, ""); + }); + + this.passthrough(); + this.passthrough(`https://${config.algolia.appID}-dsn.algolia.net/**`); + }, +}); export default class InputsDocumentSelect2Component extends Component { @service declare algolia: AlgoliaService; + @service declare session: SessionService; @service("fetch") declare fetchSvc: FetchService; @tracked relatedResources = A(); @@ -33,10 +53,6 @@ export default class InputsDocumentSelect2Component extends Component 0; } @@ -49,11 +65,22 @@ export default class InputsDocumentSelect2Component extends Component { - const maybeFaviconURL = GOOGLE_FAVICON_URL_PREFIX + this.inputValue; + protected fetchURLInfo = restartableTask(async () => { + let infoURL = GOOGLE_FAVICON_URL_PREFIX + "?url=" + this.inputValue; + + // const urlToFetch = this.inputValue; + const urlToFetch = infoURL; + try { - const response = await this.fetchSvc.fetch(maybeFaviconURL); + const response = await this.fetchSvc.fetch(urlToFetch, { + // For when we make a real request: + // headers: { + // Authorization: + // "Bearer " + this.session.data.authenticated.access_token, + // "Content-Type": "application/json", + // }, + }); + if (response?.ok) { - this.faviconURL = maybeFaviconURL; + this.faviconURL = + "https://www.google.com/s2/favicons?domain=" + this.inputValue; } + if (response?.status === 404) { this.faviconURL = null; - console.log("nothing"); } } catch (e) { - this.faviconURL = null; console.error(e); } }); @@ -116,6 +157,8 @@ export default class InputsDocumentSelect2Component extends Component + +
+ Related docs +
+ + + + + {{#if this.popoverIsShown}} +
+
+ +
+
+ {{/if}} +
+{{#if this.relatedResources.length}} + {{#each this.relatedResources as |resource|}} + {{! either linkTos or external links }} + {{resource}} + {{! button to delete it from the document }} + ❎ + {{/each}} +{{else}} +
+ + None yet +
+{{/if}} diff --git a/web/app/components/inputs/document-select3.ts b/web/app/components/inputs/document-select3.ts new file mode 100644 index 000000000..4ca0ef284 --- /dev/null +++ b/web/app/components/inputs/document-select3.ts @@ -0,0 +1,104 @@ +import Component from "@glimmer/component"; +import { A } from "@ember/array"; +import { action } from "@ember/object"; +import { tracked } from "@glimmer/tracking"; +import { inject as service } from "@ember/service"; +import AlgoliaService from "hermes/services/algolia"; +import { HermesDocument } from "hermes/types/document"; + +import { restartableTask } from "ember-concurrency"; +interface InputsDocumentSelect3ComponentSignature { + Args: {}; +} + +export default class InputsDocumentSelect3Component extends Component { + @service declare algolia: AlgoliaService; + + @tracked relatedResources = A(); + + @tracked inputValue = ""; + @tracked query = ""; + + @tracked inputValueIsValid = false; + @tracked popoverIsShown = false; + @tracked popoverTrigger: HTMLElement | null = null; + @tracked shownDocuments: HermesDocument[] | null = null; + + @tracked searchInput: HTMLInputElement | null = null; + + @action maybeAddResource() { + if (!this.inputValueIsValid) { + alert("invalid url"); + } else { + this.relatedResources.pushObject(this.inputValue); + this.clearSearch(); + } + } + + @action togglePopover() { + this.popoverIsShown = !this.popoverIsShown; + } + + @action hidePopover() { + this.popoverIsShown = false; + } + + @action registerPopoverTrigger(e: HTMLElement) { + this.popoverTrigger = e; + } + + @action registerAndFocusSearchInput(e: HTMLInputElement) { + this.searchInput = e; + this.searchInput.focus(); + } + + @action onKeydown(event: KeyboardEvent) { + if (event.key === "Enter") { + this.maybeAddResource(); + } + + if (event.key === "Escape") { + this.clearSearch(); + } + } + + @action onInput(event: Event) { + this.inputValue = (event.target as HTMLInputElement).value; + this.checkURL.perform(); + } + + @action clearSearch() { + this.inputValue = ""; + } + + protected search = restartableTask(async (inputEvent: InputEvent) => { + const input = inputEvent.target as HTMLInputElement; + this.query = input.value; + + if (this.query === "") { + this.shownDocuments = null; + return; + } + + let algoliaResponse = await this.algolia.search.perform(this.query, { + hitsPerPage: 5, + attributesToRetrieve: ["title", "product", "docNumber"], + // give extra ranking to docs in the same product area + // optionalFilters: ["product:" + this.args.productArea], + }); + + if (algoliaResponse) { + this.shownDocuments = algoliaResponse.hits as HermesDocument[]; + } + }); + + + protected checkURL = restartableTask(async () => { + const url = this.inputValue; + try { + this.inputValueIsValid = Boolean(new URL(url)); + } catch (e) { + this.inputValueIsValid = false; + } + }); +} diff --git a/web/app/templates/grass.hbs b/web/app/templates/grass.hbs index d5541ded3..d61594ec6 100644 --- a/web/app/templates/grass.hbs +++ b/web/app/templates/grass.hbs @@ -5,4 +5,6 @@
+
+
From 25aec03ba9fc180da2c35f482365d7fa9fb29865 Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Mon, 20 Mar 2023 13:35:38 -0400 Subject: [PATCH 010/340] Improved v3 prototype --- .../components/inputs/document-select3.hbs | 67 +++++++++- web/app/components/inputs/document-select3.ts | 114 ++++++++++++++---- web/app/templates/grass.hbs | 2 +- 3 files changed, 154 insertions(+), 29 deletions(-) diff --git a/web/app/components/inputs/document-select3.hbs b/web/app/components/inputs/document-select3.hbs index 9de5e9dab..f70fd7d6f 100644 --- a/web/app/components/inputs/document-select3.hbs +++ b/web/app/components/inputs/document-select3.hbs @@ -16,18 +16,79 @@ {{#if this.popoverIsShown}}
+
+ {{#if this.query.length}} + Results + {{else if this.inputValueIsValid}} + Attach link + {{else}} + Suggestions + {{/if}} + + {{#if this.inputValueIsValid}} +
+ + {{#if this.fetchURLInfo.isRunning}} + + {{else}} +
+
+ + + + + There will be a title here + +
+ +
+ {{/if}} +
+ {{else}} +
    + {{#each this.shownDocuments as |d|}} +
  1. + + {{! this needs to not be a link-to }} + + +
  2. + {{/each}} +
+ {{/if}} +
{{/if}}
diff --git a/web/app/components/inputs/document-select3.ts b/web/app/components/inputs/document-select3.ts index 4ca0ef284..307815dbf 100644 --- a/web/app/components/inputs/document-select3.ts +++ b/web/app/components/inputs/document-select3.ts @@ -5,23 +5,52 @@ import { tracked } from "@glimmer/tracking"; import { inject as service } from "@ember/service"; import AlgoliaService from "hermes/services/algolia"; import { HermesDocument } from "hermes/types/document"; +import FetchService from "hermes/services/fetch"; +import { Response, createServer } from "miragejs"; +import config from "hermes/config/environment"; import { restartableTask } from "ember-concurrency"; interface InputsDocumentSelect3ComponentSignature { - Args: {}; + Args: { + productArea?: string; + }; } +const GOOGLE_FAVICON_URL_PREFIX = + "https://s2.googleusercontent.com/s2/favicons"; + +createServer({ + routes() { + this.get(GOOGLE_FAVICON_URL_PREFIX, (schema, request) => { + // let url = request.queryParams["url"]; + + // need to respond + return new Response(200, {}, ""); + }); + + this.passthrough(); + this.passthrough(`https://${config.algolia.appID}-dsn.algolia.net/**`); + }, +}); + + export default class InputsDocumentSelect3Component extends Component { @service declare algolia: AlgoliaService; + @service("fetch") declare fetchSvc: FetchService; @tracked relatedResources = A(); - @tracked inputValue = ""; @tracked query = ""; @tracked inputValueIsValid = false; @tracked popoverIsShown = false; + + @tracked faviconURL: string | null = null; + + @tracked popoverTrigger: HTMLElement | null = null; + + // TODO: this needs to exclude selected documents (relatedResources) @tracked shownDocuments: HermesDocument[] | null = null; @tracked searchInput: HTMLInputElement | null = null; @@ -30,7 +59,7 @@ export default class InputsDocumentSelect3Component extends Component { - const input = inputEvent.target as HTMLInputElement; - this.query = input.value; + protected fetchURLInfo = restartableTask(async () => { + let infoURL = GOOGLE_FAVICON_URL_PREFIX + "?url=" + this.query; - if (this.query === "") { - this.shownDocuments = null; - return; - } + // const urlToFetch = this.inputValue; + const urlToFetch = infoURL; - let algoliaResponse = await this.algolia.search.perform(this.query, { - hitsPerPage: 5, - attributesToRetrieve: ["title", "product", "docNumber"], - // give extra ranking to docs in the same product area - // optionalFilters: ["product:" + this.args.productArea], - }); + try { + const response = await this.fetchSvc.fetch(urlToFetch, { + // For when we make a real request: + // headers: { + // Authorization: + // "Bearer " + this.session.data.authenticated.access_token, + // "Content-Type": "application/json", + // }, + }); + + if (response?.ok) { + this.faviconURL = + "https://www.google.com/s2/favicons?domain=" + this.query; + } + + if (response?.status === 404) { + this.faviconURL = null; + } + } catch (e) { + console.error(e); + } + }); - if (algoliaResponse) { - this.shownDocuments = algoliaResponse.hits as HermesDocument[]; + protected search = restartableTask(async (query: string) => { + try { + let algoliaResponse = await this.algolia.search.perform(query, { + hitsPerPage: 5, + attributesToRetrieve: ["title", "product", "docNumber"], + // give extra ranking to docs in the same product area + optionalFilters: ["product:" + this.args.productArea], + }); + + if (algoliaResponse) { + this.shownDocuments = algoliaResponse.hits as HermesDocument[]; + } + } catch (e) { + console.error(e); } }); + protected onInput = restartableTask(async (inputEvent: InputEvent) => { + const input = inputEvent.target as HTMLInputElement; + this.query = input.value; + + this.checkURL.perform(); + + void this.search.perform(this.query); + }); protected checkURL = restartableTask(async () => { - const url = this.inputValue; + const url = this.query; try { this.inputValueIsValid = Boolean(new URL(url)); } catch (e) { this.inputValueIsValid = false; + } finally { + if (this.inputValueIsValid) { + this.fetchURLInfo.perform(); + } } }); } diff --git a/web/app/templates/grass.hbs b/web/app/templates/grass.hbs index d61594ec6..a534f7dd9 100644 --- a/web/app/templates/grass.hbs +++ b/web/app/templates/grass.hbs @@ -6,5 +6,5 @@

- +
From 081693da5251f0f5eafef4481c573f41c05bae14 Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Mon, 20 Mar 2023 16:44:13 -0400 Subject: [PATCH 011/340] Improved v3 design --- web/app/components/doc/inline.hbs | 22 ++-- .../components/inputs/document-select3.hbs | 121 ++++++++++++------ web/app/components/inputs/document-select3.ts | 10 +- web/app/styles/components/doc/tile.scss | 13 +- 4 files changed, 107 insertions(+), 59 deletions(-) diff --git a/web/app/components/doc/inline.hbs b/web/app/components/doc/inline.hbs index 6f36074fe..b44149023 100644 --- a/web/app/components/doc/inline.hbs +++ b/web/app/components/doc/inline.hbs @@ -51,20 +51,16 @@
-

{{@title}}

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

{{@title}}

+ {{#if (not (is-empty @docNumber))}} + {{@docNumber}} + {{/if}} +
- + {{#if @isResult}} {{#if @snippet}} diff --git a/web/app/components/inputs/document-select3.hbs b/web/app/components/inputs/document-select3.hbs index f70fd7d6f..fc21ad2d0 100644 --- a/web/app/components/inputs/document-select3.hbs +++ b/web/app/components/inputs/document-select3.hbs @@ -1,5 +1,4 @@
-
Related docs
@@ -16,64 +15,95 @@ {{#if this.popoverIsShown}}
- {{#if this.query.length}} - Results - {{else if this.inputValueIsValid}} - Attach link - {{else}} - Suggestions - {{/if}} - - {{#if this.inputValueIsValid}} -
- {{#if this.fetchURLInfo.isRunning}} - +
+ {{#if this.query.length}} + {{#if this.inputValueIsValid}} + {{! Attach link }} {{else}} -
-
+ Results + {{/if}} + {{else}} + Suggestions + {{/if}} +
+ + {{#if this.inputValueIsValid}} + {{#if this.fetchURLInfo.isRunning}} +
+
+ +
+
+ {{! }} + {{else}} + +
+
- - - There will be a title here + + Add external document
-
- {{/if}} -
+ + {{/if}} {{else}} -
    - {{#each this.shownDocuments as |d|}} -
  1. - - {{! this needs to not be a link-to }} - + {{#each this.shownDocuments as |d|}} +
  2. + +
    + +
    +
    +

    + {{d.title}} +

    + {{#if d.docNumber}} + + {{d.docNumber}} + + {{/if}} +
    + + {{! this needs to not be a link-to }} + {{!-- -
    -
  3. - {{/each}} -
+ /> --}} + + + {{/each}} + + {{else}} +
+ {{#if (or this.search.isRunning this.fetchURLInfo.isRunning)}} +
+ +
+ {{else}} +
+ No matches +
+ {{/if}} +
+ {{/if}} {{/if}}
@@ -100,7 +143,7 @@ ❎ {{/each}} {{else}} -
+
None yet
diff --git a/web/app/components/inputs/document-select3.ts b/web/app/components/inputs/document-select3.ts index 307815dbf..f14989b91 100644 --- a/web/app/components/inputs/document-select3.ts +++ b/web/app/components/inputs/document-select3.ts @@ -33,7 +33,6 @@ createServer({ }, }); - export default class InputsDocumentSelect3Component extends Component { @service declare algolia: AlgoliaService; @service("fetch") declare fetchSvc: FetchService; @@ -47,7 +46,6 @@ export default class InputsDocumentSelect3Component extends Component { @@ -148,8 +147,7 @@ export default class InputsDocumentSelect3Component extends Component Date: Mon, 20 Mar 2023 17:22:47 -0400 Subject: [PATCH 012/340] LinkTo related Docs --- .../components/inputs/document-select3.hbs | 38 ++++++--- web/app/components/inputs/document-select3.ts | 78 +++++++------------ web/app/templates/grass.hbs | 8 +- 3 files changed, 61 insertions(+), 63 deletions(-) diff --git a/web/app/components/inputs/document-select3.hbs b/web/app/components/inputs/document-select3.hbs index fc21ad2d0..895d10cbc 100644 --- a/web/app/components/inputs/document-select3.hbs +++ b/web/app/components/inputs/document-select3.hbs @@ -56,7 +56,7 @@ {{else}}
@@ -80,19 +80,20 @@ {{/if}} {{else}} {{#if this.shownDocuments.length}} -
    +
      {{#each this.shownDocuments as |d|}}
    1. -

      +

      {{d.title}}

      {{#if d.docNumber}} @@ -136,12 +137,29 @@ {{/if}}
      {{#if this.relatedResources.length}} - {{#each this.relatedResources as |resource|}} - {{! either linkTos or external links }} - {{resource}} - {{! button to delete it from the document }} - ❎ - {{/each}} +
        + + {{#each this.relatedResources as |resource|}} +
      • + + {{#if resource.objectID}} + + {{resource.title}} + {{#if resource.docNumber}} + {{resource.docNumber}} + {{/if}} + + {{else}} + + {{resource}} + + {{/if}} + ❎ +
      • + + {{/each}} +
      + {{else}}
      diff --git a/web/app/components/inputs/document-select3.ts b/web/app/components/inputs/document-select3.ts index f14989b91..988490a45 100644 --- a/web/app/components/inputs/document-select3.ts +++ b/web/app/components/inputs/document-select3.ts @@ -6,38 +6,23 @@ import { inject as service } from "@ember/service"; import AlgoliaService from "hermes/services/algolia"; import { HermesDocument } from "hermes/types/document"; import FetchService from "hermes/services/fetch"; -import { Response, createServer } from "miragejs"; -import config from "hermes/config/environment"; +import { restartableTask, timeout } from "ember-concurrency"; +import NativeArray from "@ember/array/-private/native-array"; -import { restartableTask } from "ember-concurrency"; interface InputsDocumentSelect3ComponentSignature { Args: { productArea?: string; }; } -const GOOGLE_FAVICON_URL_PREFIX = - "https://s2.googleusercontent.com/s2/favicons"; - -createServer({ - routes() { - this.get(GOOGLE_FAVICON_URL_PREFIX, (schema, request) => { - // let url = request.queryParams["url"]; - - // need to respond - return new Response(200, {}, ""); - }); - - this.passthrough(); - this.passthrough(`https://${config.algolia.appID}-dsn.algolia.net/**`); - }, -}); +// const GOOGLE_FAVICON_URL_PREFIX = +// "https://s2.googleusercontent.com/s2/favicons"; export default class InputsDocumentSelect3Component extends Component { @service declare algolia: AlgoliaService; @service("fetch") declare fetchSvc: FetchService; - @tracked relatedResources = A(); + @tracked relatedResources: NativeArray = A(); @tracked query = ""; @@ -53,14 +38,14 @@ export default class InputsDocumentSelect3Component extends Component { - let infoURL = GOOGLE_FAVICON_URL_PREFIX + "?url=" + this.query; - + // let infoURL = GOOGLE_FAVICON_URL_PREFIX + "?url=" + this.query; // const urlToFetch = this.inputValue; - const urlToFetch = infoURL; + // const urlToFetch = infoURL; try { - const response = await this.fetchSvc.fetch(urlToFetch, { - // For when we make a real request: - // headers: { - // Authorization: - // "Bearer " + this.session.data.authenticated.access_token, - // "Content-Type": "application/json", - // }, - }); - - if (response?.ok) { - this.faviconURL = - "https://www.google.com/s2/favicons?domain=" + this.query; - } - - if (response?.status === 404) { - this.faviconURL = null; - } + // Simulate a request + await timeout(300); + // const response = await this.fetchSvc.fetch(urlToFetch, { + // // For when we make a real request: + // // headers: { + // // Authorization: + // // "Bearer " + this.session.data.authenticated.access_token, + // // "Content-Type": "application/json", + // // }, + // }); + + this.faviconURL = + "https://www.google.com/s2/favicons?domain=" + this.query; } catch (e) { console.error(e); } diff --git a/web/app/templates/grass.hbs b/web/app/templates/grass.hbs index a534f7dd9..e1623b8ab 100644 --- a/web/app/templates/grass.hbs +++ b/web/app/templates/grass.hbs @@ -2,9 +2,9 @@ {{set-body-class "grass"}}
      - -
      - -
      + {{!-- --}} + {{!--
      --}} + {{!-- --}} + {{!--
      --}}
      From cb4108b5503cc393b56c574dba86081824fe21c4 Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Mon, 20 Mar 2023 21:06:20 -0400 Subject: [PATCH 013/340] Additional V3 design --- .../components/inputs/document-select3.hbs | 318 ++++++++++-------- web/app/components/inputs/document-select3.ts | 9 +- 2 files changed, 181 insertions(+), 146 deletions(-) diff --git a/web/app/components/inputs/document-select3.hbs b/web/app/components/inputs/document-select3.hbs index 895d10cbc..d2dd40b83 100644 --- a/web/app/components/inputs/document-select3.hbs +++ b/web/app/components/inputs/document-select3.hbs @@ -1,168 +1,198 @@ -
      -
      - Related docs -
      - - - - - {{#if this.popoverIsShown}} -
      + +
      +
      + Related docs +
      + -
      - -
      -
      + + + + {{#if this.popoverIsShown}} +
      +
      + +
      +
      -
      - {{#if this.query.length}} - {{#if this.inputValueIsValid}} - {{! Attach link }} +
      + {{#if this.query.length}} + {{#if this.inputValueIsValid}} + {{! Attach link }} + {{else}} + Results + {{/if}} {{else}} - Results + Suggestions + {{/if}} +
      + + {{#if this.inputValueIsValid}} + {{#if this.fetchURLInfo.isRunning}} +
      +
      + +
      +
      + {{! }} + {{else}} + +
      +
      + + + Add external document + +
      + {{! if focused only }} + +
      +
      {{/if}} {{else}} - Suggestions + {{#if this.shownDocuments.length}} +
        + {{#each this.shownDocuments as |d|}} +
      1. + +
        + +
        +
        +

        + {{d.title}} +

        + {{#if d.docNumber}} + + {{d.docNumber}} + + {{/if}} +
        +
        +
      2. + {{/each}} +
      + {{else}} +
      + {{#if (or this.search.isRunning this.fetchURLInfo.isRunning)}} +
      + +
      + {{else}} +
      + No matches +
      + {{/if}} +
      + {{/if}} {{/if}}
      +
      + {{/if}} +
      + + {{#if this.relatedResources.length}} +
        + {{#each (reverse this.relatedResources) as |r|}} +
      • + {{#if r.objectID}} + - {{#if this.inputValueIsValid}} - {{#if this.fetchURLInfo.isRunning}} -
        -
        +
        + +
        +
        +
        + {{! Create space for the "more" icon }} +
        +
        - +

        + {{r.title}} +

        +
        + {{#if r.docNumber}} + + {{r.docNumber}} + + {{/if}}
        -
        - {{! }} + {{else}} - +
        -
        +
        - - Add external document + + {{r}}
        - {{! if focused only }} -
        - + {{/if}} - {{else}} - {{#if this.shownDocuments.length}} -
          - {{#each this.shownDocuments as |d|}} -
        1. - -
          - -
          -
          -

          - {{d.title}} -

          - {{#if d.docNumber}} - - {{d.docNumber}} - - {{/if}} -
          - - {{! this needs to not be a link-to }} - {{!-- --}} -
          -
        2. - {{/each}} -
        - {{else}} -
        - {{#if (or this.search.isRunning this.fetchURLInfo.isRunning)}} -
        - -
        - {{else}} -
        - No matches -
        - {{/if}} -
        - {{/if}} - {{/if}} -
        + + + +
      • + {{/each}} +
      + {{else}} +
      + None yet
      {{/if}}
      -{{#if this.relatedResources.length}} -
        - - {{#each this.relatedResources as |resource|}} -
      • - - {{#if resource.objectID}} - - {{resource.title}} - {{#if resource.docNumber}} - {{resource.docNumber}} - {{/if}} - - {{else}} - - {{resource}} - - {{/if}} - ❎ -
      • - - {{/each}} -
      - -{{else}} -
      - - None yet -
      -{{/if}} diff --git a/web/app/components/inputs/document-select3.ts b/web/app/components/inputs/document-select3.ts index 988490a45..cf98f8b8e 100644 --- a/web/app/components/inputs/document-select3.ts +++ b/web/app/components/inputs/document-select3.ts @@ -39,12 +39,12 @@ export default class InputsDocumentSelect3Component extends Component { // let infoURL = GOOGLE_FAVICON_URL_PREFIX + "?url=" + this.query; // const urlToFetch = this.inputValue; @@ -107,6 +111,7 @@ export default class InputsDocumentSelect3Component extends Component { + try { let algoliaResponse = await this.algolia.search.perform(query, { hitsPerPage: 5, From 63c00259a9b3c189b76b558e7308a0e396d2c17e Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Tue, 21 Mar 2023 10:36:58 -0400 Subject: [PATCH 014/340] Improved search logic and design --- .../components/inputs/document-select3.hbs | 15 ++-- web/app/components/inputs/document-select3.ts | 75 ++++++++++++++++--- 2 files changed, 71 insertions(+), 19 deletions(-) diff --git a/web/app/components/inputs/document-select3.hbs b/web/app/components/inputs/document-select3.hbs index d2dd40b83..8e4e8acd8 100644 --- a/web/app/components/inputs/document-select3.hbs +++ b/web/app/components/inputs/document-select3.hbs @@ -129,14 +129,14 @@
      {{#if this.relatedResources.length}} -
        - {{#each (reverse this.relatedResources) as |r|}} -
      • +
          + {{#each this.relatedResources as |r|}} +
        • {{#if r.objectID}}
          {{! Create space for the "more" icon }} -
          -
          +

          {{r.title}} @@ -180,10 +179,10 @@ {{/if}} diff --git a/web/app/components/inputs/document-select3.ts b/web/app/components/inputs/document-select3.ts index cf98f8b8e..3e198c5cf 100644 --- a/web/app/components/inputs/document-select3.ts +++ b/web/app/components/inputs/document-select3.ts @@ -8,6 +8,8 @@ import { HermesDocument } from "hermes/types/document"; import FetchService from "hermes/services/fetch"; import { restartableTask, timeout } from "ember-concurrency"; import NativeArray from "@ember/array/-private/native-array"; +import ConfigService from "hermes/services/config"; +import FlashMessageService from "ember-cli-flash/services/flash-messages"; interface InputsDocumentSelect3ComponentSignature { Args: { @@ -19,10 +21,20 @@ interface InputsDocumentSelect3ComponentSignature { // "https://s2.googleusercontent.com/s2/favicons"; export default class InputsDocumentSelect3Component extends Component { - @service declare algolia: AlgoliaService; + @service("config") declare configSvc: ConfigService; @service("fetch") declare fetchSvc: FetchService; + @service declare algolia: AlgoliaService; + @service declare flashMessages: FlashMessageService; - @tracked relatedResources: NativeArray = A(); + @tracked relatedLinks: NativeArray = A(); + @tracked relatedDocuments: NativeArray = A(); + + get relatedResources(): NativeArray { + let resources: NativeArray = A(); + resources.pushObjects(this.relatedDocuments); + resources.pushObjects(this.relatedLinks); + return resources; + } @tracked query = ""; @@ -39,13 +51,30 @@ export default class InputsDocumentSelect3Component extends Component { @@ -111,14 +148,30 @@ export default class InputsDocumentSelect3Component extends Component { + let index = + this.configSvc.config.algolia_docs_index_name + + "_createdTime_desc__productRanked"; + + // TODO: this search needs to filter out already-selected relatedDocs + let relatedDocIDs = this.relatedDocuments.map((doc) => doc.objectID); + let filterString = + '(NOT objectID:"' + relatedDocIDs.join('" AND NOT objectID:"') + '")'; + + if (!this.relatedDocuments.length) { + filterString = ""; + } + console.log(filterString); try { - let algoliaResponse = await this.algolia.search.perform(query, { - hitsPerPage: 5, - attributesToRetrieve: ["title", "product", "docNumber"], - // give extra ranking to docs in the same product area - optionalFilters: ["product:" + this.args.productArea], - }); + let algoliaResponse = await this.algolia.searchIndex + .perform(index, query, { + hitsPerPage: 5, + filters: filterString, + attributesToRetrieve: ["title", "product", "docNumber"], + // give extra ranking to docs in the same product area + optionalFilters: ["product:" + this.args.productArea], + }) + .then((response) => response); if (algoliaResponse) { this.shownDocuments = algoliaResponse.hits as HermesDocument[]; From 3420d10fdb277909aeedebb16b8de6abbc793849 Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Tue, 21 Mar 2023 12:36:43 -0400 Subject: [PATCH 015/340] Some CSS cleanup --- .../components/inputs/document-select3.hbs | 50 +++++++++---------- web/app/styles/app.scss | 1 + .../styles/components/document-select.scss | 11 ++++ 3 files changed, 37 insertions(+), 25 deletions(-) create mode 100644 web/app/styles/components/document-select.scss diff --git a/web/app/components/inputs/document-select3.hbs b/web/app/components/inputs/document-select3.hbs index 8e4e8acd8..e0572b9c4 100644 --- a/web/app/components/inputs/document-select3.hbs +++ b/web/app/components/inputs/document-select3.hbs @@ -1,4 +1,4 @@ -
          +
          @@ -7,7 +7,7 @@ {{#if this.popoverIsShown}}
          @@ -32,31 +32,31 @@
          -
          - {{#if this.query.length}} - {{#if this.inputValueIsValid}} - {{! Attach link }} + {{#unless (and this.query.length this.inputValueIsValid)}} +
          + {{#if this.query.length}} + {{#unless this.inputValueIsValid}} + Results + {{/unless}} {{else}} - Results + Suggestions {{/if}} - {{else}} - Suggestions - {{/if}} -
          +
          + {{/unless}} {{#if this.inputValueIsValid}} {{#if this.fetchURLInfo.isRunning}} -
          -
          - -
          +
          +
          {{! }} {{else}}
          @@ -74,19 +74,19 @@ {{! if focused only }}
          {{/if}} {{else}} {{#if this.shownDocuments.length}} -
            +
              {{#each this.shownDocuments as |d|}}
            1. {{else}} - +
              Date: Tue, 21 Mar 2023 14:35:28 -0400 Subject: [PATCH 016/340] Additional styles --- web/app/components/inputs/document-select3.hbs | 8 ++++---- web/app/styles/components/document-select.scss | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/web/app/components/inputs/document-select3.hbs b/web/app/components/inputs/document-select3.hbs index e0572b9c4..112bc79aa 100644 --- a/web/app/components/inputs/document-select3.hbs +++ b/web/app/components/inputs/document-select3.hbs @@ -7,7 +7,7 @@
              {{#if this.relatedResources.length}} -
                +
                  {{#each this.relatedResources as |r|}}
                • {{#if r.objectID}} @@ -140,7 +140,7 @@ >
                  @@ -153,25 +153,25 @@ {{r.title}}

          - {{#if r.docNumber}} + {{!-- {{#if r.docNumber}} {{r.docNumber}} - {{/if}} + {{/if}} --}}
          {{else}} - +
          -
          +
          - {{r}} + {{r.displayURL}}
          diff --git a/web/app/components/inputs/document-select3.ts b/web/app/components/inputs/document-select3.ts index 3e198c5cf..af6487c89 100644 --- a/web/app/components/inputs/document-select3.ts +++ b/web/app/components/inputs/document-select3.ts @@ -17,6 +17,11 @@ interface InputsDocumentSelect3ComponentSignature { }; } +interface RelatedExternalLink { + url: string; + displayURL: string; +} + // const GOOGLE_FAVICON_URL_PREFIX = // "https://s2.googleusercontent.com/s2/favicons"; @@ -26,11 +31,11 @@ export default class InputsDocumentSelect3Component extends Component = A(); + @tracked relatedLinks: NativeArray = A(); @tracked relatedDocuments: NativeArray = A(); - get relatedResources(): NativeArray { - let resources: NativeArray = A(); + get relatedResources(): NativeArray { + let resources: NativeArray = A(); resources.pushObjects(this.relatedDocuments); resources.pushObjects(this.relatedLinks); return resources; @@ -45,22 +50,44 @@ export default class InputsDocumentSelect3Component extends Component Date: Wed, 22 Mar 2023 10:09:11 -0400 Subject: [PATCH 018/340] Enter-button tweak --- web/app/components/document/sidebar.hbs | 5 +++ .../components/inputs/document-select3.hbs | 35 ++++++++++--------- web/app/components/inputs/document-select3.ts | 4 ++- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/web/app/components/document/sidebar.hbs b/web/app/components/document/sidebar.hbs index 5805bd932..fd8cfeb5f 100644 --- a/web/app/components/document/sidebar.hbs +++ b/web/app/components/document/sidebar.hbs @@ -167,6 +167,11 @@ class="whitespace-nowrap" />
          +
          + +
          + +
          - {{!-- {{#if r.docNumber}} +
      {{else}} - -
      -
      - - - {{r.displayURL}} - -
      + +
      + + + {{r.displayURL}} +
      {{/if}}
    2. {{/each}} diff --git a/web/app/components/inputs/document-select3.ts b/web/app/components/inputs/document-select3.ts index 30b5838b7..441b4e038 100644 --- a/web/app/components/inputs/document-select3.ts +++ b/web/app/components/inputs/document-select3.ts @@ -18,7 +18,7 @@ interface InputsDocumentSelect3ComponentSignature { }; } -interface RelatedExternalLink { +export interface RelatedExternalLink { url: string; displayURL: string; } diff --git a/web/app/styles/components/document-select.scss b/web/app/styles/components/document-select.scss index a01355c76..ecd22f43b 100644 --- a/web/app/styles/components/document-select.scss +++ b/web/app/styles/components/document-select.scss @@ -1,6 +1,14 @@ .document-select { @apply max-w-[250px] w-full; + .popover { + @apply absolute -bottom-px translate-y-full -left-[13px] -right-[13px] border rounded-lg border-color-border-strong bg-color-foreground-high-contrast; + + &.more-popover { + @apply -right-px top-[30px] left-auto bottom-auto rounded translate-y-0; + } + } + .related-doc-link { @apply w-[calc(100%+16px)] -ml-[8px] px-[8px] rounded -mr-[8px] flex items-start py-1 space-x-3 border border-transparent; } @@ -10,7 +18,7 @@ &:hover, &:focus { + .more-button { - @apply visible; + @apply opacity-100; } } } @@ -21,10 +29,16 @@ } .more-button { - @apply absolute invisible opacity-75 flex rounded -right-1 py-1 px-1 border border-transparent; + @apply absolute opacity-50 flex rounded -right-px py-1 px-1 border border-transparent; + + &:hover, + &:focus, + &.active { + @apply opacity-100 bg-color-page-primary border-color-border-strong; + } - &:hover { - @apply visible opacity-100 bg-color-page-primary border-color-border-strong; + &.active { + @apply bg-color-surface-interactive-hover border-color-border-strong; } } From 86f36fb527b94aad402337c2698c43c83a09cfe3 Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Wed, 22 Mar 2023 14:41:12 -0400 Subject: [PATCH 022/340] Tweak colors; Tweak return-icon visibility --- web/app/components/inputs/document-select/more-button.hbs | 4 ++-- web/app/components/inputs/document-select3.hbs | 2 +- web/app/styles/components/document-select.scss | 6 +----- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/web/app/components/inputs/document-select/more-button.hbs b/web/app/components/inputs/document-select/more-button.hbs index 053cc69d4..9f3daace7 100644 --- a/web/app/components/inputs/document-select/more-button.hbs +++ b/web/app/components/inputs/document-select/more-button.hbs @@ -8,12 +8,12 @@ {{#if this.popoverIsShown}}
      Remove diff --git a/web/app/components/inputs/document-select3.hbs b/web/app/components/inputs/document-select3.hbs index 042a63157..5b29332ff 100644 --- a/web/app/components/inputs/document-select3.hbs +++ b/web/app/components/inputs/document-select3.hbs @@ -74,7 +74,7 @@ {{! if focused only }}
      diff --git a/web/app/styles/components/document-select.scss b/web/app/styles/components/document-select.scss index ecd22f43b..8ff54e42c 100644 --- a/web/app/styles/components/document-select.scss +++ b/web/app/styles/components/document-select.scss @@ -2,7 +2,7 @@ @apply max-w-[250px] w-full; .popover { - @apply absolute -bottom-px translate-y-full -left-[13px] -right-[13px] border rounded-lg border-color-border-strong bg-color-foreground-high-contrast; + @apply absolute -bottom-px translate-y-full -left-[13px] -right-[13px] border rounded-lg border-color-border-strong bg-color-foreground-high-contrast z-50; &.more-popover { @apply -right-px top-[30px] left-auto bottom-auto rounded translate-y-0; @@ -36,10 +36,6 @@ &.active { @apply opacity-100 bg-color-page-primary border-color-border-strong; } - - &.active { - @apply bg-color-surface-interactive-hover border-color-border-strong; - } } .hermes-doc { From 3efe7ecb65b261c703c96187900fd8560ca1f23d Mon Sep 17 00:00:00 2001 From: Jeff Daley Date: Wed, 22 Mar 2023 14:55:29 -0400 Subject: [PATCH 023/340] Start of padding --- web/app/components/document/index.hbs | 32 +++++++++++++------------ web/app/components/document/sidebar.hbs | 2 +- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/web/app/components/document/index.hbs b/web/app/components/document/index.hbs index 6bf3bd413..a1c4e1209 100644 --- a/web/app/components/document/index.hbs +++ b/web/app/components/document/index.hbs @@ -1,4 +1,4 @@ -
      +
      - - - + + +
      diff --git a/web/app/components/document/sidebar.hbs b/web/app/components/document/sidebar.hbs index 5805bd932..f58a7cc4c 100644 --- a/web/app/components/document/sidebar.hbs +++ b/web/app/components/document/sidebar.hbs @@ -1,4 +1,4 @@ -