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 Project::Tile component #379

Merged
merged 13 commits into from
Oct 25, 2023
54 changes: 54 additions & 0 deletions web/app/components/project/tile.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<Hds::Card::Container
data-test-project-tile
@hasBorder={{true}}
@levelHover="mid"
class="project-tile h-48 p-4"
...attributes
>
<div class="relative h-full pb-16">
<h3
data-test-title
class="title text-display-300 font-semibold text-color-foreground-strong"
>
{{@project.title}}
</h3>
{{#if @project.description}}
<p
data-test-description
class="description mt-1 text-body-300 text-color-foreground-faint"
>
{{@project.description}}
</p>
{{/if}}

<div
class="absolute bottom-0 left-0 flex w-full items-center justify-between"
>
{{#if this.productAreas}}
<ul class="flex gap-px">
{{#each this.productAreas as |productArea|}}
<li class="flex items-center" data-test-product>
{{productArea}}
</li>
{{/each}}
</ul>
{{/if}}
{{#if this.jiraObject}}
<div class="flex items-center gap-1.5">
{{#if @project.jiraObject.type}}
<span data-test-jira-type>
{{@project.jiraObject.type}}
</span>
{{/if}}
<span
data-test-jira-key
class="text-body-100 text-color-foreground-faint
{{if (eq this.jiraObject.status 'Done') 'line-through'}}"
>
{{this.jiraObject.key}}
</span>
</div>
{{/if}}
</div>
</div>
</Hds::Card::Container>
29 changes: 29 additions & 0 deletions web/app/components/project/tile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Component from "@glimmer/component";
import { HermesProject } from "hermes/types/project";

interface ProjectTileComponentSignature {
Element: HTMLDivElement;
Args: {
project: HermesProject;
};
}

export default class ProjectTileComponent extends Component<ProjectTileComponentSignature> {
protected get documents() {
return this.args.project.documents;
}

protected get jiraObject() {
return this.args.project.jiraObject;
}

protected get productAreas() {
return this.documents?.map((doc) => doc.product).uniq();
}
}

declare module "@glint/environment-ember-loose/registry" {
export default interface Registry {
"Project::Tile": typeof ProjectTileComponent;
}
}
3 changes: 2 additions & 1 deletion web/app/styles/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
@use "components/doc/tile-list";
@use "components/doc/thumbnail";
@use "components/doc/folder-affordance";
@use "components/doc/tile";
@use "components/doc/tile" as doc-tile;
@use "components/doc/state";
@use "components/table/sortable-header";
@use "components/preview-card";
Expand All @@ -38,6 +38,7 @@
@use "components/document/related-resources";
@use "components/hds-badge";
@use "components/product-badge-link";
@use "components/project/tile" as project-tile;
@use "components/header/facet-dropdown";
@use "components/floating-u-i/content";
@use "components/settings/subscription-list-item";
Expand Down
18 changes: 18 additions & 0 deletions web/app/styles/components/project/tile.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.project-tile {
.title,
.description {
@apply overflow-hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
}

.title {
-webkit-line-clamp: 2;
line-clamp: 2;
}

.description {
-webkit-line-clamp: 3;
line-clamp: 3;
}
}
6 changes: 4 additions & 2 deletions web/app/templates/authenticated/projects/index.hbs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
{{page-title "All Projects"}}

<ol>
<ol class="relative grid grid-cols-3 gap-2">
{{#each-in this.model as |_id project|}}
<li data-test-project>
{{project.title}}
<LinkTo @route="authenticated.projects.project" @model={{project.id}}>
<Project::Tile @project={{project}} />
</LinkTo>
</li>
{{/each-in}}
</ol>
12 changes: 12 additions & 0 deletions web/mirage/factories/jira-object.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Factory } from "miragejs";

export default Factory.extend({
id: (i) => i,
key: (i) => `KEY-00${i}`,
url: "",
priority: "Medium",
status: "Open",
assignee: "Unassigned",
type: "Task",
summary: "This is a Jira object",
});
20 changes: 19 additions & 1 deletion web/mirage/factories/project.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,27 @@
import { Factory } from "miragejs";
import { Factory, ModelInstance, Server } from "miragejs";
import { HermesProject } from "hermes/types/project";

export default Factory.extend({
id: (i: number) => i,
title: (i: number) => `Test Project ${i}`,
dateCreated: 1,
dateModified: 1,
creator: "[email protected]",

// @ts-ignore - Bug https://github.com/miragejs/miragejs/issues/1052
afterCreate(project: ModelInstance<HermesProject>, server: any): void {
server.createList("related-hermes-document", 1);
server.create("jira-object");

const relatedHermesDocuments = server.schema.relatedHermesDocument
.all()
.models.map((doc: ModelInstance) => doc.attrs);

const jiraObject = server.schema.jiraObjects.first()?.attrs;

project.update({
documents: relatedHermesDocuments,
jiraObject,
});
},
});
5 changes: 5 additions & 0 deletions web/mirage/models/jira-object.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Model } from "miragejs";

export default Model.extend({
// Required for Mirage, even though it's empty
});
59 changes: 56 additions & 3 deletions web/tests/acceptance/authenticated/projects-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ import { getPageTitle } from "ember-page-title/test-support";
import { setupApplicationTest } from "ember-qunit";
import { HermesProject } from "hermes/types/project";

const PROJECT_TILE = "[data-test-project-tile]";
const PROJECT_TITLE = `${PROJECT_TILE} [data-test-title]`;
const PROJECT_DESCRIPTION = `${PROJECT_TILE} [data-test-description]`;
const PROJECT_PRODUCT = `${PROJECT_TILE} [data-test-product]`;
const PROJECT_JIRA_TYPE = `${PROJECT_TILE} [data-test-jira-type]`;
const PROJECT_JIRA_KEY = `${PROJECT_TILE} [data-test-jira-key]`;

interface AuthenticatedProjectsRouteTestContext extends MirageTestContext {}
module("Acceptance | authenticated/projects", function (hooks) {
setupApplicationTest(hooks);
Expand All @@ -27,14 +34,60 @@ module("Acceptance | authenticated/projects", function (hooks) {

assert.dom("[data-test-project]").exists({ count: 3 });

const expectedTitles = this.server.schema.projects
let expectedTitles: string[] = [];
let expectedDescriptions: string[] = [];
let expectedProducts: string[] = [];
let expectedKeys: string[] = [];
let expectedJiraTypes: string[] = [];

this.server.schema.projects
.all()
.models.map((project: HermesProject) => project.title);
.models.forEach((project: HermesProject) => {
expectedTitles.push(project.title);

if (project.description) {
expectedDescriptions.push(project.description);
}

if (project.jiraObject) {
expectedKeys.push(project.jiraObject.key);
if (project.jiraObject.type) {
expectedJiraTypes.push(project.jiraObject.type);
}
}
if (project.documents) {
project.documents.forEach((doc) => {
if (doc.product) {
expectedProducts.push(doc.product);
}
});
}
});

const renderedTitles = findAll(PROJECT_TITLE).map(
(e) => e.textContent?.trim(),
);

const renderedDescriptions = findAll(PROJECT_DESCRIPTION).map(
(e) => e.textContent?.trim(),
);

const renderedProducts = findAll(PROJECT_PRODUCT).map(
(e) => e.textContent?.trim(),
);

const renderedKeys = findAll(PROJECT_JIRA_KEY).map(
(e) => e.textContent?.trim(),
);

const renderedTitles = findAll("[data-test-project]").map(
const renderedJiraTypes = findAll(PROJECT_JIRA_TYPE).map(
(e) => e.textContent?.trim(),
);

assert.deepEqual(renderedTitles, expectedTitles);
assert.deepEqual(renderedDescriptions, expectedDescriptions);
assert.deepEqual(renderedProducts, expectedProducts);
assert.deepEqual(renderedKeys, expectedKeys);
assert.deepEqual(renderedJiraTypes, expectedJiraTypes);
});
});
Loading