gdk-toogle 1.0.1 → 1.2.0
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.
- checksums.yaml +4 -4
- data/README.md +5 -3
- data/app/assets/javascript/toogle/application.js +59 -19
- data/app/assets/stylesheets/toogle/application.css +5 -5
- data/app/assets/stylesheets/toogle/components/toggle.css +4 -1
- data/app/assets/stylesheets/toogle/elements.css +4 -0
- data/app/assets/stylesheets/toogle/variables.css +23 -0
- data/app/controllers/toogle/assets_controller.rb +29 -0
- data/app/controllers/toogle/branches_controller.rb +7 -0
- data/app/services/toogle/git_repo.rb +7 -0
- data/app/views/layouts/toogle/application.html.haml +8 -5
- data/config/routes.rb +4 -0
- data/lib/toogle/version.rb +1 -1
- metadata +5 -3
- data/app/assets/config/toogle_manifest.js +0 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 31e11a727853a15792bcdb3963066222752c19b30234d0dc63db07a360a44472
|
|
4
|
+
data.tar.gz: ddef44896dfda4944158d2e4204900b3df49d1c0c582973dc0efadc104122f57
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: abcefb8b6457c45c10d5adb906deb4f25bc01f5202e0ac1cf17acc61da1d6d6c0ef4b32abd4aa8fbcb7e1fc00a6488d5ba0b429028d06e9649f24cbf4ce36052
|
|
7
|
+
data.tar.gz: d13585fdd22505d237f1166cc7d07b9c0233e66d1e6047ab7d945d68aa43dc08b09a67e8613b33298667e90c7049e5435d40e11d754756cd4ef92c4625e08cf5
|
data/README.md
CHANGED
|
@@ -10,7 +10,7 @@ GitLab's `Feature` classes, so mounting it in any other Rails app won't work
|
|
|
10
10
|
|
|
11
11
|
### Usage within the GitLab Development Kit
|
|
12
12
|
|
|
13
|
-
The UI is available at http://gdk.test:
|
|
13
|
+
The UI is available at http://gdk.test:4000/rails/features.
|
|
14
14
|
|
|
15
15
|
## Contributing
|
|
16
16
|
|
|
@@ -29,11 +29,12 @@ The dummy app used for testing includes fake in-memory versions of GitLab's
|
|
|
29
29
|
develop the engine without a GDK:
|
|
30
30
|
|
|
31
31
|
```sh
|
|
32
|
+
bundle install
|
|
32
33
|
cd spec/dummy
|
|
33
34
|
bin/rails server
|
|
34
35
|
```
|
|
35
36
|
|
|
36
|
-
Then open http://localhost:
|
|
37
|
+
Then open http://localhost:4000/toogle. Toggled state lives in memory and
|
|
37
38
|
resets on restart.
|
|
38
39
|
|
|
39
40
|
To test your changes inside a real GDK, point GitLab's `Gemfile` at your
|
|
@@ -80,7 +81,8 @@ Keep Ruby and gem versions at or below what GitLab itself runs (see
|
|
|
80
81
|
One design goal of this little Rails engine was to keep it free of any dependencies, that GitLab uses today.
|
|
81
82
|
Because, tomorrow we might decide to ditch one or the other tech we use today, and Toogle shouldn't break just because GitLab removes `sassc`, as an example (that actually happened during development).
|
|
82
83
|
|
|
83
|
-
That's why Toogle only depends on the bare basics: `rails
|
|
84
|
+
That's why Toogle only depends on the bare basics: `rails` and `haml`.
|
|
85
|
+
It doesn't even use the host's asset pipeline: the engine serves its own CSS and JS files.
|
|
84
86
|
|
|
85
87
|
### Javascript
|
|
86
88
|
|
|
@@ -33,25 +33,20 @@ document.addEventListener("alpine:init", () => {
|
|
|
33
33
|
definitionsUrl,
|
|
34
34
|
|
|
35
35
|
init() {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
const definitionsLoaded = fetch(this.definitionsUrl, {
|
|
39
|
-
method: "GET",
|
|
40
|
-
headers: {
|
|
41
|
-
Accept: "application/json",
|
|
42
|
-
},
|
|
43
|
-
})
|
|
44
|
-
.then((response) => response.json())
|
|
45
|
-
.then((data) => {
|
|
46
|
-
this.definitions = data;
|
|
47
|
-
})
|
|
48
|
-
.catch(showFetchError);
|
|
36
|
+
const loading = this.reload();
|
|
49
37
|
|
|
50
38
|
if (shareName) {
|
|
51
|
-
|
|
39
|
+
loading.then(() =>
|
|
52
40
|
this.openDetails(shareName)
|
|
53
41
|
);
|
|
54
42
|
}
|
|
43
|
+
|
|
44
|
+
this.onReload = () => this.reload();
|
|
45
|
+
window.addEventListener("reload", this.onReload);
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
destroy() {
|
|
49
|
+
window.removeEventListener("reload", this.onReload);
|
|
55
50
|
},
|
|
56
51
|
|
|
57
52
|
openDetails(name) {
|
|
@@ -119,6 +114,27 @@ document.addEventListener("alpine:init", () => {
|
|
|
119
114
|
.catch(showFetchError);
|
|
120
115
|
},
|
|
121
116
|
|
|
117
|
+
fetchDefinitions() {
|
|
118
|
+
return fetch(this.definitionsUrl, {
|
|
119
|
+
method: "GET",
|
|
120
|
+
headers: {
|
|
121
|
+
Accept: "application/json",
|
|
122
|
+
},
|
|
123
|
+
})
|
|
124
|
+
.then((response) => response.json())
|
|
125
|
+
.then((data) => {
|
|
126
|
+
this.definitions = data;
|
|
127
|
+
})
|
|
128
|
+
.catch(showFetchError);
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
reload() {
|
|
132
|
+
const featuresLoaded = this.fetchFeatures();
|
|
133
|
+
const definitionsLoaded = this.fetchDefinitions();
|
|
134
|
+
|
|
135
|
+
return Promise.all([featuresLoaded, definitionsLoaded])
|
|
136
|
+
},
|
|
137
|
+
|
|
122
138
|
// Animates the layout change, e.g. a row moving between the sections.
|
|
123
139
|
// Only the moving row gets a view-transition-name (see the view), so the
|
|
124
140
|
// browser snapshots one row, not all ~700 — keeping toggles fast no
|
|
@@ -238,15 +254,39 @@ document.addEventListener("alpine:init", () => {
|
|
|
238
254
|
["@click"]() {
|
|
239
255
|
this.isDark = !this.isDark;
|
|
240
256
|
document.cookie = `toogle-dark=${this.isDark}; SameSite=Strict`;
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
} else {
|
|
244
|
-
document.documentElement.classList.add("light-mode");
|
|
245
|
-
}
|
|
257
|
+
document.documentElement.classList.toggle("dark-mode", this.isDark);
|
|
258
|
+
document.documentElement.classList.toggle("light-mode", !this.isDark);
|
|
246
259
|
},
|
|
247
260
|
["x-bind:title"]() {
|
|
248
261
|
return `Switch to ${this.isDark ? "Light Mode" : "Dark Mode"}`;
|
|
249
262
|
},
|
|
250
263
|
},
|
|
251
264
|
}));
|
|
265
|
+
|
|
266
|
+
Alpine.data("gitBranchWatcher", (branch, branchUrl) => ({
|
|
267
|
+
branch,
|
|
268
|
+
branchUrl,
|
|
269
|
+
|
|
270
|
+
init() {
|
|
271
|
+
this.$watch("branch", () => {
|
|
272
|
+
this.$dispatch("reload")
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
window.addEventListener("focus", () => this.fetchCurrentBranch())
|
|
276
|
+
},
|
|
277
|
+
|
|
278
|
+
fetchCurrentBranch() {
|
|
279
|
+
fetch(this.branchUrl, {
|
|
280
|
+
method: "GET",
|
|
281
|
+
headers: {
|
|
282
|
+
Accept: "application/json",
|
|
283
|
+
},
|
|
284
|
+
})
|
|
285
|
+
.then((response) => response.json())
|
|
286
|
+
.then((data) => {
|
|
287
|
+
this.branch = data;
|
|
288
|
+
})
|
|
289
|
+
.catch(showFetchError);
|
|
290
|
+
},
|
|
291
|
+
}))
|
|
252
292
|
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
@import "variables";
|
|
1
|
+
@import "variables.css";
|
|
2
2
|
|
|
3
|
-
@import "elements";
|
|
4
|
-
@import "layout";
|
|
5
|
-
@import "utilities";
|
|
3
|
+
@import "elements.css";
|
|
4
|
+
@import "layout.css";
|
|
5
|
+
@import "utilities.css";
|
|
6
6
|
|
|
7
|
-
@import "components/toggle";
|
|
7
|
+
@import "components/toggle.css";
|
|
8
8
|
|
|
9
9
|
[x-cloak] {
|
|
10
10
|
display: none !important;
|
|
@@ -2,6 +2,7 @@ html {
|
|
|
2
2
|
color-scheme: light;
|
|
3
3
|
|
|
4
4
|
--hue-primary: 35;
|
|
5
|
+
--hue-on: 140;
|
|
5
6
|
--saturation-bg: 5%;
|
|
6
7
|
--lightness-bg0: 92%; /* page */
|
|
7
8
|
--lightness-bg2: 97%; /* raised surfaces: inputs, badges */
|
|
@@ -11,8 +12,11 @@ html {
|
|
|
11
12
|
--lightness-fg: 10%;
|
|
12
13
|
--lightness-muted: 42%;
|
|
13
14
|
--lightness-shadow: 65%;
|
|
15
|
+
--saturation-on: 60%; /* toggle track when on */
|
|
16
|
+
--lightness-on: 38%;
|
|
14
17
|
|
|
15
18
|
--color-primary: hsl(var(--hue-primary), 90%, 50%);
|
|
19
|
+
--color-on: hsl(var(--hue-on), var(--saturation-on), var(--lightness-on));
|
|
16
20
|
--color-text: hsl(var(--hue-primary), 0%, var(--lightness-fg));
|
|
17
21
|
--color-text-muted: hsl(var(--hue-primary), 5%, var(--lightness-muted));
|
|
18
22
|
--color-shadow: hsl(0, var(--saturation-bg), var(--lightness-shadow));
|
|
@@ -43,6 +47,7 @@ html {
|
|
|
43
47
|
);
|
|
44
48
|
}
|
|
45
49
|
|
|
50
|
+
/* Keep in sync with the block below */
|
|
46
51
|
@media (prefers-color-scheme: dark) {
|
|
47
52
|
html:not(.light-mode) {
|
|
48
53
|
color-scheme: dark;
|
|
@@ -55,5 +60,23 @@ html {
|
|
|
55
60
|
--lightness-fg: 90%;
|
|
56
61
|
--lightness-muted: 60%;
|
|
57
62
|
--lightness-shadow: 3%;
|
|
63
|
+
--saturation-on: 45%;
|
|
64
|
+
--lightness-on: 48%;
|
|
58
65
|
}
|
|
59
66
|
}
|
|
67
|
+
|
|
68
|
+
/* Keep in sync with the block above */
|
|
69
|
+
html.dark-mode {
|
|
70
|
+
color-scheme: dark;
|
|
71
|
+
|
|
72
|
+
--lightness-bg0: 8%;
|
|
73
|
+
--lightness-bg2: 16%;
|
|
74
|
+
--lightness-track: 22%;
|
|
75
|
+
--lightness-thumb: 70%;
|
|
76
|
+
--lightness-disabled: 12%;
|
|
77
|
+
--lightness-fg: 90%;
|
|
78
|
+
--lightness-muted: 60%;
|
|
79
|
+
--lightness-shadow: 3%;
|
|
80
|
+
--saturation-on: 45%;
|
|
81
|
+
--lightness-on: 48%;
|
|
82
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Toogle
|
|
2
|
+
# Serves our own CSS and JS instead of going through the host's asset
|
|
3
|
+
# pipeline: hosts that only serve precompiled assets, or whose web server
|
|
4
|
+
# answers /assets/* itself, never deliver them otherwise.
|
|
5
|
+
class AssetsController < ApplicationController
|
|
6
|
+
ROOT = Engine.root.join("app/assets")
|
|
7
|
+
|
|
8
|
+
# Only these files are served, so no path from the URL ever reaches the
|
|
9
|
+
# filesystem.
|
|
10
|
+
FILES = Dir[ROOT.join("{stylesheets,javascript}/**/*.{css,js}")]
|
|
11
|
+
.index_by { Pathname(_1).relative_path_from(ROOT).to_s }
|
|
12
|
+
|
|
13
|
+
# Static public files: nothing to protect, and Rails' cross-origin check
|
|
14
|
+
# would otherwise refuse to serve JavaScript to a <script> tag.
|
|
15
|
+
skip_forgery_protection
|
|
16
|
+
|
|
17
|
+
def show
|
|
18
|
+
file = FILES[params[:path]]
|
|
19
|
+
return head :not_found unless file
|
|
20
|
+
|
|
21
|
+
# Send the content, not the file: GitLab enables X-Sendfile, which hands
|
|
22
|
+
# file bodies to Workhorse, and Workhorse may run on another host (as in
|
|
23
|
+
# Caproni) where this path doesn't exist.
|
|
24
|
+
send_data File.read(file),
|
|
25
|
+
type: Mime::Type.lookup_by_extension(File.extname(file).delete(".")),
|
|
26
|
+
disposition: :inline
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
!!!
|
|
2
|
-
|
|
2
|
+
- theme_class = {"true" => "dark-mode", "false" => "light-mode"}[request.cookies["toogle-dark"]]
|
|
3
|
+
%html{ class: theme_class }
|
|
3
4
|
%head
|
|
4
5
|
%meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
|
|
5
6
|
%meta(name="viewport" content="width=device-width, initial-scale=1.0")
|
|
@@ -10,15 +11,17 @@
|
|
|
10
11
|
%title Feature flags
|
|
11
12
|
= csrf_meta_tags
|
|
12
13
|
= csp_meta_tag
|
|
13
|
-
=
|
|
14
|
-
=
|
|
14
|
+
%link(rel="stylesheet" media="all" href="#{asset_file_path("stylesheets/toogle/application.css", v: Toogle::VERSION)}")
|
|
15
|
+
%script(src="#{asset_file_path("javascript/toogle/application.js", v: Toogle::VERSION)}")
|
|
15
16
|
%script(defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js")
|
|
16
17
|
|
|
17
18
|
%body
|
|
18
19
|
%header
|
|
19
20
|
%nav.d-flex.gap
|
|
20
|
-
=
|
|
21
|
-
=
|
|
21
|
+
%div(x-data="gitBranchWatcher(#{Toogle::GitRepo.current_branch.to_json}, '#{branch_url}')")
|
|
22
|
+
= link_to main_app.root_path do
|
|
23
|
+
= render partial: "shared/logo", formats: :svg
|
|
24
|
+
%code(x-text="branch" title="Current git branch")
|
|
22
25
|
|
|
23
26
|
%button(x-data="darkModeSwitcher" x-bind="button")
|
|
24
27
|
%svg(x-show="isDark" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round")
|
data/config/routes.rb
CHANGED
data/lib/toogle/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gdk-toogle
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Thomas Hutterer
|
|
@@ -90,7 +90,6 @@ files:
|
|
|
90
90
|
- MIT-LICENSE
|
|
91
91
|
- README.md
|
|
92
92
|
- Rakefile
|
|
93
|
-
- app/assets/config/toogle_manifest.js
|
|
94
93
|
- app/assets/javascript/toogle/application.js
|
|
95
94
|
- app/assets/stylesheets/toogle/application.css
|
|
96
95
|
- app/assets/stylesheets/toogle/components/toggle.css
|
|
@@ -99,10 +98,13 @@ files:
|
|
|
99
98
|
- app/assets/stylesheets/toogle/utilities.css
|
|
100
99
|
- app/assets/stylesheets/toogle/variables.css
|
|
101
100
|
- app/controllers/toogle/application_controller.rb
|
|
101
|
+
- app/controllers/toogle/assets_controller.rb
|
|
102
|
+
- app/controllers/toogle/branches_controller.rb
|
|
102
103
|
- app/controllers/toogle/definitions_controller.rb
|
|
103
104
|
- app/controllers/toogle/features_controller.rb
|
|
104
105
|
- app/models/toogle/definition.rb
|
|
105
106
|
- app/models/toogle/feature.rb
|
|
107
|
+
- app/services/toogle/git_repo.rb
|
|
106
108
|
- app/views/layouts/toogle/application.html.haml
|
|
107
109
|
- app/views/toogle/features/_details_button.html.haml
|
|
108
110
|
- app/views/toogle/features/index.html.haml
|
|
@@ -132,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
132
134
|
- !ruby/object:Gem::Version
|
|
133
135
|
version: '0'
|
|
134
136
|
requirements: []
|
|
135
|
-
rubygems_version: 4.0.
|
|
137
|
+
rubygems_version: 4.0.22
|
|
136
138
|
specification_version: 4
|
|
137
139
|
summary: Toogle toggles feature flags
|
|
138
140
|
test_files: []
|