Skip to content
This repository was archived by the owner on Dec 6, 2024. It is now read-only.

Commit f373bf2

Browse files
mabreuortegaMiguel Abreukharbutli-metafrancisco-j-romerotrietlu
authored
Merge-v1.1.6-onto-mainline (#738)
* Miguel.abreu/gtt 1648 fix nav colors (#717) * Fix locales tests * Adjust nav colors to match buttons Co-authored-by: Miguel Abreu <miabreu@amazon.com> * Adds backend support for copying dashboards (#719) * Backend support for copying dashboards. * Setup title configuration and update route titles (#720) * Setup title configuration and update route titles * Unit tests Co-authored-by: Miguel Abreu <miabreu@amazon.com> * Adds frontend support for copying dashboards (#725) * Frontend changes to copy dashboards * Added aria label and tab functionality to the Vertical Tabs component (#726) * change for release 1.1.6 * Add translation files for Portuguese and Spanish Co-authored-by: Miguel Abreu <miabreu@amazon.com> Co-authored-by: Mazen Kharbutli <89935687+mazenkh-amazon@users.noreply.github.com> Co-authored-by: francisco-j-romero <65923669+francisco-j-romero@users.noreply.github.com> Co-authored-by: Triet <triet05@gmail.com> Co-authored-by: Miguel Pavon Diaz <miguelpdiaz8@gmail.com>
1 parent adf83ad commit f373bf2

38 files changed

+1038
-343
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.1.6] - 2021-12-17
9+
10+
- Copy/duplicate an individual dashboard
11+
- Made improvements to meet accessibility requirements
12+
- Added text alternative to label images
13+
- Establish unique page titles
14+
- Made global button color changes
15+
- Introduced different visual indicators beyond color for line charts
16+
- Improved vertical tabs for accessibility
17+
818
## [1.1.5] - 2021-11-29
919

1020
- Made improvements to meet accessibility requirements

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ PDoA comes with pre-built code to provision an instance in your AWS account. You
3333

3434
| Region | Launch |
3535
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
36-
| Install in us-east-1 | [![Install in us-east-1](docs/images/launch-stack.svg)](https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/quickcreate?templateURL=https://performance-dashboard-on-aws-solution-releases-us-west-2.s3.us-west-2.amazonaws.com/performance-dashboard-on-aws/v1.1.5/performance-dashboard-on-aws.template) |
36+
| Install in us-east-1 | [![Install in us-east-1](docs/images/launch-stack.svg)](https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/quickcreate?templateURL=https://performance-dashboard-on-aws-solution-releases-us-west-2.s3.us-west-2.amazonaws.com/performance-dashboard-on-aws/v1.1.6/performance-dashboard-on-aws.template) |
3737

3838
### Clone this repository
3939

backend/package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "performance-dashboard-backend",
3-
"version": "1.1.5",
3+
"version": "1.1.6",
44
"description": "Performance Dashboard on AWS Backend",
55
"awssdkUserAgent": "AwsSolution/SO0157/v",
66
"scripts": {

backend/postman/Performance Dashboard API.postman_collection.json

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,50 @@
297297
},
298298
"response": []
299299
},
300+
{
301+
"name": "Copy Dashboard",
302+
"request": {
303+
"auth": {
304+
"type": "bearer",
305+
"bearer": [
306+
{
307+
"key": "token",
308+
"value": "{{token}}",
309+
"type": "string"
310+
}
311+
]
312+
},
313+
"method": "POST",
314+
"header": [],
315+
"body": {
316+
"mode": "raw",
317+
"raw": "{\n \"updatedAt\": \"2020-10-16T00:25:24.576Z\"\n}",
318+
"options": {
319+
"raw": {
320+
"language": "json"
321+
}
322+
}
323+
},
324+
"url": {
325+
"raw": "{{baseUrl}}/dashboard/:id/copy",
326+
"host": [
327+
"{{baseUrl}}"
328+
],
329+
"path": [
330+
"dashboard",
331+
":id",
332+
"copy"
333+
],
334+
"variable": [
335+
{
336+
"key": "id",
337+
"value": "49b1e4c5-c621-459b-96c4-66504a6b21eb"
338+
}
339+
]
340+
}
341+
},
342+
"response": []
343+
},
300344
{
301345
"name": "Archive Dashboard",
302346
"request": {

backend/src/lib/api/dashboard-api.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ router.put(
7070
errorHandler(DashboardCtrl.moveToDraftDashboard)
7171
);
7272

73+
router.post(
74+
"/:id/copy",
75+
rbac(Role.Admin, Role.Editor),
76+
errorHandler(DashboardCtrl.copyDashboard)
77+
);
78+
7379
router.put(
7480
"/:id/widgetorder",
7581
rbac(Role.Admin, Role.Editor),

backend/src/lib/controllers/__tests__/dashboard-ctrl.test.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import FriendlyURLService from "../../services/friendlyurl-service";
1313
import DashboardRepository from "../../repositories/dashboard-repo";
1414
import TopicAreaRepository from "../../repositories/topicarea-repo";
1515
import dashboardCtrl from "../dashboard-ctrl";
16+
import { WidgetType } from "../../models/widget";
1617

1718
jest.mock("../../repositories/dashboard-repo");
1819
jest.mock("../../repositories/topicarea-repo");
@@ -845,3 +846,53 @@ describe("getPublicDashboardByFriendlyURL", () => {
845846
expect(res.send).toBeCalledWith("Dashboard not found");
846847
});
847848
});
849+
850+
describe("copyDashboard", () => {
851+
let req: Request;
852+
let dashboard: Dashboard;
853+
beforeEach(() => {
854+
req = {
855+
user,
856+
params: {
857+
id: "abcdef00",
858+
},
859+
} as any as Request;
860+
861+
dashboard = {
862+
id: "abcdef00",
863+
version: 3,
864+
parentDashboardId: "abcdef00",
865+
name: "My Dashboard",
866+
topicAreaId: "abc",
867+
topicAreaName: "My Topic Area",
868+
displayTableOfContents: false,
869+
updatedAt: new Date(),
870+
createdBy: "johndoe",
871+
state: DashboardState.Published,
872+
description: "",
873+
widgets: [
874+
{
875+
id: "12345678",
876+
name: "Text Widget",
877+
widgetType: WidgetType.Text,
878+
dashboardId: "abcdef00",
879+
order: 0,
880+
updatedAt: new Date(),
881+
showTitle: true,
882+
content: {
883+
text: "Just some simple text.",
884+
},
885+
},
886+
],
887+
releaseNotes: "Release note test",
888+
};
889+
});
890+
891+
it("creates a copy dashboard in draft state", async () => {
892+
repository.getDashboardWithWidgets = jest.fn().mockReturnValue(dashboard);
893+
894+
await DashboardCtrl.copyDashboard(req, res);
895+
896+
expect(repository.saveDashboardAndWidgets).toBeCalledTimes(2);
897+
});
898+
});

backend/src/lib/controllers/dashboard-ctrl.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,23 @@ async function createNewDraft(req: Request, res: Response) {
352352
return res.json(draft);
353353
}
354354

355+
async function copyDashboard(req: Request, res: Response) {
356+
const user = req.user;
357+
const { id } = req.params;
358+
359+
const repo = DashboardRepository.getInstance();
360+
361+
const origDashboard = await repo.getDashboardWithWidgets(id);
362+
363+
const newDashboard = DashboardFactory.createCopyFromDashboard(
364+
origDashboard,
365+
user
366+
);
367+
368+
await repo.saveDashboardAndWidgets(newDashboard);
369+
res.json(newDashboard);
370+
}
371+
355372
export default {
356373
listDashboards,
357374
createDashboard,
@@ -367,4 +384,5 @@ export default {
367384
deleteDashboards,
368385
getPublicDashboardById,
369386
createNewDraft,
387+
copyDashboard,
370388
};

backend/src/lib/factories/__tests__/dashboard-factory.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
DashboardState,
66
} from "../../models/dashboard";
77
import { User } from "../../models/user";
8+
import { convertCompilerOptionsFromJson } from "typescript";
89

910
const user: User = {
1011
userId: "johndoe",
@@ -304,3 +305,34 @@ describe("createDraftFromDashboard", () => {
304305
expect(draft.friendlyURL).toBeUndefined();
305306
});
306307
});
308+
309+
describe("createCopyFromDashboard", () => {
310+
const dashboard: Dashboard = {
311+
id: "123",
312+
version: 3,
313+
parentDashboardId: "123",
314+
name: "Original Dashboard",
315+
topicAreaId: "456",
316+
topicAreaName: "Topic 1",
317+
displayTableOfContents: false,
318+
description: "Description original dashboard",
319+
createdBy: user.userId,
320+
updatedAt: new Date(),
321+
state: DashboardState.Published,
322+
releaseNotes: "release note test",
323+
};
324+
325+
it("Should create a copy of the original dashboard", () => {
326+
const copy = factory.createCopyFromDashboard(dashboard, user);
327+
328+
expect(copy.id).not.toEqual(dashboard.id);
329+
expect(copy.name).toEqual("Copy of Original Dashboard");
330+
expect(copy.version).toEqual(1);
331+
expect(copy.topicAreaId).toEqual(dashboard.topicAreaId);
332+
expect(copy.topicAreaName).toEqual(dashboard.topicAreaName);
333+
expect(copy.createdBy).toEqual(dashboard.createdBy);
334+
expect(copy.state).toEqual(DashboardState.Draft);
335+
expect(copy.parentDashboardId).not.toEqual(dashboard.parentDashboardId);
336+
expect(copy.friendlyURL).toBeUndefined();
337+
});
338+
});

backend/src/lib/factories/dashboard-factory.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,55 @@ function createDraftFromDashboard(
8686
};
8787
}
8888

89+
function createCopyFromDashboard(dashboard: Dashboard, user: User): Dashboard {
90+
const id = uuidv4();
91+
92+
// Copy all widgets associated with the dashboard.
93+
let widgets: Array<Widget> = [];
94+
if (dashboard.widgets) {
95+
widgets = dashboard.widgets.map((widget) =>
96+
WidgetFactory.createFromWidget(id, widget)
97+
);
98+
for (const widget of widgets) {
99+
if (widget.section) {
100+
const sectionIndex = dashboard.widgets.findIndex(
101+
(w) => w.id === widget.section
102+
);
103+
widget.section = widgets[sectionIndex].id;
104+
}
105+
if (widget.content && widget.content.widgetIds) {
106+
const widgetIds: string[] = [];
107+
for (const id of widget.content.widgetIds) {
108+
const widgetIndex = dashboard.widgets.findIndex((w) => w.id === id);
109+
widgetIds.push(widgets[widgetIndex].id);
110+
}
111+
widget.content.widgetIds = widgetIds;
112+
}
113+
}
114+
}
115+
116+
return {
117+
id,
118+
name: "Copy of " + dashboard.name,
119+
version: 1,
120+
parentDashboardId: id,
121+
topicAreaId: dashboard.topicAreaId,
122+
topicAreaName: dashboard.topicAreaName,
123+
displayTableOfContents: dashboard.displayTableOfContents,
124+
tableOfContents: dashboard.tableOfContents,
125+
description: dashboard.description,
126+
state: DashboardState.Draft,
127+
createdBy: user.userId,
128+
updatedAt: new Date(),
129+
updatedBy: user.userId,
130+
submittedBy: undefined,
131+
publishedBy: undefined,
132+
archivedBy: undefined,
133+
widgets,
134+
friendlyURL: undefined,
135+
};
136+
}
137+
89138
/**
90139
* Converts a Dashboard to a DynamoDB item.
91140
*/
@@ -177,6 +226,7 @@ function toVersion(dashboard: Dashboard): DashboardVersion {
177226
export default {
178227
createNew,
179228
createDraftFromDashboard,
229+
createCopyFromDashboard,
180230
toItem,
181231
fromItem,
182232
itemId,

0 commit comments

Comments
 (0)