Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add types to Document route; Document-related cleanup #324

Merged
merged 20 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion web/app/components/dashboard/latest-updates.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
@owner={{get doc.owners 0}}
@productArea={{doc.product}}
@status={{lowercase doc.status}}
@thumbnail={{doc.googleMetadata.thumbnailLink}}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully we're going to add thumbnails back sooner than later, but I'll defer to you if you want to remove this before then.

@title={{doc.title}}
/>
{{/each}}
Expand Down
3 changes: 0 additions & 3 deletions web/app/components/dashboard/latest-updates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ import ConfigService from "hermes/services/config";
import { HermesDocument } from "hermes/types/document";
import { SearchResponse } from "instantsearch.js";

// @ts-ignore - not yet typed
import timeAgo from "hermes/utils/time-ago";

interface DashboardLatestUpdatesComponentSignature {
Args: {};
}
Expand Down
2 changes: 1 addition & 1 deletion web/app/components/doc/row.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
@route="authenticated.document"
@model="{{@docID}}"
@query={{hash draft=@isDraft}}
class="flex space-x-4 items-start"
class="flex items-start space-x-4"
>
<Doc::Thumbnail @status={{@status}} @product={{@productArea}} />
<div>
Expand Down
1 change: 0 additions & 1 deletion web/app/components/doc/tile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ interface DocTileComponentSignature {
productArea?: string;
snippet?: string;
status?: string;
thumbnail?: string;
title?: string;
};
}
Expand Down
2 changes: 1 addition & 1 deletion web/app/components/document/sidebar.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@

<div class="flex flex-col items-start space-y-2">
<Document::Sidebar::SectionHeader @title="Created" />
<p>{{or @document.createdDate "Unknown"}}</p>
<p>{{or (parse-date @document.created "long") "Unknown"}}</p>
</div>

<div class="flex flex-col items-start space-y-2">
Expand Down
2 changes: 1 addition & 1 deletion web/app/components/row-results.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
</H.Tr>
</:head>
<:body>
{{#each @docs as |doc index|}}
{{#each @docs as |doc|}}
<Doc::Row
@avatar="{{get doc.ownerPhotos 0}}"
@createdDate="{{parse-date doc.created}}"
Expand Down
3 changes: 3 additions & 0 deletions web/app/controllers/authenticated/dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import Controller from "@ember/controller";
import { inject as service } from "@ember/service";
import AuthenticatedUserService from "hermes/services/authenticated-user";
import RecentlyViewedDocsService from "hermes/services/recently-viewed-docs";
import { HermesDocument } from "hermes/types/document";

export default class AuthenticatedDashboardController extends Controller {
@service declare authenticatedUser: AuthenticatedUserService;
@service("recently-viewed-docs")
declare recentDocs: RecentlyViewedDocsService;

declare model: HermesDocument[];
}
7 changes: 2 additions & 5 deletions web/app/helpers/parse-date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,14 @@ export interface ParseDateHelperSignature {
Args: {
Positional: [
time: string | number | Date | undefined,
monthFormat: "short" | "long"
monthFormat?: "short" | "long"
];
Return: Date | undefined;
};
}

const parseDateHelper = helper<ParseDateHelperSignature>(
([time, monthFormat = "short"]: [
string | number | Date | undefined,
"short" | "long"
]) => {
([time, monthFormat = "short"]) => {
return parseDate(time, monthFormat);
}
);
Expand Down
1 change: 0 additions & 1 deletion web/app/routes/authenticated/dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import FetchService from "hermes/services/fetch";
import RecentlyViewedDocsService from "hermes/services/recently-viewed-docs";
import SessionService from "hermes/services/session";
import AuthenticatedUserService from "hermes/services/authenticated-user";
import timeAgo from "hermes/utils/time-ago";
import { HermesDocument } from "hermes/types/document";

export default class DashboardRoute extends Route {
Expand Down
109 changes: 66 additions & 43 deletions web/app/routes/authenticated/document.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,49 @@
// @ts-nocheck - Not yet typed
import Route from "@ember/routing/route";
import { inject as service } from "@ember/service";
import timeAgo from "hermes/utils/time-ago";
import RSVP from "rsvp";
import parseDate from "hermes/utils/parse-date";
import htmlElement from "hermes/utils/html-element";
import { scheduleOnce } from "@ember/runloop";

const serializePeople = (people) =>
people.map((p) => ({
email: p.emailAddresses[0].value,
import { schedule } from "@ember/runloop";
import { GoogleUser } from "hermes/components/inputs/people-select";
import ConfigService from "hermes/services/config";
import FetchService from "hermes/services/fetch";
import RecentlyViewedDocsService from "hermes/services/recently-viewed-docs";
import AlgoliaService from "hermes/services/algolia";
import SessionService from "hermes/services/session";
import FlashMessageService from "ember-cli-flash/services/flash-messages";
import RouterService from "@ember/routing/router-service";
import { HermesDocument, HermesUser } from "hermes/types/document";
import Transition from "@ember/routing/transition";
import { HermesDocumentType } from "hermes/types/document-type";
import AuthenticatedDocumentController from "hermes/controllers/authenticated/document";

const serializePeople = (people: GoogleUser[]): HermesUser[] => {
return people.map((p) => ({
email: p.emailAddresses[0]?.value as string,
imgURL: p.photos?.[0]?.url,
}));
};

interface DocumentRouteParams {
document_id: string;
draft: boolean;
}

interface DocumentRouteModel {
doc: HermesDocument;
docType: HermesDocumentType;
}

export default class DocumentRoute extends Route {
@service algolia;
@service("config") configSvc;
@service("fetch") fetchSvc;
@service("recently-viewed-docs") recentDocs;
@service session;
@service flashMessages;
@service router;
@service("config") declare configSvcL: ConfigService;
@service("fetch") declare fetchSvc: FetchService;
@service("recently-viewed-docs")
declare recentDocs: RecentlyViewedDocsService;
@service declare algolia: AlgoliaService;
@service declare session: SessionService;
@service declare flashMessages: FlashMessageService;
@service declare router: RouterService;

declare controller: AuthenticatedDocumentController;

// Ideally we'd refresh the model when the draft query param changes, but
// because of a suspected bug in Ember, we can't do that.
Expand All @@ -31,7 +54,7 @@ export default class DocumentRoute extends Route {
// },
// };

showErrorMessage(err) {
showErrorMessage(err: Error) {
this.flashMessages.add({
title: "Error fetching document",
message: err.message,
Expand All @@ -41,7 +64,7 @@ export default class DocumentRoute extends Route {
});
}

async model(params, transition) {
async model(params: DocumentRouteParams, transition: Transition) {
let doc = {};
let draftFetched = false;

Expand All @@ -57,9 +80,8 @@ export default class DocumentRoute extends Route {
"Add-To-Recently-Viewed": "true",
},
})
.then((r) => r.json());

doc.isDraft = params.draft;
.then((r) => r?.json());
(doc as HermesDocument).isDraft = params.draft;
draftFetched = true;
} catch (err) {
/**
Expand All @@ -85,25 +107,24 @@ export default class DocumentRoute extends Route {
"Add-To-Recently-Viewed": "true",
},
})
.then((r) => r.json());
.then((r) => r?.json());

doc.isDraft = false;
(doc as HermesDocument).isDraft = false;
} catch (err) {
this.showErrorMessage(err);
const typedError = err as Error;
this.showErrorMessage(typedError);

// Transition to dashboard
this.router.transitionTo("authenticated.dashboard");
throw new Error(errorMessage);
throw new Error(typedError.message);
}
}

// With the document fetched and added to the db's RecentlyViewedDocs index,
// make a background call to update the front-end index.
void this.recentDocs.fetchAll.perform();

if (!!doc.createdTime) {
doc.createdDate = parseDate(doc.createdTime * 1000, "long");
}
let typedDoc = doc as HermesDocument;

// Record analytics.
try {
Expand All @@ -112,7 +133,7 @@ export default class DocumentRoute extends Route {
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
document_id: params.document_id,
product_name: doc.product,
product_name: typedDoc.product,
}),
});
} catch (err) {
Expand All @@ -122,37 +143,39 @@ export default class DocumentRoute extends Route {
// Load the document as well as the logged in user info

// Preload avatars for all approvers in the Algolia index.
if (doc.contributors?.length) {
if (typedDoc.contributors?.length) {
const contributors = await this.fetchSvc
.fetch(`/api/v1/people?emails=${doc.contributors.join(",")}`)
.then((r) => r.json());
.fetch(`/api/v1/people?emails=${typedDoc.contributors.join(",")}`)
.then((r) => r?.json());

if (contributors) {
doc.contributors = serializePeople(contributors);
typedDoc.contributors = serializePeople(contributors);
} else {
doc.contributors = [];
typedDoc.contributors = [];
}
}
if (doc.approvers?.length) {
if (typedDoc.approvers?.length) {
const approvers = await this.fetchSvc
.fetch(`/api/v1/people?emails=${doc.approvers.join(",")}`)
.then((r) => r.json());
.fetch(`/api/v1/people?emails=${typedDoc.approvers.join(",")}`)
.then((r) => r?.json());

if (approvers) {
doc.approvers = serializePeople(approvers);
typedDoc.approvers = serializePeople(approvers);
} else {
doc.approvers = [];
typedDoc.approvers = [];
}
}

let docTypes = await this.fetchSvc
.fetch("/api/v1/document-types")
.then((r) => r.json());
.then((r) => r?.json());

let docType = docTypes.find((docType) => docType.name === doc.docType);
let docType = docTypes.find(
(docType: HermesDocumentType) => docType.name === typedDoc.docType
);

return RSVP.hash({
doc,
doc: typedDoc,
docType,
});
}
Expand All @@ -164,7 +187,7 @@ export default class DocumentRoute extends Route {
* `modelIsChanging` property to remove and rerender the sidebar,
* resetting its local state to reflect the new model data.
*/
afterModel(model, transition) {
afterModel(_model: DocumentRouteModel, transition: any) {
if (transition.from) {
if (transition.from.name === transition.to.name) {
if (
Expand All @@ -175,7 +198,7 @@ export default class DocumentRoute extends Route {

htmlElement(".sidebar-body").scrollTop = 0;

scheduleOnce("afterRender", () => {
schedule("afterRender", () => {
this.controller.set("modelIsChanging", false);
});
}
Expand Down
26 changes: 20 additions & 6 deletions web/app/types/document.d.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,30 @@
import { GoogleUser } from "hermes/components/inputs/people-select";

/**
* NOTE: This is a partial type definition.
* We are defining it incrementally as we expand TS coverage.
*/
export interface HermesDocument {
readonly objectID: string;

status: string;
product?: string;
modifiedTime?: number; // Not available on drafts fetched as Hits from backend

/**
* A human-readable date string, e.g., "Aug 16, 2028".
* Mutated in the layout by the `parse-date` helper to place
* the date before the month.
*/
created: string;

/**
* A timestamp in seconds. Used for sorting.
*/
createdTime: number;

/**
* A timestamp in seconds. Used Translated by the `time-ago` helper
* into a human-readable string, e.g., "2 days ago."
* Not available on drafts fetched as Hits from backend.
*/
modifiedTime?: number;

docNumber: string;
docType: string;
title: string;
Expand All @@ -25,7 +40,6 @@ export interface HermesDocument {
isDraft?: boolean;
customEditableFields?: CustomEditableFields;

thumbnail?: string;
_snippetResult?: {
content: {
value: string;
Expand Down
2 changes: 1 addition & 1 deletion web/app/utils/time-ago.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export default function timeAgo(timeInSeconds: number) {
const now = Date.now();
const before = new Date(timeInSeconds * 1000).getTime();
const elapsed = now - before;

const elapsedSeconds = elapsed / 1000;

if (elapsedSeconds < 2) {
return "1 second ago";
}
Expand Down