@raketa-cloud/admin 0.0.96 → 0.0.98

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.
Files changed (69) hide show
  1. package/package.json +1 -1
  2. package/src/Adapter.js +3 -1
  3. package/src/cloud/ArticleChanges.js +24 -3
  4. package/src/cloud/EventChanges.js +24 -3
  5. package/src/cloud/PageChanges.js +24 -3
  6. package/src/cloud/Pages.js +1 -1
  7. package/src/cloud/documents/articlesDocuments.js +18 -5
  8. package/src/cloud/documents/common.js +2 -0
  9. package/src/cloud/documents/eventsDocuments.js +17 -4
  10. package/src/cloud/documents/pagesDocuments.js +17 -4
  11. package/src/handlers/articles/ArticlesHandler.js +2 -2
  12. package/src/handlers/articles/HistoryHandler.js +31 -0
  13. package/src/handlers/events/EventsHandler.js +2 -2
  14. package/src/handlers/events/HistoryHandler.js +31 -0
  15. package/src/handlers/pages/HistoryHandler.js +31 -0
  16. package/src/handlers/pages/PagesHandler.js +2 -2
  17. package/src/helpers/historyUtils.js +133 -0
  18. package/src/routeArticlesModule.js +19 -13
  19. package/src/routeEventsModule.js +18 -12
  20. package/src/routePagesModule.js +7 -1
  21. package/src/tests/handlers/articles/ArticlesHandler.test/show.test.js +5 -5
  22. package/src/tests/handlers/articles/ArticlesHistoryHandler.test/index.test.js +87 -0
  23. package/src/tests/handlers/events/EventsHandler.test/show.test.js +5 -5
  24. package/src/tests/handlers/events/EventsHistoryHandler.test/index.test.js +87 -0
  25. package/src/tests/handlers/pages/PagesHandler.test/show.test.js +5 -5
  26. package/src/tests/handlers/pages/PagesHistoryHandler.test/index.test.js +87 -0
  27. package/src/tests/helpers/historyUtils.test.js +107 -0
  28. package/src/views/article_revisions/codes/_form.ejs +13 -0
  29. package/src/views/article_revisions/codes/edit_form.ejs +1 -13
  30. package/src/views/article_revisions/locks/_form.ejs +11 -0
  31. package/src/views/article_revisions/locks/create_form.ejs +2 -12
  32. package/src/views/article_revisions/meta/_form.ejs +15 -0
  33. package/src/views/article_revisions/meta/edit_form.ejs +2 -16
  34. package/src/views/article_revisions/tags/_form.ejs +12 -0
  35. package/src/views/article_revisions/tags/edit_form.ejs +2 -13
  36. package/src/views/article_revisions/visuals/_form.ejs +12 -0
  37. package/src/views/article_revisions/visuals/edit_form.ejs +2 -13
  38. package/src/views/articles/_shared/_history_toolbar.ejs +9 -8
  39. package/src/views/articles/_shared/history_table.ejs +68 -0
  40. package/src/views/articles/history/index.ejs +87 -0
  41. package/src/views/articles/show.ejs +12 -52
  42. package/src/views/event_revisions/codes/_form.ejs +13 -0
  43. package/src/views/event_revisions/codes/edit_form.ejs +1 -13
  44. package/src/views/event_revisions/locks/_form.ejs +11 -0
  45. package/src/views/event_revisions/locks/create_form.ejs +2 -12
  46. package/src/views/event_revisions/meta/_form.ejs +15 -0
  47. package/src/views/event_revisions/meta/edit_form.ejs +2 -16
  48. package/src/views/event_revisions/tags/_form.ejs +12 -0
  49. package/src/views/event_revisions/tags/edit_form.ejs +2 -13
  50. package/src/views/event_revisions/visuals/_form.ejs +12 -0
  51. package/src/views/event_revisions/visuals/edit_form.ejs +2 -13
  52. package/src/views/events/_shared/_history_toolbar.ejs +9 -8
  53. package/src/views/events/_shared/history_table.ejs +68 -0
  54. package/src/views/events/history/index.ejs +87 -0
  55. package/src/views/events/show.ejs +12 -52
  56. package/src/views/page_revisions/codes/_form.ejs +13 -0
  57. package/src/views/page_revisions/codes/edit_form.ejs +1 -13
  58. package/src/views/page_revisions/locks/_form.ejs +11 -0
  59. package/src/views/page_revisions/locks/create_form.ejs +2 -12
  60. package/src/views/page_revisions/meta/_form.ejs +15 -0
  61. package/src/views/page_revisions/meta/edit_form.ejs +1 -15
  62. package/src/views/page_revisions/tags/_form.ejs +12 -0
  63. package/src/views/page_revisions/tags/edit_form.ejs +3 -14
  64. package/src/views/page_revisions/visuals/_form.ejs +12 -0
  65. package/src/views/page_revisions/visuals/edit_form.ejs +1 -12
  66. package/src/views/pages/_shared/_history_toolbar.ejs +8 -7
  67. package/src/views/pages/_shared/history_table.ejs +68 -0
  68. package/src/views/pages/history/index.ejs +87 -0
  69. package/src/views/pages/show.ejs +12 -52
@@ -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, "all")
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, "all")
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, "all")
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,13 @@
1
+ <% form_for({ resource }, errors, (f) => { %>
2
+ <form action="<%= `/${_context.locale}/${_context.resourceConfig.articleType}_revisions/${resource.id}/codes` %>" method="POST" class="form">
3
+ <%- render_partial('../../_shared/_scripts_input.ejs', { resource, f }) %>
4
+ <%- render_partial('../../_shared/_structured_json_input.ejs', { resource, f }) %>
5
+
6
+ <div class="form-actions">
7
+ <div class="btn-toolbar">
8
+ <%- f.submit('Save changes', { class: 'btn-primary' }) %>
9
+ <a href="<%= `/${_context.locale}/${_context.resourceConfig.articleTypePlural}/${resource.originalId}` %>" class="btn-secondary">Back</a>
10
+ </div>
11
+ </div>
12
+ </form>
13
+ <% }) %>
@@ -10,19 +10,7 @@
10
10
 
11
11
  <div class="grid gap-4 md:grid-cols-3">
12
12
  <div>
13
- <% form_for({ resource }, errors, (f) => { %>
14
- <form action="<%= `/${_context.locale}/${_context.resourceConfig.articleType}_revisions/${resource.id}/codes` %>" method="POST" class="form">
15
- <%- render_partial('../../_shared/_scripts_input.ejs', { resource, f }) %>
16
- <%- render_partial('../../_shared/_structured_json_input.ejs', { resource, f }) %>
17
-
18
- <div class="form-actions">
19
- <div class="btn-toolbar">
20
- <%- f.submit('Save changes', { class: 'btn-primary' }) %>
21
- <a href="<%= `/${_context.locale}/${_context.resourceConfig.articleTypePlural}/${resource.originalId}` %>" class="btn-secondary">Back</a>
22
- </div>
23
- </div>
24
- </form>
25
- <% }) %>
13
+ <%- render_partial('_form.ejs', { render_partial: render_partial }) %>
26
14
  </div>
27
15
  </div>
28
16
  </div>
@@ -0,0 +1,11 @@
1
+ <% form_for({ resource }, errors, (f) => { %>
2
+ <form action="<%= `/${_context.locale}/${_context.resourceConfig.articleType}_revisions/${resource.id}/locks` %>" method="POST" class="form">
3
+ <%- f.field('resource.message', { as: 'textarea', label: 'Lock Message', required: true }) %>
4
+ <div class="form-actions">
5
+ <div class="btn-toolbar">
6
+ <%- f.submit('Lock revision', { class: 'btn-primary' }) %>
7
+ <a href="<%= `/${_context.locale}/${_context.resourceConfig.articleTypePlural}/${resource.originalId}` %>" class="btn-secondary">Cancel</a>
8
+ </div>
9
+ </div>
10
+ </form>
11
+ <% }) %>
@@ -5,17 +5,7 @@
5
5
 
6
6
  <div class="grid gap-4 md:grid-cols-3">
7
7
  <div>
8
- <% form_for({ resource }, errors, (f) => { %>
9
- <form action="<%= `/${_context.locale}/${_context.resourceConfig.articleType}_revisions/${resource.id}/locks` %>" method="POST" class="form">
10
- <%- f.field('resource.message', { as: 'textarea', label: 'Lock Message', required: true }) %>
11
- <div class="form-actions">
12
- <div class="btn-toolbar">
13
- <%- f.submit('Lock revision', { class: 'btn-primary' }) %>
14
- <a href="<%= `/${_context.locale}/${_context.resourceConfig.articleTypePlural}/${resource.originalId}` %>" class="btn-secondary">Cancel</a>
15
- </div>
16
- </div>
17
- </form>
18
- <% }) %>
8
+ <%- render_partial('_form.ejs') %>
19
9
  </div>
20
10
 
21
11
  <div>
@@ -34,4 +24,4 @@
34
24
  </div>
35
25
  </div>
36
26
  </div>
37
- </div>
27
+ </div>
@@ -0,0 +1,15 @@
1
+ <% form_for({ resource }, errors, (f) => { %>
2
+ <form action="<%= `/${_context.locale}/${_context.resourceConfig.articleType}_revisions/${resource.id}/meta` %>" method="POST" class="form">
3
+ <%- f.field('resource.settings.meta.title', { required: true, label: "Meta title", hint: "Used for both meta and OpenGraph" }) %>
4
+ <%- f.field('resource.settings.meta.description', { as: "textarea", required: true, label: "Meta description", hint: "Used for both meta and OpenGraph" }) %>
5
+
6
+ <raketa-image-picker name="resource[settings][meta][image]" value="<%= JSON.stringify(resource.settings?.meta?.image || {}) %>" label="OpenGraph image"></raketa-image-picker>
7
+
8
+ <div class="form-actions">
9
+ <div class="btn-toolbar">
10
+ <%- f.submit('Save changes', { class: 'btn-primary' }) %>
11
+ <a href="<%= `/${_context.locale}/${_context.resourceConfig.articleTypePlural}/${resource.originalId}` %>" class="btn-secondary">Back</a>
12
+ </div>
13
+ </div>
14
+ </form>
15
+ <% }) %>
@@ -10,21 +10,7 @@
10
10
 
11
11
  <div class="grid gap-4 md:grid-cols-3">
12
12
  <div>
13
- <% form_for({ resource }, errors, (f) => { %>
14
- <form action="<%= `/${_context.locale}/${_context.resourceConfig.articleType}_revisions/${resource.id}/meta` %>" method="POST" class="form">
15
- <%- f.field('resource.settings.meta.title', { required: true, label: "Meta title", hint: "Used for both meta and OpenGraph" }) %>
16
- <%- f.field('resource.settings.meta.description', { as: "textarea", required: true, label: "Meta description", hint: "Used for both meta and OpenGraph" }) %>
17
-
18
- <raketa-image-picker name="resource[settings][meta][image]" value="<%= JSON.stringify(resource.settings?.meta?.image || {}) %>" label="OpenGraph image"></raketa-image-picker>
19
-
20
- <div class="form-actions">
21
- <div class="btn-toolbar">
22
- <%- f.submit('Save changes', { class: 'btn-primary' }) %>
23
- <a href="<%= `/${_context.locale}/${_context.resourceConfig.articleTypePlural}/${resource.originalId}` %>" class="btn-secondary">Back</a>
24
- </div>
25
- </div>
26
- </form>
27
- <% }) %>
13
+ <%- render_partial('_form.ejs') %>
28
14
  </div>
29
15
  </div>
30
- </div>
16
+ </div>
@@ -0,0 +1,12 @@
1
+ <% form_for({ resource }, errors, (f) => { %>
2
+ <form action="<%= `/${_context.locale}/${_context.resourceConfig.articleType}_revisions/${resource.id}/tags` %>" method="POST" class="form">
3
+ <%- f.field('resource.tags', { as: 'checkbox_group', options: tags.map(tag => [tag.id, tag.name]) }) %>
4
+
5
+ <div class="form-actions">
6
+ <div class="btn-toolbar">
7
+ <%- f.submit('Save changes', { class: 'btn-primary' }) %>
8
+ <a href="<%= `/${_context.locale}/${_context.resourceConfig.articleTypePlural}/${resource.originalId}` %>" class="btn-secondary">Back</a>
9
+ </div>
10
+ </div>
11
+ </form>
12
+ <% }) %>
@@ -10,18 +10,7 @@
10
10
 
11
11
  <div class="grid gap-4 md:grid-cols-3">
12
12
  <div>
13
- <% form_for({ resource }, errors, (f) => { %>
14
- <form action="<%= `/${_context.locale}/${_context.resourceConfig.articleType}_revisions/${resource.id}/tags` %>" method="POST" class="form">
15
- <%- f.field('resource.tags', { as: 'checkbox_group', options: tags.map(tag => [tag.id, tag.name]) }) %>
16
-
17
- <div class="form-actions">
18
- <div class="btn-toolbar">
19
- <%- f.submit('Save changes', { class: 'btn-primary' }) %>
20
- <a href="<%= `/${_context.locale}/${_context.resourceConfig.articleTypePlural}/${resource.originalId}` %>" class="btn-secondary">Back</a>
21
- </div>
22
- </div>
23
- </form>
24
- <% }) %>
13
+ <%- render_partial('_form.ejs', { tags: tags }) %>
25
14
  </div>
26
15
  </div>
27
- </div>
16
+ </div>