alchemy_cms 7.0.0.pre.b → 7.0.0.pre.c

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/lint.yml +21 -1
  3. data/.github/workflows/{ci.yml → test.yml} +1 -1
  4. data/.gitignore +0 -5
  5. data/CHANGELOG.md +4 -0
  6. data/Gemfile +0 -1
  7. data/README.md +3 -3
  8. data/Rakefile +0 -19
  9. data/alchemy_cms.gemspec +2 -1
  10. data/app/assets/config/alchemy_manifest.js +1 -0
  11. data/app/assets/javascripts/alchemy/admin.js +0 -1
  12. data/app/assets/javascripts/alchemy/alchemy.dirty.js.coffee +1 -1
  13. data/app/assets/javascripts/alchemy/alchemy.initializer.js.coffee +5 -12
  14. data/app/assets/stylesheets/alchemy/base.scss +2 -2
  15. data/app/controllers/alchemy/base_controller.rb +0 -7
  16. data/{package/src → app/javascript/alchemy_admin}/node_tree.js +2 -2
  17. data/{package/src → app/javascript/alchemy_admin}/page_publication_fields.js +1 -1
  18. data/{package/src → app/javascript/alchemy_admin}/page_sorter.js +1 -1
  19. data/{package/src → app/javascript/alchemy_admin}/picture_editors.js +2 -2
  20. data/{package/src → app/javascript/alchemy_admin}/sitemap.js +4 -4
  21. data/app/javascript/alchemy_admin.js +34 -0
  22. data/app/views/alchemy/_menubar.html.erb +1 -1
  23. data/app/views/alchemy/admin/attachments/_replace_button.html.erb +1 -1
  24. data/app/views/alchemy/admin/attachments/destroy.js.erb +1 -1
  25. data/app/views/alchemy/admin/nodes/index.html.erb +4 -2
  26. data/app/views/alchemy/admin/pages/_page_layout_filter.html.erb +1 -1
  27. data/app/views/alchemy/admin/pages/edit.html.erb +3 -4
  28. data/app/views/alchemy/admin/pages/index.html.erb +1 -1
  29. data/app/views/alchemy/admin/pages/update.js.erb +2 -2
  30. data/app/views/alchemy/admin/resources/_filter_bar.html.erb +1 -1
  31. data/app/views/alchemy/admin/styleguide/index.html.erb +1 -1
  32. data/app/views/alchemy/admin/uploader/_button.html.erb +1 -1
  33. data/app/views/alchemy/base/permission_denied.js.erb +1 -1
  34. data/app/views/alchemy/base/redirect.js.erb +1 -1
  35. data/app/views/layouts/alchemy/admin.html.erb +4 -8
  36. data/bin/importmap +4 -0
  37. data/bin/setup +0 -9
  38. data/bin/start +1 -1
  39. data/config/brakeman.ignore +0 -46
  40. data/config/importmap.rb +8 -0
  41. data/lib/alchemy/engine.rb +14 -0
  42. data/lib/alchemy/upgrader/seven_point_zero.rb +13 -23
  43. data/lib/alchemy/upgrader.rb +0 -11
  44. data/lib/alchemy/version.rb +1 -1
  45. data/lib/alchemy.rb +5 -0
  46. data/lib/alchemy_cms.rb +2 -1
  47. data/lib/generators/alchemy/install/files/application.html.erb +2 -2
  48. data/lib/generators/alchemy/install/install_generator.rb +0 -24
  49. data/lib/tasks/alchemy/upgrade.rake +6 -12
  50. data/package.json +6 -26
  51. metadata +44 -27
  52. data/package/admin.js +0 -34
  53. data/package/dist/admin.js +0 -16
  54. data/package/dist/admin.js.map +0 -7
  55. data/package/src/__tests__/i18n.spec.js +0 -93
  56. data/package/src/utils/__tests__/ajax.spec.js +0 -168
  57. data/package/src/utils/__tests__/events.spec.js +0 -38
  58. /data/{package/src → app/javascript/alchemy_admin}/datepicker.js +0 -0
  59. /data/{package/src → app/javascript/alchemy_admin}/file_editors.js +0 -0
  60. /data/{package/src → app/javascript/alchemy_admin}/i18n.js +0 -0
  61. /data/{package/src → app/javascript/alchemy_admin}/image_cropper.js +0 -0
  62. /data/{package/src → app/javascript/alchemy_admin}/image_loader.js +0 -0
  63. /data/{package/src → app/javascript/alchemy_admin}/ingredient_anchor_link.js +0 -0
  64. /data/{package/src → app/javascript/alchemy_admin}/tinymce.js +0 -0
  65. /data/{package/src → app/javascript/alchemy_admin}/translations.js +0 -0
  66. /data/{package/src → app/javascript/alchemy_admin}/utils/ajax.js +0 -0
  67. /data/{package/src → app/javascript/alchemy_admin}/utils/events.js +0 -0
@@ -1,93 +0,0 @@
1
- import translate from "../i18n"
2
-
3
- describe("translate", () => {
4
- describe("if Alchemy.locale is not set", () => {
5
- it("Throws an error", () => {
6
- expect(() => {
7
- translate("help")
8
- }).toThrow("Alchemy.locale is not set")
9
- })
10
- })
11
-
12
- describe("if Alchemy.locale is set to a known locale", () => {
13
- beforeEach(() => {
14
- Alchemy.locale = "en"
15
- })
16
-
17
- describe("if translation is present", () => {
18
- beforeEach(() => {
19
- Alchemy.translations = { en: { help: "Help" } }
20
- })
21
-
22
- it("Returns translated string", () => {
23
- expect(translate("help")).toEqual("Help")
24
- })
25
-
26
- describe("if key includes a period", () => {
27
- describe("that is translated", () => {
28
- beforeEach(() => {
29
- Alchemy.translations = { en: { formats: { date: "Y-m-d" } } }
30
- })
31
-
32
- it("splits into group", () => {
33
- expect(translate("formats.date")).toEqual("Y-m-d")
34
- })
35
- })
36
-
37
- describe("that is not translated", () => {
38
- it("returns key", () => {
39
- expect(translate("formats.lala")).toEqual("formats.lala")
40
- })
41
- })
42
-
43
- describe("that has unknown group", () => {
44
- it("returns key", () => {
45
- expect(translate("foo.bar")).toEqual("foo.bar")
46
- })
47
- })
48
- })
49
-
50
- describe("if replacement is given", () => {
51
- beforeEach(() => {
52
- Alchemy.translations = { en: { allowed_chars: "of %{number} chars" } }
53
- })
54
-
55
- it("replaces it", () => {
56
- expect(translate("allowed_chars", 5)).toEqual("of 5 chars")
57
- })
58
- })
59
- })
60
-
61
- describe("if translation is not present", () => {
62
- it("Returns passed string", () => {
63
- expect(translate("foo")).toEqual("foo")
64
- })
65
- })
66
- })
67
-
68
- describe("if Alchemy.locale is set to a unknown locale", () => {
69
- beforeEach(() => {
70
- Alchemy.locale = "kl"
71
- })
72
-
73
- it("Returns passed string and logs a warning", () => {
74
- const spy = jest.spyOn(console, "warn").mockImplementation(() => {})
75
- expect(translate("help")).toEqual("help")
76
- expect(spy.mock.calls).toEqual([
77
- ["Translations for locale kl not found!"]
78
- ])
79
- spy.mockRestore()
80
- })
81
- })
82
-
83
- describe("if Alchemy.translations is not set", () => {
84
- it("Returns passed string and logs a warning", () => {
85
- const spy = jest.spyOn(console, "warn").mockImplementation(() => {})
86
- expect(translate("help")).toEqual("help")
87
- expect(spy.mock.calls).toEqual([
88
- ["Translations for locale kl not found!"]
89
- ])
90
- spy.mockRestore()
91
- })
92
- })
93
- })
@@ -1,168 +0,0 @@
1
- import xhrMock from "xhr-mock"
2
- import { get, patch, post } from "../ajax"
3
-
4
- const token = "s3cr3t"
5
-
6
- beforeEach(() => {
7
- document.head.innerHTML = `<meta name="csrf-token" content="${token}">`
8
- xhrMock.setup()
9
- })
10
-
11
- describe("get", () => {
12
- it("sends X-CSRF-TOKEN header", async () => {
13
- xhrMock.get("http://localhost/users", (req, res) => {
14
- expect(req.header("X-CSRF-TOKEN")).toEqual(token)
15
- return res.status(200).body('{"message":"Ok"}')
16
- })
17
- await get("/users")
18
- })
19
-
20
- it("sends Content-Type header", async () => {
21
- xhrMock.get("http://localhost/users", (req, res) => {
22
- expect(req.header("Content-Type")).toEqual(
23
- "application/json; charset=utf-8"
24
- )
25
- return res.status(200).body('{"message":"Ok"}')
26
- })
27
- await get("/users")
28
- })
29
-
30
- it("sends Accept header", async () => {
31
- xhrMock.get("http://localhost/users", (req, res) => {
32
- expect(req.header("Accept")).toEqual("application/json")
33
- return res.status(200).body('{"message":"Ok"}')
34
- })
35
- await get("/users")
36
- })
37
-
38
- it("returns JSON", async () => {
39
- xhrMock.get("http://localhost/users", (_req, res) => {
40
- return res.status(200).body('{"email":"mail@example.com"}')
41
- })
42
- await get("/users").then((res) => {
43
- expect(res.data).toEqual({ email: "mail@example.com" })
44
- })
45
- })
46
-
47
- it("JSON parse errors get rejected", async () => {
48
- xhrMock.get("http://localhost/users", (_req, res) => {
49
- return res.status(200).body('email => "mail@example.com"')
50
- })
51
- expect.assertions(1)
52
- await get("/users").catch((e) => {
53
- expect(e.message).toMatch("Unexpected token")
54
- })
55
- })
56
-
57
- it("network errors get rejected", async () => {
58
- xhrMock.get("http://localhost/users", () => {
59
- return Promise.reject(new Error())
60
- })
61
- expect.assertions(1)
62
- await get("/users").catch((e) => {
63
- expect(e.message).toEqual("An error occurred during the transaction")
64
- })
65
- })
66
-
67
- it("server errors get rejected", async () => {
68
- xhrMock.get("http://localhost/users", (_req, res) => {
69
- return res.status(401).body('{"error":"Unauthorized"}')
70
- })
71
- expect.assertions(1)
72
- await get("/users").catch((e) => {
73
- expect(e.error).toEqual("Unauthorized")
74
- })
75
- })
76
-
77
- it("server errors parsing errors get rejected", async () => {
78
- xhrMock.get("http://localhost/users", (_req, res) => {
79
- return res.status(401).body("Unauthorized")
80
- })
81
- expect.assertions(1)
82
- await get("/users").catch((e) => {
83
- expect(e.message).toMatch("Unexpected token")
84
- })
85
- })
86
-
87
- it("params get attached as query string", async () => {
88
- xhrMock.get("http://localhost/users?name=foo", (_req, res) => {
89
- return res.status(200).body(`{"name":"foo"}`)
90
- })
91
- const { data } = await get("/users", { name: "foo" })
92
- expect(data.name).toEqual("foo")
93
- })
94
- })
95
-
96
- describe("patch", () => {
97
- it("sends X-CSRF-TOKEN header", async () => {
98
- xhrMock.patch("http://localhost/users", (req, res) => {
99
- expect(req.header("X-CSRF-TOKEN")).toEqual(token)
100
- return res.status(200).body('{"message":"Ok"}')
101
- })
102
- await patch("/users")
103
- })
104
-
105
- it("sends Content-Type header", async () => {
106
- xhrMock.patch("http://localhost/users", (req, res) => {
107
- expect(req.header("Content-Type")).toEqual(
108
- "application/json; charset=utf-8"
109
- )
110
- return res.status(200).body('{"message":"Ok"}')
111
- })
112
- await patch("/users")
113
- })
114
-
115
- it("sends Accept header", async () => {
116
- xhrMock.patch("http://localhost/users", (req, res) => {
117
- expect(req.header("Accept")).toEqual("application/json")
118
- return res.status(200).body('{"message":"Ok"}')
119
- })
120
- await patch("/users")
121
- })
122
-
123
- it("sends JSON data", async () => {
124
- xhrMock.patch("http://localhost/users", (req, res) => {
125
- expect(req.body()).toEqual('{"email":"mail@example.com"}')
126
- return res.status(200).body('{"message":"Ok"}')
127
- })
128
- await patch("/users", { email: "mail@example.com" })
129
- })
130
- })
131
-
132
- describe("post", () => {
133
- it("sends X-CSRF-TOKEN header", async () => {
134
- xhrMock.post("http://localhost/users", (req, res) => {
135
- expect(req.header("X-CSRF-TOKEN")).toEqual(token)
136
- return res.status(200).body('{"message":"Ok"}')
137
- })
138
- await post("/users")
139
- })
140
-
141
- it("sends Content-Type header", async () => {
142
- xhrMock.post("http://localhost/users", (req, res) => {
143
- expect(req.header("Content-Type")).toEqual(
144
- "application/json; charset=utf-8"
145
- )
146
- return res.status(200).body('{"message":"Ok"}')
147
- })
148
- await post("/users")
149
- })
150
-
151
- it("sends Accept header", async () => {
152
- xhrMock.post("http://localhost/users", (req, res) => {
153
- expect(req.header("Accept")).toEqual("application/json")
154
- return res.status(200).body('{"message":"Ok"}')
155
- })
156
- await post("/users")
157
- })
158
-
159
- it("sends JSON data", async () => {
160
- xhrMock.post("http://localhost/users", (req, res) => {
161
- expect(req.body()).toEqual('{"email":"mail@example.com"}')
162
- return res.status(200).body('{"message":"Ok"}')
163
- })
164
- await post("/users", { email: "mail@example.com" })
165
- })
166
- })
167
-
168
- afterEach(() => xhrMock.teardown())
@@ -1,38 +0,0 @@
1
- import { on } from "../events"
2
-
3
- describe("on", () => {
4
- const callback = jest.fn()
5
-
6
- beforeEach(() => {
7
- document.body.innerHTML = `
8
- <ul class="list">
9
- <li class="first item"><span>One</span></li>
10
- <li class="second item">Two</li>
11
- </ul>
12
- `
13
- })
14
-
15
- it("adds event listener to base node", () => {
16
- const baseNode = document.querySelector(".list")
17
- const spy = jest.spyOn(baseNode, "addEventListener")
18
- on("click", ".list", ".item", callback)
19
- expect(spy).toHaveBeenCalledWith("click", expect.any(Function))
20
- spy.mockReset()
21
- })
22
-
23
- it("event triggered on matching child node calls callback", () => {
24
- const childNode = document.querySelector(".first.item")
25
- on("click", ".list", ".item", callback)
26
- childNode.click()
27
- expect(callback).toHaveBeenCalledWith(expect.any(MouseEvent))
28
- })
29
-
30
- it("event triggered on child of registered target still calls callback", () => {
31
- const child = document.querySelector(".first.item span")
32
- on("click", ".list", ".item", callback)
33
- child.click()
34
- expect(callback).toHaveBeenCalledWith(expect.any(MouseEvent))
35
- })
36
-
37
- afterEach(() => callback.mockReset())
38
- })