@raketa-cloud/admin 0.0.97 → 0.0.99
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/Adapter.js +5 -1
- package/src/cloud/ArticleChanges.js +24 -3
- package/src/cloud/EventChanges.js +24 -3
- package/src/cloud/PageChanges.js +24 -3
- package/src/cloud/Pages.js +1 -1
- package/src/cloud/documents/articlesDocuments.js +18 -5
- package/src/cloud/documents/common.js +2 -0
- package/src/cloud/documents/eventsDocuments.js +17 -4
- package/src/cloud/documents/pagesDocuments.js +17 -4
- package/src/handlers/articles/ArticlesHandler.js +2 -2
- package/src/handlers/articles/HistoryHandler.js +31 -0
- package/src/handlers/events/EventsHandler.js +2 -2
- package/src/handlers/events/HistoryHandler.js +31 -0
- package/src/handlers/pages/HistoryHandler.js +31 -0
- package/src/handlers/pages/PagesHandler.js +2 -2
- package/src/helpers/historyUtils.js +133 -0
- package/src/helpers/utils.js +21 -0
- package/src/routeArticlesModule.js +19 -13
- package/src/routeEventsModule.js +18 -12
- package/src/routePagesModule.js +7 -1
- package/src/tests/handlers/articles/ArticlesHandler.test/show.test.js +5 -5
- package/src/tests/handlers/articles/ArticlesHistoryHandler.test/index.test.js +87 -0
- package/src/tests/handlers/events/EventsHandler.test/show.test.js +5 -5
- package/src/tests/handlers/events/EventsHistoryHandler.test/index.test.js +87 -0
- package/src/tests/handlers/pages/PagesHandler.test/show.test.js +5 -5
- package/src/tests/handlers/pages/PagesHistoryHandler.test/index.test.js +87 -0
- package/src/tests/helpers/historyUtils.test.js +107 -0
- package/src/tests/helpers/utils.test.js +27 -0
- package/src/views/articles/_shared/_history_toolbar.ejs +9 -8
- package/src/views/articles/_shared/history_table.ejs +68 -0
- package/src/views/articles/history/index.ejs +87 -0
- package/src/views/articles/index.ejs +1 -1
- package/src/views/articles/show.ejs +12 -52
- package/src/views/events/_shared/_history_toolbar.ejs +9 -8
- package/src/views/events/_shared/history_table.ejs +68 -0
- package/src/views/events/history/index.ejs +87 -0
- package/src/views/events/index.ejs +1 -1
- package/src/views/events/show.ejs +12 -52
- package/src/views/pages/_shared/_history_toolbar.ejs +8 -7
- package/src/views/pages/_shared/history_table.ejs +68 -0
- package/src/views/pages/history/index.ejs +87 -0
- package/src/views/pages/index.ejs +1 -1
- package/src/views/pages/show.ejs +12 -52
package/src/routeEventsModule.js
CHANGED
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import routeNestedMember from "./routeNestedMember";
|
|
4
|
-
import TranslationsHandler from "./handlers/events/TranslationsHandler";
|
|
1
|
+
import CancelSchedulesHandler from "./handlers/event_revisions/CancelSchedulesHandler";
|
|
2
|
+
import CodeHandler from "./handlers/event_revisions/CodeHandler";
|
|
5
3
|
import EventRevisionsHandler from "./handlers/event_revisions/EventRevisionsHandler";
|
|
6
4
|
import GeneralHandler from "./handlers/event_revisions/GeneralHandler";
|
|
7
|
-
import
|
|
8
|
-
import CodeHandler from "./handlers/event_revisions/CodeHandler";
|
|
5
|
+
import LocksHandler from "./handlers/event_revisions/LocksHandler";
|
|
9
6
|
import MetaHandler from "./handlers/event_revisions/MetaHandler";
|
|
7
|
+
import PublishesHandler from "./handlers/event_revisions/PublishesHandler";
|
|
8
|
+
import RevertsHandler from "./handlers/event_revisions/RevertsHandler";
|
|
10
9
|
import TagHandler from "./handlers/event_revisions/TagHandler";
|
|
11
|
-
import LocksHandler from "./handlers/event_revisions/LocksHandler";
|
|
12
10
|
import UnlocksHandler from "./handlers/event_revisions/UnlocksHandler";
|
|
11
|
+
import VisualHandler from "./handlers/event_revisions/VisualHandler";
|
|
12
|
+
import WidgetHandler from "./handlers/event_revisions/WidgetHandler";
|
|
13
13
|
import ClonesHandler from "./handlers/events/ClonesHandler";
|
|
14
|
-
import URLsHandler from "./handlers/events/URLsHandler";
|
|
15
14
|
import DeletesHandler from "./handlers/events/DeletesHandler";
|
|
16
|
-
import RevertsHandler from "./handlers/event_revisions/RevertsHandler";
|
|
17
|
-
import PublishesHandler from "./handlers/event_revisions/PublishesHandler";
|
|
18
|
-
import WidgetHandler from "./handlers/event_revisions/WidgetHandler";
|
|
19
15
|
import EventsHandler from "./handlers/events/EventsHandler";
|
|
20
|
-
import
|
|
16
|
+
import HistoryHandler from "./handlers/events/HistoryHandler";
|
|
17
|
+
import TranslationsHandler from "./handlers/events/TranslationsHandler";
|
|
18
|
+
import URLsHandler from "./handlers/events/URLsHandler";
|
|
19
|
+
import routeCollection from "./routeCollection";
|
|
20
|
+
import routeNestedCollection from "./routeNestedCollection";
|
|
21
|
+
import routeNestedMember from "./routeNestedMember";
|
|
21
22
|
|
|
22
23
|
function routeEventsModule(
|
|
23
24
|
adapter,
|
|
@@ -48,6 +49,11 @@ function routeEventsModule(
|
|
|
48
49
|
}
|
|
49
50
|
);
|
|
50
51
|
|
|
52
|
+
routeNestedCollection(adapter, baseResource, "history", HistoryHandler, {
|
|
53
|
+
...resourceConfig,
|
|
54
|
+
viewsFallback: "events/history",
|
|
55
|
+
});
|
|
56
|
+
|
|
51
57
|
routeNestedCollection(
|
|
52
58
|
adapter,
|
|
53
59
|
baseResource,
|
package/src/routePagesModule.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import CancelSchedulesHandler from "./handlers/page_revisions/CancelSchedulesHandler";
|
|
1
2
|
import CodeHandler from "./handlers/page_revisions/CodeHandler";
|
|
2
3
|
import GeneralHandler from "./handlers/page_revisions/GeneralHandler";
|
|
3
4
|
import LocksHandler from "./handlers/page_revisions/LocksHandler";
|
|
@@ -11,13 +12,13 @@ import VisualHandler from "./handlers/page_revisions/VisualHandler";
|
|
|
11
12
|
import WidgetHandler from "./handlers/page_revisions/WidgetHandler";
|
|
12
13
|
import ClonesHandler from "./handlers/pages/ClonesHandler";
|
|
13
14
|
import DeletesHandler from "./handlers/pages/DeletesHandler";
|
|
15
|
+
import HistoryHandler from "./handlers/pages/HistoryHandler";
|
|
14
16
|
import PagesHandler from "./handlers/pages/PagesHandler";
|
|
15
17
|
import TranslationsHandler from "./handlers/pages/TranslationsHandler";
|
|
16
18
|
import URLsHandler from "./handlers/pages/URLsHandler";
|
|
17
19
|
import routeCollection from "./routeCollection";
|
|
18
20
|
import routeNestedCollection from "./routeNestedCollection";
|
|
19
21
|
import routeNestedMember from "./routeNestedMember";
|
|
20
|
-
import CancelSchedulesHandler from "./handlers/page_revisions/CancelSchedulesHandler";
|
|
21
22
|
|
|
22
23
|
function routePagesModule(
|
|
23
24
|
adapter,
|
|
@@ -45,6 +46,11 @@ function routePagesModule(
|
|
|
45
46
|
{ ...resourceConfig, viewsFallback: "pages/translations" }
|
|
46
47
|
);
|
|
47
48
|
|
|
49
|
+
routeNestedCollection(adapter, baseResource, "history", HistoryHandler, {
|
|
50
|
+
...resourceConfig,
|
|
51
|
+
viewsFallback: "pages/history",
|
|
52
|
+
});
|
|
53
|
+
|
|
48
54
|
routeNestedCollection(
|
|
49
55
|
adapter,
|
|
50
56
|
baseResource,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import ArticlesHandler from "../../../../handlers/articles/ArticlesHandler";
|
|
2
|
-
import Articles from "../../../../cloud/Articles";
|
|
3
1
|
import ArticleChanges from "../../../../cloud/ArticleChanges";
|
|
4
2
|
import ArticleRevisions from "../../../../cloud/ArticleRevisions";
|
|
3
|
+
import Articles from "../../../../cloud/Articles";
|
|
4
|
+
import ArticlesHandler from "../../../../handlers/articles/ArticlesHandler";
|
|
5
5
|
|
|
6
6
|
import Factory from "../../../support/factory";
|
|
7
7
|
|
|
@@ -65,20 +65,20 @@ describe("Articles Handler", () => {
|
|
|
65
65
|
.mockImplementation(() => ({ list: [revision] }));
|
|
66
66
|
|
|
67
67
|
const mockedArticleChanges = jest
|
|
68
|
-
.spyOn(ctx.client.articleChanges, "
|
|
68
|
+
.spyOn(ctx.client.articleChanges, "list")
|
|
69
69
|
.mockImplementation(() => ({ list: [change] }));
|
|
70
70
|
|
|
71
71
|
const result = await ArticlesHandler.show(ctx);
|
|
72
72
|
|
|
73
73
|
expect(mockedArticleFind).toHaveBeenCalledWith(article.id, "en");
|
|
74
74
|
expect(mockedArticleRevisions).toHaveBeenCalledWith(article.id, "en");
|
|
75
|
-
expect(mockedArticleChanges).toHaveBeenCalledWith(article.id, "en");
|
|
75
|
+
expect(mockedArticleChanges).toHaveBeenCalledWith({}, article.id, "en");
|
|
76
76
|
|
|
77
77
|
expect(result).toEqual({
|
|
78
78
|
assigns: {
|
|
79
79
|
resource: article,
|
|
80
80
|
revisions: [revision],
|
|
81
|
-
changes: [change],
|
|
81
|
+
changes: { list: [change] },
|
|
82
82
|
_translations: [
|
|
83
83
|
{
|
|
84
84
|
locale: "bg",
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import ArticleChanges from "../../../../cloud/ArticleChanges";
|
|
2
|
+
import Articles from "../../../../cloud/Articles";
|
|
3
|
+
import ArticlesHandler from "../../../../handlers/articles/ArticlesHandler";
|
|
4
|
+
import HistoryHandler from "../../../../handlers/articles/HistoryHandler";
|
|
5
|
+
import Factory from "../../../support/factory";
|
|
6
|
+
|
|
7
|
+
describe("Articles History Handler", () => {
|
|
8
|
+
function buildHistoryCtx() {
|
|
9
|
+
return {
|
|
10
|
+
client: {
|
|
11
|
+
articles: new Articles(() => ({}), "token"),
|
|
12
|
+
articleChanges: new ArticleChanges(() => ({}), "token"),
|
|
13
|
+
},
|
|
14
|
+
query: { foo: "bar" },
|
|
15
|
+
locale: "en",
|
|
16
|
+
params: {
|
|
17
|
+
parent_id: "123",
|
|
18
|
+
},
|
|
19
|
+
resourceConfig: {
|
|
20
|
+
articleType: "article",
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
test("successfully returns history data", async () => {
|
|
26
|
+
const ctx = buildHistoryCtx();
|
|
27
|
+
const article = Factory.build("article");
|
|
28
|
+
const changes = {
|
|
29
|
+
list: [
|
|
30
|
+
{ operatorMeta: { name: "John Travolta" } },
|
|
31
|
+
{ operatorMeta: { name: "Generic Jane Smith" } },
|
|
32
|
+
],
|
|
33
|
+
pagination: Factory.build("pagination"),
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
jest.spyOn(ctx.client.articles, "find").mockImplementation(() => article);
|
|
37
|
+
jest
|
|
38
|
+
.spyOn(ctx.client.articleChanges, "list")
|
|
39
|
+
.mockImplementation(() => changes);
|
|
40
|
+
jest
|
|
41
|
+
.spyOn(ctx.client.articleChanges, "all_editors")
|
|
42
|
+
.mockImplementation(() => ["John Travolta", "Generic Jane Smith"]);
|
|
43
|
+
|
|
44
|
+
const result = await HistoryHandler.index(ctx);
|
|
45
|
+
|
|
46
|
+
expect(result).toEqual({
|
|
47
|
+
assigns: {
|
|
48
|
+
resource: article,
|
|
49
|
+
changes: changes,
|
|
50
|
+
editors: ["John Travolta", "Generic Jane Smith"],
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("throws error when article is not found", async () => {
|
|
56
|
+
const ctx = buildHistoryCtx();
|
|
57
|
+
jest.spyOn(ctx.client.articles, "find").mockImplementation(() => null);
|
|
58
|
+
|
|
59
|
+
await expect(HistoryHandler.index(ctx)).rejects.toThrow(
|
|
60
|
+
"Missing article #123"
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("returns unique editors list", async () => {
|
|
65
|
+
const ctx = buildHistoryCtx();
|
|
66
|
+
const article = Factory.build("article");
|
|
67
|
+
const changes = {
|
|
68
|
+
list: [
|
|
69
|
+
{ operatorMeta: { name: "John Travolta" } },
|
|
70
|
+
{ operatorMeta: { name: "John Travolta" } },
|
|
71
|
+
],
|
|
72
|
+
pagination: Factory.build("pagination"),
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
jest.spyOn(ctx.client.articles, "find").mockImplementation(() => article);
|
|
76
|
+
jest
|
|
77
|
+
.spyOn(ctx.client.articleChanges, "list")
|
|
78
|
+
.mockImplementation(() => changes);
|
|
79
|
+
jest
|
|
80
|
+
.spyOn(ctx.client.articleChanges, "all_editors")
|
|
81
|
+
.mockImplementation(() => ["John Travolta"]);
|
|
82
|
+
|
|
83
|
+
const result = await HistoryHandler.index(ctx);
|
|
84
|
+
|
|
85
|
+
expect(result.assigns.editors).toEqual(["John Travolta"]);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import EventsHandler from "../../../../handlers/events/EventsHandler";
|
|
2
|
-
import Events from "../../../../cloud/Events";
|
|
3
1
|
import EventChanges from "../../../../cloud/EventChanges";
|
|
4
2
|
import EventRevisions from "../../../../cloud/EventRevisions";
|
|
3
|
+
import Events from "../../../../cloud/Events";
|
|
4
|
+
import EventsHandler from "../../../../handlers/events/EventsHandler";
|
|
5
5
|
|
|
6
6
|
import Factory from "../../../support/factory";
|
|
7
7
|
|
|
@@ -65,20 +65,20 @@ describe("Events Handler", () => {
|
|
|
65
65
|
.mockImplementation(() => ({ list: [revision] }));
|
|
66
66
|
|
|
67
67
|
const mockedEventChanges = jest
|
|
68
|
-
.spyOn(ctx.client.eventChanges, "
|
|
68
|
+
.spyOn(ctx.client.eventChanges, "list")
|
|
69
69
|
.mockImplementation(() => ({ list: [change] }));
|
|
70
70
|
|
|
71
71
|
const result = await EventsHandler.show(ctx);
|
|
72
72
|
|
|
73
73
|
expect(mockedeventFind).toHaveBeenCalledWith(event.id, "en");
|
|
74
74
|
expect(mockedEventRevisions).toHaveBeenCalledWith(event.id, "en");
|
|
75
|
-
expect(mockedEventChanges).toHaveBeenCalledWith(event.id, "en");
|
|
75
|
+
expect(mockedEventChanges).toHaveBeenCalledWith({}, event.id, "en");
|
|
76
76
|
|
|
77
77
|
expect(result).toEqual({
|
|
78
78
|
assigns: {
|
|
79
79
|
resource: event,
|
|
80
80
|
revisions: [revision],
|
|
81
|
-
changes: [change],
|
|
81
|
+
changes: { list: [change] },
|
|
82
82
|
_translations: [
|
|
83
83
|
{
|
|
84
84
|
locale: "bg",
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import EventChanges from "../../../../cloud/EventChanges";
|
|
2
|
+
import Events from "../../../../cloud/Events";
|
|
3
|
+
import EventsHandler from "../../../../handlers/events/EventsHandler";
|
|
4
|
+
import HistoryHandler from "../../../../handlers/events/HistoryHandler";
|
|
5
|
+
import Factory from "../../../support/factory";
|
|
6
|
+
|
|
7
|
+
describe("Events History Handler", () => {
|
|
8
|
+
function buildHistoryCtx() {
|
|
9
|
+
return {
|
|
10
|
+
client: {
|
|
11
|
+
events: new Events(() => ({}), "token"),
|
|
12
|
+
eventChanges: new EventChanges(() => ({}), "token"),
|
|
13
|
+
},
|
|
14
|
+
query: { foo: "bar" },
|
|
15
|
+
locale: "en",
|
|
16
|
+
params: {
|
|
17
|
+
parent_id: "123",
|
|
18
|
+
},
|
|
19
|
+
resourceConfig: {
|
|
20
|
+
eventType: "event",
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
test("successfully returns history data", async () => {
|
|
26
|
+
const ctx = buildHistoryCtx();
|
|
27
|
+
const event = Factory.build("event");
|
|
28
|
+
const changes = {
|
|
29
|
+
list: [
|
|
30
|
+
{ operatorMeta: { name: "Generic John Doe" } },
|
|
31
|
+
{ operatorMeta: { name: "Generic Jane Smith" } },
|
|
32
|
+
],
|
|
33
|
+
pagination: Factory.build("pagination"),
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
jest.spyOn(ctx.client.events, "find").mockImplementation(() => event);
|
|
37
|
+
jest
|
|
38
|
+
.spyOn(ctx.client.eventChanges, "list")
|
|
39
|
+
.mockImplementation(() => changes);
|
|
40
|
+
jest
|
|
41
|
+
.spyOn(ctx.client.eventChanges, "all_editors")
|
|
42
|
+
.mockImplementation(() => ["Generic John Doe", "Generic Jane Smith"]);
|
|
43
|
+
|
|
44
|
+
const result = await HistoryHandler.index(ctx);
|
|
45
|
+
|
|
46
|
+
expect(result).toEqual({
|
|
47
|
+
assigns: {
|
|
48
|
+
resource: event,
|
|
49
|
+
changes: changes,
|
|
50
|
+
editors: ["Generic John Doe", "Generic Jane Smith"],
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("throws error when event is not found", async () => {
|
|
56
|
+
const ctx = buildHistoryCtx();
|
|
57
|
+
jest.spyOn(ctx.client.events, "find").mockImplementation(() => null);
|
|
58
|
+
|
|
59
|
+
await expect(HistoryHandler.index(ctx)).rejects.toThrow(
|
|
60
|
+
"Missing event #123"
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("returns unique editors list", async () => {
|
|
65
|
+
const ctx = buildHistoryCtx();
|
|
66
|
+
const event = Factory.build("event");
|
|
67
|
+
const changes = {
|
|
68
|
+
list: [
|
|
69
|
+
{ operatorMeta: { name: "Generic John Doe" } },
|
|
70
|
+
{ operatorMeta: { name: "Generic John Doe" } },
|
|
71
|
+
],
|
|
72
|
+
pagination: Factory.build("pagination"),
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
jest.spyOn(ctx.client.events, "find").mockImplementation(() => event);
|
|
76
|
+
jest
|
|
77
|
+
.spyOn(ctx.client.eventChanges, "list")
|
|
78
|
+
.mockImplementation(() => changes);
|
|
79
|
+
jest
|
|
80
|
+
.spyOn(ctx.client.eventChanges, "all_editors")
|
|
81
|
+
.mockImplementation(() => ["Generic John Doe"]);
|
|
82
|
+
|
|
83
|
+
const result = await HistoryHandler.index(ctx);
|
|
84
|
+
|
|
85
|
+
expect(result.assigns.editors).toEqual(["Generic John Doe"]);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import PagesHandler from "../../../../handlers/pages/PagesHandler";
|
|
2
|
-
import Pages from "../../../../cloud/Pages";
|
|
3
1
|
import PageChanges from "../../../../cloud/PageChanges";
|
|
4
2
|
import PageRevisions from "../../../../cloud/PageRevisions";
|
|
3
|
+
import Pages from "../../../../cloud/Pages";
|
|
4
|
+
import PagesHandler from "../../../../handlers/pages/PagesHandler";
|
|
5
5
|
|
|
6
6
|
import Factory from "../../../support/factory";
|
|
7
7
|
|
|
@@ -63,20 +63,20 @@ describe("Pages Handler", () => {
|
|
|
63
63
|
.mockImplementation(() => ({ list: [revision] }));
|
|
64
64
|
|
|
65
65
|
const mockedPageChanges = jest
|
|
66
|
-
.spyOn(ctx.client.pageChanges, "
|
|
66
|
+
.spyOn(ctx.client.pageChanges, "list")
|
|
67
67
|
.mockImplementation(() => ({ list: [change] }));
|
|
68
68
|
|
|
69
69
|
const result = await PagesHandler.show(ctx);
|
|
70
70
|
|
|
71
71
|
expect(mockedPageFind).toHaveBeenCalledWith(page.id, "en");
|
|
72
72
|
expect(mockedPageRevisions).toHaveBeenCalledWith(page.id, "en");
|
|
73
|
-
expect(mockedPageChanges).toHaveBeenCalledWith(page.id, "en");
|
|
73
|
+
expect(mockedPageChanges).toHaveBeenCalledWith({}, page.id, "en");
|
|
74
74
|
|
|
75
75
|
expect(result).toEqual({
|
|
76
76
|
assigns: {
|
|
77
77
|
resource: page,
|
|
78
78
|
revisions: [revision],
|
|
79
|
-
changes: [change],
|
|
79
|
+
changes: { list: [change] },
|
|
80
80
|
_translations: [
|
|
81
81
|
{
|
|
82
82
|
locale: "bg",
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import PageChanges from "../../../../cloud/PageChanges";
|
|
2
|
+
import Pages from "../../../../cloud/Pages";
|
|
3
|
+
import HistoryHandler from "../../../../handlers/pages/HistoryHandler";
|
|
4
|
+
import PagesHandler from "../../../../handlers/pages/PagesHandler";
|
|
5
|
+
import Factory from "../../../support/factory";
|
|
6
|
+
|
|
7
|
+
describe("history", () => {
|
|
8
|
+
function buildHistoryCtx() {
|
|
9
|
+
return {
|
|
10
|
+
client: {
|
|
11
|
+
pages: new Pages(() => ({}), "token"),
|
|
12
|
+
pageChanges: new PageChanges(() => ({}), "token"),
|
|
13
|
+
},
|
|
14
|
+
query: { foo: "bar" },
|
|
15
|
+
locale: "en",
|
|
16
|
+
params: {
|
|
17
|
+
parent_id: "123",
|
|
18
|
+
},
|
|
19
|
+
resourceConfig: {
|
|
20
|
+
pageType: "page",
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
test("successfully returns history data", async () => {
|
|
26
|
+
const ctx = buildHistoryCtx();
|
|
27
|
+
const page = Factory.build("page");
|
|
28
|
+
const changes = {
|
|
29
|
+
list: [
|
|
30
|
+
{ operatorMeta: { name: "Generic John Doe" } },
|
|
31
|
+
{ operatorMeta: { name: "Generic Jane Smith" } },
|
|
32
|
+
],
|
|
33
|
+
pagination: Factory.build("pagination"),
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
jest.spyOn(ctx.client.pages, "find").mockImplementation(() => page);
|
|
37
|
+
jest
|
|
38
|
+
.spyOn(ctx.client.pageChanges, "list")
|
|
39
|
+
.mockImplementation(() => changes);
|
|
40
|
+
jest
|
|
41
|
+
.spyOn(ctx.client.pageChanges, "all_editors")
|
|
42
|
+
.mockImplementation(() => ["Generic John Doe", "Generic Jane Smith"]);
|
|
43
|
+
|
|
44
|
+
const result = await HistoryHandler.index(ctx);
|
|
45
|
+
|
|
46
|
+
expect(result).toEqual({
|
|
47
|
+
assigns: {
|
|
48
|
+
resource: page,
|
|
49
|
+
changes: changes,
|
|
50
|
+
editors: ["Generic John Doe", "Generic Jane Smith"],
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("throws error when page is not found", async () => {
|
|
56
|
+
const ctx = buildHistoryCtx();
|
|
57
|
+
jest.spyOn(ctx.client.pages, "find").mockImplementation(() => null);
|
|
58
|
+
|
|
59
|
+
await expect(HistoryHandler.index(ctx)).rejects.toThrow(
|
|
60
|
+
"Missing page #123"
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("returns unique editors list", async () => {
|
|
65
|
+
const ctx = buildHistoryCtx();
|
|
66
|
+
const page = Factory.build("page");
|
|
67
|
+
const changes = {
|
|
68
|
+
list: [
|
|
69
|
+
{ operatorMeta: { name: "Generic John Doe" } },
|
|
70
|
+
{ operatorMeta: { name: "Generic John Doe" } },
|
|
71
|
+
],
|
|
72
|
+
pagination: Factory.build("pagination"),
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
jest.spyOn(ctx.client.pages, "find").mockImplementation(() => page);
|
|
76
|
+
jest
|
|
77
|
+
.spyOn(ctx.client.pageChanges, "list")
|
|
78
|
+
.mockImplementation(() => changes);
|
|
79
|
+
jest
|
|
80
|
+
.spyOn(ctx.client.pageChanges, "all_editors")
|
|
81
|
+
.mockImplementation(() => ["Generic John Doe"]);
|
|
82
|
+
|
|
83
|
+
const result = await HistoryHandler.index(ctx);
|
|
84
|
+
|
|
85
|
+
expect(result.assigns.editors).toEqual(["Generic John Doe"]);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import history from "../../helpers/historyUtils";
|
|
2
|
+
|
|
3
|
+
describe("changeTypes", () => {
|
|
4
|
+
it("replaces #RESOURCE_TYPE# with provided resource type", () => {
|
|
5
|
+
const result = history.changeTypes("article");
|
|
6
|
+
|
|
7
|
+
expect(result.create.label).toEqual("Article created");
|
|
8
|
+
expect(result.create.displayAction).toEqual("Article created");
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("uses default Page type if none provided", () => {
|
|
12
|
+
const result = history.changeTypes();
|
|
13
|
+
|
|
14
|
+
expect(result.create.label).toEqual("Page created");
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe("changeAction", () => {
|
|
19
|
+
it("formats action with revision ID", () => {
|
|
20
|
+
const change = { changeType: "revision_publish", revisionId: "123" };
|
|
21
|
+
const result = history.changeAction(change, "page");
|
|
22
|
+
|
|
23
|
+
expect(result).toEqual("Page updated by revision #123");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("handles revert source", () => {
|
|
27
|
+
const change = {
|
|
28
|
+
changeType: "revision_publish",
|
|
29
|
+
revisionId: "123",
|
|
30
|
+
source: "revert",
|
|
31
|
+
};
|
|
32
|
+
const result = history.changeAction(change, "page");
|
|
33
|
+
|
|
34
|
+
expect(result).toEqual("Page updated by revision #123 by revert");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("handles unknown change type", () => {
|
|
38
|
+
const change = { changeType: "unknown_type" };
|
|
39
|
+
const result = history.changeAction(change, "page");
|
|
40
|
+
|
|
41
|
+
expect(result).toBe("unknown_type");
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe("changeReason", () => {
|
|
46
|
+
function testChangeReasonFor(changeType, title, expectedResult) {
|
|
47
|
+
const change = { changeType, title };
|
|
48
|
+
const result = history.changeReason(change);
|
|
49
|
+
|
|
50
|
+
expect(result).toEqual(expectedResult);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
it("Returns the hange reason for each change type correctly", () => {
|
|
54
|
+
testChangeReasonFor("revision_publish", "Title", "Title");
|
|
55
|
+
testChangeReasonFor("revision_create", "Title", "");
|
|
56
|
+
testChangeReasonFor("create", "Title", "");
|
|
57
|
+
testChangeReasonFor("revision_lock", "Title", "Title");
|
|
58
|
+
testChangeReasonFor("revision_unlock", "Title", "");
|
|
59
|
+
testChangeReasonFor("revision_delete", "Title", "");
|
|
60
|
+
testChangeReasonFor("update", "Title", "Title");
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe("getMaxVersion", () => {
|
|
65
|
+
it("uses the pagination information for maxVersion calculation", () => {
|
|
66
|
+
const changes = {
|
|
67
|
+
list: [{ version: 1 }, { version: 5 }, { version: 3 }],
|
|
68
|
+
pagination: { entriesCount: 3 },
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
expect(history.getMaxVersion(changes)).toEqual(3);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe("isChangeRevertable", () => {
|
|
76
|
+
function testReversableNotForMaxVersion(changeType, expectedResult) {
|
|
77
|
+
const change = { changeType, version: 1 };
|
|
78
|
+
|
|
79
|
+
expect(history.isChangeRevertable(change, 2)).toEqual(expectedResult);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
it("returns true for revertable change types when not the for the max version", () => {
|
|
83
|
+
testReversableNotForMaxVersion("revision_publish", true);
|
|
84
|
+
testReversableNotForMaxVersion("revision_create", false);
|
|
85
|
+
testReversableNotForMaxVersion("create", true);
|
|
86
|
+
testReversableNotForMaxVersion("revision_lock", false);
|
|
87
|
+
testReversableNotForMaxVersion("revision_unlock", false);
|
|
88
|
+
testReversableNotForMaxVersion("revision_delete", true);
|
|
89
|
+
testReversableNotForMaxVersion("update", true);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
function testReversableForMaxVersion(changeType, expectedResult) {
|
|
93
|
+
const change = { changeType, version: 1 };
|
|
94
|
+
|
|
95
|
+
expect(history.isChangeRevertable(change, 1)).toEqual(expectedResult);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
it("returns true for revertable change types when for the max version", () => {
|
|
99
|
+
testReversableForMaxVersion("revision_publish", false);
|
|
100
|
+
testReversableForMaxVersion("revision_create", false);
|
|
101
|
+
testReversableForMaxVersion("create", false);
|
|
102
|
+
testReversableForMaxVersion("revision_lock", false);
|
|
103
|
+
testReversableForMaxVersion("revision_unlock", false);
|
|
104
|
+
testReversableForMaxVersion("revision_delete", true);
|
|
105
|
+
testReversableForMaxVersion("update", false);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import utils from "../../helpers/utils";
|
|
2
|
+
|
|
3
|
+
describe("includedInCollection", () => {
|
|
4
|
+
it("returns true when the given collection is a string equal to the given value", () => {
|
|
5
|
+
expect(utils.includedInCollection("key", "key")).toEqual(true);
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it("returns false when the given collection is a string not equal to the given value", () => {
|
|
9
|
+
expect(utils.includedInCollection("key", "key-2")).toEqual(false);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("returns true when the given collection is an array including the given value", () => {
|
|
13
|
+
expect(utils.includedInCollection("key", ["key"])).toEqual(true);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("returns false when the given collection is an array not including the given value", () => {
|
|
17
|
+
expect(utils.includedInCollection("key", ["key-2"])).toEqual(false);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("returns false when the given collection null", () => {
|
|
21
|
+
expect(utils.includedInCollection("key", null)).toEqual(false);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("returns false when the given collection undefined", () => {
|
|
25
|
+
expect(utils.includedInCollection("key", undefined)).toEqual(false);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
<div class="actions-toolbar justify-end">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
<input type="hidden" name="version" value=<%= change.version %>>
|
|
5
|
-
<button type="submit" class="btn-text has-icon">
|
|
6
|
-
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
|
|
7
|
-
<path stroke-linecap="round" stroke-linejoin="round" d="M9 15 3 9m0 0 6-6M3 9h12a6 6 0 0 1 0 12h-3" />
|
|
8
|
-
</svg>
|
|
2
|
+
<form method="POST" action="<%= `/${_context.locale}/${_context.resourceConfig.pageTypePlural}/${resource.id}/${_context.resourceConfig.pageType}_changes/reverts` %>" class="inline-block">
|
|
3
|
+
<input type="hidden" name="version" value="<%= change.version %>">
|
|
9
4
|
|
|
5
|
+
<% if (history.isChangeRevertable(change, maxVersion)) { %>
|
|
6
|
+
<button type="submit" class="btn-text">
|
|
10
7
|
Revert
|
|
11
8
|
</button>
|
|
9
|
+
<% } else { %>
|
|
10
|
+
<button type="submit" disabled class="btn-text opacity-50 cursor-not-allowed">
|
|
11
|
+
Revert
|
|
12
|
+
</button>
|
|
13
|
+
<% } %>
|
|
12
14
|
</form>
|
|
13
|
-
<% } %>
|
|
14
15
|
|
|
15
16
|
<a href="/remote/login?redirect_to=/<%= _context.locale %>/admin/<%= _context.resourceConfig.articleTypePlural %>/<%= resource.id %>/changes/<%= change.version %>" class="btn-text has-icon">
|
|
16
17
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
|