audited-timeline 0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/dependabot.yml +10 -0
- data/.github/workflows/codeql-analysis.yml +27 -0
- data/.github/workflows/gem-build.yml +18 -0
- data/.github/workflows/gem-push.yml +27 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Dockerfile +14 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +177 -0
- data/README.md +81 -0
- data/Rakefile +8 -0
- data/app/assets/stylesheets/audited-timeline/_audits.scss +10 -0
- data/app/assets/stylesheets/audited-timeline/_timeline.scss +135 -0
- data/app/assets/stylesheets/audited-timeline/_variables.scss +12 -0
- data/app/assets/stylesheets/audited-timeline.scss +3 -0
- data/app/views/audited_timeline/_diff.html.erb +25 -0
- data/app/views/audited_timeline/_diff_create.html.erb +1 -0
- data/app/views/audited_timeline/_diff_destroy.html.erb +1 -0
- data/app/views/audited_timeline/_diff_update.html.erb +2 -0
- data/app/views/audited_timeline/_list.html.erb +34 -0
- data/audited_timeline.gemspec +26 -0
- data/config/locales/audited_timeline.de.yml +13 -0
- data/config/locales/audited_timeline.en.yml +13 -0
- data/docker-compose.yml +7 -0
- data/images/screenshot.png +0 -0
- data/lib/audited-timeline.rb +1 -0
- data/lib/audited_timeline/audit.rb +9 -0
- data/lib/audited_timeline/audit_decorator.rb +78 -0
- data/lib/audited_timeline/audited_concern.rb +9 -0
- data/lib/audited_timeline/railtie.rb +15 -0
- data/lib/audited_timeline/view_helpers.rb +28 -0
- data/lib/audited_timeline.rb +7 -0
- metadata +131 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d4653647ba75b773e777546fe904aac57d540b7655da9a789ad38e5e514f6365
|
4
|
+
data.tar.gz: 445e18c24d7411fdc7b23993df0209ce4500d84fbb6fa9eb16169f575cbef7c2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: '0339cfec236473d6d8351e3500dd56b12e23897f07350d3c6640ef2eab29bdf31b6868670431b4334afcaf9bf03eee06340d2447a663bc5efc015d151affa8bb'
|
7
|
+
data.tar.gz: 4068c83fad885a04e2ce21adec50adde14429c0d8a439f178f53d4e099127348e87b425e43bdc9d0f982128d09a236907e7d8d215037bacdf5a4e7135cee0e67
|
@@ -0,0 +1,27 @@
|
|
1
|
+
name: "CodeQL"
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [master]
|
6
|
+
pull_request:
|
7
|
+
branches: [master]
|
8
|
+
schedule:
|
9
|
+
- cron: "25 2 * * 6"
|
10
|
+
|
11
|
+
jobs:
|
12
|
+
analyze:
|
13
|
+
name: Analyze
|
14
|
+
runs-on: ubuntu-latest
|
15
|
+
permissions:
|
16
|
+
actions: read
|
17
|
+
contents: read
|
18
|
+
security-events: write
|
19
|
+
steps:
|
20
|
+
- name: Checkout repository
|
21
|
+
uses: actions/checkout@v3
|
22
|
+
- name: Initialize CodeQL
|
23
|
+
uses: github/codeql-action/init@v2
|
24
|
+
- name: Autobuild
|
25
|
+
uses: github/codeql-action/autobuild@v2
|
26
|
+
- name: Perform CodeQL Analysis
|
27
|
+
uses: github/codeql-action/analyze@v2
|
@@ -0,0 +1,18 @@
|
|
1
|
+
name: Build Ruby Gem
|
2
|
+
|
3
|
+
on:
|
4
|
+
pull_request:
|
5
|
+
branches: [master]
|
6
|
+
|
7
|
+
jobs:
|
8
|
+
build:
|
9
|
+
name: Build
|
10
|
+
runs-on: ubuntu-latest
|
11
|
+
steps:
|
12
|
+
- uses: actions/checkout@v2
|
13
|
+
with:
|
14
|
+
fetch-depth: 0
|
15
|
+
- uses: ruby/setup-ruby@v1
|
16
|
+
with:
|
17
|
+
ruby-version: 3.0
|
18
|
+
- run: gem build *.gemspec
|
@@ -0,0 +1,27 @@
|
|
1
|
+
name: Build + Publish Ruby Gem
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
tags:
|
6
|
+
- "*"
|
7
|
+
|
8
|
+
jobs:
|
9
|
+
build:
|
10
|
+
name: Build + Publish
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
steps:
|
13
|
+
- uses: actions/checkout@v2
|
14
|
+
- uses: ruby/setup-ruby@v1
|
15
|
+
with:
|
16
|
+
ruby-version: 3.0
|
17
|
+
- name: Publish to RubyGems
|
18
|
+
run: |
|
19
|
+
mkdir -p $HOME/.gem
|
20
|
+
touch $HOME/.gem/credentials
|
21
|
+
chmod 0600 $HOME/.gem/credentials
|
22
|
+
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
23
|
+
gem build *.gemspec
|
24
|
+
gem push *.gem
|
25
|
+
env:
|
26
|
+
GEM_VERSION: ${{ vars.GITHUB_REF_NAME }}
|
27
|
+
GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
audited-timeline
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.0.0
|
data/Dockerfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
FROM ruby:3.0-alpine
|
2
|
+
|
3
|
+
WORKDIR /app
|
4
|
+
|
5
|
+
RUN apk add -U \
|
6
|
+
bash less tzdata shared-mime-info build-base libc6-compat git && \
|
7
|
+
gem install bundler bundler-audit
|
8
|
+
|
9
|
+
COPY *.gemspec Gemfile Gemfile.lock VERSION ./
|
10
|
+
RUN BUNDLER_VERSION=$(grep -A 1 "BUNDLED WITH" Gemfile.lock | grep -v "BUNDLED WITH" | tr -d '[:space:]') && \
|
11
|
+
gem install "bundler:$BUNDLER_VERSION" && \
|
12
|
+
bundle install --jobs $(nproc)
|
13
|
+
|
14
|
+
COPY . ./
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
audited-timeline (1.1.1)
|
5
|
+
audited (~> 4.3)
|
6
|
+
draper (>= 2.1.0)
|
7
|
+
rails (>= 4.0.0)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
actioncable (6.1.7.2)
|
13
|
+
actionpack (= 6.1.7.2)
|
14
|
+
activesupport (= 6.1.7.2)
|
15
|
+
nio4r (~> 2.0)
|
16
|
+
websocket-driver (>= 0.6.1)
|
17
|
+
actionmailbox (6.1.7.2)
|
18
|
+
actionpack (= 6.1.7.2)
|
19
|
+
activejob (= 6.1.7.2)
|
20
|
+
activerecord (= 6.1.7.2)
|
21
|
+
activestorage (= 6.1.7.2)
|
22
|
+
activesupport (= 6.1.7.2)
|
23
|
+
mail (>= 2.7.1)
|
24
|
+
actionmailer (6.1.7.2)
|
25
|
+
actionpack (= 6.1.7.2)
|
26
|
+
actionview (= 6.1.7.2)
|
27
|
+
activejob (= 6.1.7.2)
|
28
|
+
activesupport (= 6.1.7.2)
|
29
|
+
mail (~> 2.5, >= 2.5.4)
|
30
|
+
rails-dom-testing (~> 2.0)
|
31
|
+
actionpack (6.1.7.2)
|
32
|
+
actionview (= 6.1.7.2)
|
33
|
+
activesupport (= 6.1.7.2)
|
34
|
+
rack (~> 2.0, >= 2.0.9)
|
35
|
+
rack-test (>= 0.6.3)
|
36
|
+
rails-dom-testing (~> 2.0)
|
37
|
+
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
38
|
+
actiontext (6.1.7.2)
|
39
|
+
actionpack (= 6.1.7.2)
|
40
|
+
activerecord (= 6.1.7.2)
|
41
|
+
activestorage (= 6.1.7.2)
|
42
|
+
activesupport (= 6.1.7.2)
|
43
|
+
nokogiri (>= 1.8.5)
|
44
|
+
actionview (6.1.7.2)
|
45
|
+
activesupport (= 6.1.7.2)
|
46
|
+
builder (~> 3.1)
|
47
|
+
erubi (~> 1.4)
|
48
|
+
rails-dom-testing (~> 2.0)
|
49
|
+
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
50
|
+
activejob (6.1.7.2)
|
51
|
+
activesupport (= 6.1.7.2)
|
52
|
+
globalid (>= 0.3.6)
|
53
|
+
activemodel (6.1.7.2)
|
54
|
+
activesupport (= 6.1.7.2)
|
55
|
+
activemodel-serializers-xml (1.0.2)
|
56
|
+
activemodel (> 5.x)
|
57
|
+
activesupport (> 5.x)
|
58
|
+
builder (~> 3.1)
|
59
|
+
activerecord (6.1.7.2)
|
60
|
+
activemodel (= 6.1.7.2)
|
61
|
+
activesupport (= 6.1.7.2)
|
62
|
+
activestorage (6.1.7.2)
|
63
|
+
actionpack (= 6.1.7.2)
|
64
|
+
activejob (= 6.1.7.2)
|
65
|
+
activerecord (= 6.1.7.2)
|
66
|
+
activesupport (= 6.1.7.2)
|
67
|
+
marcel (~> 1.0)
|
68
|
+
mini_mime (>= 1.1.0)
|
69
|
+
activesupport (6.1.7.2)
|
70
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
71
|
+
i18n (>= 1.6, < 2)
|
72
|
+
minitest (>= 5.1)
|
73
|
+
tzinfo (~> 2.0)
|
74
|
+
zeitwerk (~> 2.3)
|
75
|
+
audited (4.10.0)
|
76
|
+
activerecord (>= 4.2, < 6.2)
|
77
|
+
builder (3.2.4)
|
78
|
+
concurrent-ruby (1.2.0)
|
79
|
+
crass (1.0.6)
|
80
|
+
date (3.3.3)
|
81
|
+
draper (4.0.2)
|
82
|
+
actionpack (>= 5.0)
|
83
|
+
activemodel (>= 5.0)
|
84
|
+
activemodel-serializers-xml (>= 1.0)
|
85
|
+
activesupport (>= 5.0)
|
86
|
+
request_store (>= 1.0)
|
87
|
+
ruby2_keywords
|
88
|
+
erubi (1.12.0)
|
89
|
+
globalid (1.1.0)
|
90
|
+
activesupport (>= 5.0)
|
91
|
+
i18n (1.12.0)
|
92
|
+
concurrent-ruby (~> 1.0)
|
93
|
+
loofah (2.19.1)
|
94
|
+
crass (~> 1.0.2)
|
95
|
+
nokogiri (>= 1.5.9)
|
96
|
+
mail (2.8.0.1)
|
97
|
+
mini_mime (>= 0.1.1)
|
98
|
+
net-imap
|
99
|
+
net-pop
|
100
|
+
net-smtp
|
101
|
+
marcel (1.0.2)
|
102
|
+
method_source (1.0.0)
|
103
|
+
mini_mime (1.1.2)
|
104
|
+
mini_portile2 (2.8.1)
|
105
|
+
minitest (5.17.0)
|
106
|
+
net-imap (0.3.4)
|
107
|
+
date
|
108
|
+
net-protocol
|
109
|
+
net-pop (0.1.2)
|
110
|
+
net-protocol
|
111
|
+
net-protocol (0.2.1)
|
112
|
+
timeout
|
113
|
+
net-smtp (0.3.3)
|
114
|
+
net-protocol
|
115
|
+
nio4r (2.5.8)
|
116
|
+
nokogiri (1.14.1)
|
117
|
+
mini_portile2 (~> 2.8.0)
|
118
|
+
racc (~> 1.4)
|
119
|
+
racc (1.6.2)
|
120
|
+
rack (2.2.6.2)
|
121
|
+
rack-test (2.0.2)
|
122
|
+
rack (>= 1.3)
|
123
|
+
rails (6.1.7.2)
|
124
|
+
actioncable (= 6.1.7.2)
|
125
|
+
actionmailbox (= 6.1.7.2)
|
126
|
+
actionmailer (= 6.1.7.2)
|
127
|
+
actionpack (= 6.1.7.2)
|
128
|
+
actiontext (= 6.1.7.2)
|
129
|
+
actionview (= 6.1.7.2)
|
130
|
+
activejob (= 6.1.7.2)
|
131
|
+
activemodel (= 6.1.7.2)
|
132
|
+
activerecord (= 6.1.7.2)
|
133
|
+
activestorage (= 6.1.7.2)
|
134
|
+
activesupport (= 6.1.7.2)
|
135
|
+
bundler (>= 1.15.0)
|
136
|
+
railties (= 6.1.7.2)
|
137
|
+
sprockets-rails (>= 2.0.0)
|
138
|
+
rails-dom-testing (2.0.3)
|
139
|
+
activesupport (>= 4.2.0)
|
140
|
+
nokogiri (>= 1.6)
|
141
|
+
rails-html-sanitizer (1.5.0)
|
142
|
+
loofah (~> 2.19, >= 2.19.1)
|
143
|
+
railties (6.1.7.2)
|
144
|
+
actionpack (= 6.1.7.2)
|
145
|
+
activesupport (= 6.1.7.2)
|
146
|
+
method_source
|
147
|
+
rake (>= 12.2)
|
148
|
+
thor (~> 1.0)
|
149
|
+
rake (13.0.6)
|
150
|
+
request_store (1.5.1)
|
151
|
+
rack (>= 1.4)
|
152
|
+
ruby2_keywords (0.0.5)
|
153
|
+
sprockets (4.2.0)
|
154
|
+
concurrent-ruby (~> 1.0)
|
155
|
+
rack (>= 2.2.4, < 4)
|
156
|
+
sprockets-rails (3.4.2)
|
157
|
+
actionpack (>= 5.2)
|
158
|
+
activesupport (>= 5.2)
|
159
|
+
sprockets (>= 3.0.0)
|
160
|
+
thor (1.2.1)
|
161
|
+
timeout (0.3.1)
|
162
|
+
tzinfo (2.0.6)
|
163
|
+
concurrent-ruby (~> 1.0)
|
164
|
+
websocket-driver (0.7.5)
|
165
|
+
websocket-extensions (>= 0.1.0)
|
166
|
+
websocket-extensions (0.1.5)
|
167
|
+
zeitwerk (2.6.6)
|
168
|
+
|
169
|
+
PLATFORMS
|
170
|
+
ruby
|
171
|
+
|
172
|
+
DEPENDENCIES
|
173
|
+
audited-timeline!
|
174
|
+
bundler
|
175
|
+
|
176
|
+
BUNDLED WITH
|
177
|
+
2.4.6
|
data/README.md
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
# Audited Timeline
|
2
|
+
|
3
|
+
This gem provides a frontend to the [audited](https://github.com/collectiveidea/audited) gem.
|
4
|
+
|
5
|
+
![Screenshot](https://raw.githubusercontent.com/ninech/audited-timeline/master/images/screenshot.png?token=AAHmGTc4OGjO-QUvWWENxW-aR7QQu0Q2ks5VYuTjwA%3D%3D)
|
6
|
+
|
7
|
+
## Setup
|
8
|
+
|
9
|
+
Add the gem to your `Gemfile` and run `bundle install`.
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'audited-timeline'
|
13
|
+
```
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
### Rendering the timeline
|
18
|
+
|
19
|
+
Render the `audited_timeline/list` partial and provide it the audits to be
|
20
|
+
rendered:
|
21
|
+
|
22
|
+
```erb
|
23
|
+
<%= render 'audited_timeline/list', audits: @user.all_audits %>
|
24
|
+
```
|
25
|
+
|
26
|
+
### Add CSS Styles
|
27
|
+
|
28
|
+
Include `audited-timeline` in your `application.scss`:
|
29
|
+
|
30
|
+
```sass
|
31
|
+
@import "audited-timeline";
|
32
|
+
```
|
33
|
+
|
34
|
+
### Rendering associated audits
|
35
|
+
|
36
|
+
To ease rendering a timeline which includes associated audits, there is a
|
37
|
+
`AuditedTimeline::AuditedConcern`. Include it in your model along with `audited` and
|
38
|
+
`has_associated_audits`:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
class User < ActiveRecord::Base
|
42
|
+
include AuditedTimeline::AuditedConcern
|
43
|
+
audited
|
44
|
+
has_associated_audits
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
### Overriding an audit diff
|
49
|
+
|
50
|
+
It is possible to easily override an audit diff.
|
51
|
+
|
52
|
+
In development environment, each audit which has been rendered with the default
|
53
|
+
partial contains a HTML comment which points you to the partial you would have
|
54
|
+
to create.
|
55
|
+
|
56
|
+
```html
|
57
|
+
<div class="audited-timeline-body">
|
58
|
+
<!-- create partial audits/user.create to override this table -->
|
59
|
+
<h1>User</h1>
|
60
|
+
<table class="diff">
|
61
|
+
...
|
62
|
+
</table>
|
63
|
+
</div>
|
64
|
+
```
|
65
|
+
|
66
|
+
In this case, create in your application `app/views/audits/_user.create.html.erb`
|
67
|
+
to override this audit type.
|
68
|
+
|
69
|
+
audited-timeline will provide a locale called `audit` to your partial.
|
70
|
+
|
71
|
+
### Readable object names
|
72
|
+
|
73
|
+
audited-timeline will simply call `#to_s` on your model name. To prevent having
|
74
|
+
`#<User:0x007fe2e8a25f58>` in your timeline, define `#to_s` on your `User`
|
75
|
+
model:
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
class User < ActiveRecord::Base
|
79
|
+
alias_attribute :to_s, :fullname
|
80
|
+
end
|
81
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
.audited-timeline-list .audited-timeline-wrapper:first-child {
|
2
|
+
margin-top: 0;
|
3
|
+
}
|
4
|
+
|
5
|
+
.audited-timeline-wrapper {
|
6
|
+
margin-bottom: $base-spacing;
|
7
|
+
margin-top: $base-spacing;
|
8
|
+
padding: 2px 0px 2px;
|
9
|
+
position: relative;
|
10
|
+
|
11
|
+
&:first-child {
|
12
|
+
margin-top: 0;
|
13
|
+
}
|
14
|
+
|
15
|
+
.avatar {
|
16
|
+
float: left;
|
17
|
+
margin-left: -64px;
|
18
|
+
border-radius: $base-border-radius;
|
19
|
+
}
|
20
|
+
|
21
|
+
.with-avatars {
|
22
|
+
padding-left: 64px;
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
.audited-timeline-wrapper .with-avatars .audited-timeline-item {
|
27
|
+
position: relative;
|
28
|
+
|
29
|
+
&:before, &:after {
|
30
|
+
border-color: transparent;
|
31
|
+
border-style: solid solid outset;
|
32
|
+
content: ' ';
|
33
|
+
display: block;
|
34
|
+
height: 0;
|
35
|
+
left: -16px;
|
36
|
+
position: absolute;
|
37
|
+
right: 100%;
|
38
|
+
top: 11px;
|
39
|
+
width: 0;
|
40
|
+
}
|
41
|
+
|
42
|
+
&:before {
|
43
|
+
border-right-color: $base-border-color;
|
44
|
+
border-width: 8px;
|
45
|
+
}
|
46
|
+
|
47
|
+
&:after {
|
48
|
+
border-right-color: #f2f8fa;
|
49
|
+
border-width: 7px;
|
50
|
+
margin-left: 2px;
|
51
|
+
margin-top: 1px;
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
.audited-timeline-item {
|
56
|
+
border: $base-border;
|
57
|
+
border-radius: $base-border-radius;
|
58
|
+
|
59
|
+
&:hover .audited-timeline-header .audited-timeline-actions {
|
60
|
+
visibility: visible;
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
.audited-timeline-header {
|
65
|
+
background-color: lighten($light-gray, 15%);
|
66
|
+
border-bottom: 1px solid #eee;
|
67
|
+
border-top-left-radius: $base-border-radius;
|
68
|
+
border-top-right-radius: $base-border-radius;
|
69
|
+
padding: $base-spacing/3 $base-spacing/1.5;
|
70
|
+
|
71
|
+
.audited-timeline-user {
|
72
|
+
font-weight: bold;
|
73
|
+
margin-right: 0.5em;
|
74
|
+
}
|
75
|
+
|
76
|
+
.audited-timeline-date {
|
77
|
+
color: $dark-gray;
|
78
|
+
font-size: 0.8em;
|
79
|
+
}
|
80
|
+
|
81
|
+
.audited-timeline-actions {
|
82
|
+
float: right;
|
83
|
+
visibility: hidden;
|
84
|
+
a { color: $light-gray; }
|
85
|
+
a:hover { color: $blue; }
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
.audited-timeline-body {
|
90
|
+
background: #fff;
|
91
|
+
padding: $base-spacing/1.5;
|
92
|
+
|
93
|
+
p {
|
94
|
+
margin-bottom: 0;
|
95
|
+
}
|
96
|
+
|
97
|
+
form.simple_form {
|
98
|
+
float: none;
|
99
|
+
margin: 0;
|
100
|
+
width: 100%;
|
101
|
+
}
|
102
|
+
|
103
|
+
table {
|
104
|
+
margin: 0;
|
105
|
+
|
106
|
+
th {
|
107
|
+
padding: 0 0 .25em;
|
108
|
+
}
|
109
|
+
|
110
|
+
th:first-child {
|
111
|
+
width: 12em;
|
112
|
+
}
|
113
|
+
|
114
|
+
td {
|
115
|
+
font-size: .9em;
|
116
|
+
padding: .25em 0;
|
117
|
+
}
|
118
|
+
|
119
|
+
tr:last-child td {
|
120
|
+
border-bottom: 0;
|
121
|
+
}
|
122
|
+
|
123
|
+
tr th:first-child,
|
124
|
+
tr td:first-child {
|
125
|
+
white-space: nowrap;
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
h1 {
|
130
|
+
font-size: 1.2em;
|
131
|
+
height: auto !important;
|
132
|
+
margin: 0 0 .5em;
|
133
|
+
padding: 0;
|
134
|
+
}
|
135
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
$green: #27AE60 !default;
|
2
|
+
$red: #E74C3C !default;
|
3
|
+
$blue: #009ad7 !default;
|
4
|
+
$light-gray: #CDCFCE !default;
|
5
|
+
$dark-gray: #333 !default;
|
6
|
+
|
7
|
+
$base-line-height: 1.5 !default;
|
8
|
+
$base-spacing: $base-line-height * 1em !default;
|
9
|
+
|
10
|
+
$base-border-color: $light-gray !default;
|
11
|
+
$base-border: 1px solid $base-border-color !default;
|
12
|
+
$base-border-radius: 3px !default;
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<%= cache [audit, I18n.locale, :diff] do %>
|
2
|
+
<h1><%= audit.audited_title %></h1>
|
3
|
+
<table class="diff">
|
4
|
+
<thead>
|
5
|
+
<tr>
|
6
|
+
<th><%= t '.attribute' %></th>
|
7
|
+
<% if audit.action == 'update' %>
|
8
|
+
<th><%= t '.from' %></th>
|
9
|
+
<th><%= t '.to' %></th>
|
10
|
+
<% else %>
|
11
|
+
<th><%= t '.value' %></th>
|
12
|
+
<% end %>
|
13
|
+
</tr>
|
14
|
+
</thead>
|
15
|
+
<tbody>
|
16
|
+
<% audit.human_audited_changes.each_pair do |field, value| %>
|
17
|
+
<% next if [value].flatten.join.blank? %>
|
18
|
+
<tr>
|
19
|
+
<td><%= audit.auditable_class.human_attribute_name field %></td>
|
20
|
+
<%= render "audited_timeline/diff_#{audit.action}", field: field, value: value %>
|
21
|
+
</tr>
|
22
|
+
<% end %>
|
23
|
+
</tbody>
|
24
|
+
</table>
|
25
|
+
<% end %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<td><%= value[0] %></td>
|
@@ -0,0 +1 @@
|
|
1
|
+
<td><%= value[0] %></td>
|
@@ -0,0 +1,34 @@
|
|
1
|
+
<% with_avatars = local_assigns[:with_avatars] == true ? true : false %>
|
2
|
+
<% sort = local_assigns[:sort] || 'desc' %>
|
3
|
+
<% limit = local_assigns[:limit] || 25 %>
|
4
|
+
<div class="audited-timeline-list">
|
5
|
+
<% audits.reorder("created_at #{sort}").limit(limit).decorate.each do |audit| %>
|
6
|
+
<div id="<%= dom_id audit %>" class="audited-timeline-wrapper <%= 'with-avatars' if with_avatars == true %> ">
|
7
|
+
<% if with_avatars == true && audit.user.present? %>
|
8
|
+
<%= audited_timeline_user_gravatar audit.user %>
|
9
|
+
<% end %>
|
10
|
+
|
11
|
+
<div class="audited-timeline-item audited-timeline-audit <%= audit.action %>">
|
12
|
+
<div class="audited-timeline-header">
|
13
|
+
<span class="audited-timeline-user">
|
14
|
+
<%= audit.user %>
|
15
|
+
<%= audited_timeline_action_icon audit %>
|
16
|
+
</span>
|
17
|
+
<span class="audited-timeline-date">
|
18
|
+
<%= l audit.created_at, format: :audited_timeline %>
|
19
|
+
</span>
|
20
|
+
</div>
|
21
|
+
<div class="audited-timeline-body">
|
22
|
+
<% if lookup_context.template_exists?(audited_timeline_partial_for(audit), [], true) %>
|
23
|
+
<%= render audited_timeline_partial_for(audit), audit: audit %>
|
24
|
+
<% else %>
|
25
|
+
<% if Rails.env.development? %>
|
26
|
+
<!-- create partial <%= audited_timeline_partial_for(audit) %> to override this table -->
|
27
|
+
<% end %>
|
28
|
+
<%= render 'audited_timeline/diff', audit: audit %>
|
29
|
+
<% end %>
|
30
|
+
</div>
|
31
|
+
</div>
|
32
|
+
</div>
|
33
|
+
<% end %>
|
34
|
+
</div>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'audited-timeline'
|
8
|
+
spec.version = ENV.fetch("GEM_VERSION", [`git describe --tags --abbrev=0`, `git rev-parse --short HEAD`].map(&:chomp).join(".")).delete_prefix("v")
|
9
|
+
spec.authors = ['nine.ch Development']
|
10
|
+
spec.email = ['development@nine.ch']
|
11
|
+
spec.summary = 'Frontent to audited'
|
12
|
+
spec.homepage = 'https://github.com/ninech/audited-timeline'
|
13
|
+
spec.license = 'MIT'
|
14
|
+
spec.description = 'audited-timeline provides timeline frontend to audited'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler"
|
22
|
+
|
23
|
+
spec.add_runtime_dependency 'audited', '~> 4.3'
|
24
|
+
spec.add_runtime_dependency 'rails', '>= 4.0.0'
|
25
|
+
spec.add_runtime_dependency 'draper', '>= 2.1.0'
|
26
|
+
end
|
data/docker-compose.yml
ADDED
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'audited_timeline'
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'draper'
|
2
|
+
|
3
|
+
module AuditedTimeline
|
4
|
+
class AuditDecorator < ::Draper::Decorator
|
5
|
+
delegate_all
|
6
|
+
|
7
|
+
def human_audited_changes
|
8
|
+
human_changes = {}
|
9
|
+
audited_changes.each_pair do |field, value|
|
10
|
+
value = [value].flatten
|
11
|
+
if field.end_with?('_id')
|
12
|
+
human_changes[field] = value.map { |v| object_name_by_field_and_value(field, v) }
|
13
|
+
else
|
14
|
+
human_changes[field] = value.map { |v| human_value(field, v) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
human_changes
|
18
|
+
end
|
19
|
+
|
20
|
+
def audited_title
|
21
|
+
[
|
22
|
+
auditable_type.constantize.model_name.human,
|
23
|
+
object_name_by_type_and_value(auditable_type, auditable_id)
|
24
|
+
].join(' ')
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def human_value(field, value)
|
30
|
+
return I18n.t('audited_timeline.yes') if value == true
|
31
|
+
return I18n.t('audited_timeline.no') if value == false
|
32
|
+
if enum_values(field)
|
33
|
+
return I18n.t("#{audited_class.table_name.singularize}.#{field}.#{enum_value(field, value)}")
|
34
|
+
end
|
35
|
+
value
|
36
|
+
end
|
37
|
+
|
38
|
+
def object_name_by_field_and_value(field, value)
|
39
|
+
return nil unless value
|
40
|
+
begin
|
41
|
+
obj= associated_class_name(auditable_type, field).unscoped.find(value)
|
42
|
+
"#{obj} (#{value})"
|
43
|
+
rescue
|
44
|
+
"unknown (#{value})"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def object_name_by_type_and_value(type, value)
|
49
|
+
return nil unless value
|
50
|
+
begin
|
51
|
+
type.constantize.unscoped.find(value)
|
52
|
+
rescue
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def enum_value(field, value)
|
58
|
+
if value.kind_of?(Integer)
|
59
|
+
enum_values(field).key(value)
|
60
|
+
else
|
61
|
+
value
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def enum_values(field)
|
66
|
+
audited_class.send(field.pluralize) if audited_class.respond_to?(field.pluralize)
|
67
|
+
end
|
68
|
+
|
69
|
+
def audited_class
|
70
|
+
object.auditable.class
|
71
|
+
end
|
72
|
+
|
73
|
+
def associated_class_name(model, associated_field)
|
74
|
+
association = associated_field.sub('_id', '').to_sym
|
75
|
+
model.constantize.reflect_on_association(association).class_name.constantize
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'audited_timeline/view_helpers'
|
2
|
+
|
3
|
+
module AuditedTimeline
|
4
|
+
class Engine < Rails::Engine
|
5
|
+
initializer 'audited_timeline.view_helpers' do
|
6
|
+
ActionView::Base.send :include, ViewHelpers
|
7
|
+
end
|
8
|
+
|
9
|
+
initializer 'audited_timeline.add_view_paths', after: :add_view_paths do
|
10
|
+
ActiveSupport.on_load(:action_controller) do
|
11
|
+
append_view_path "#{Gem.loaded_specs['audited-timeline'].full_gem_path}/app/views"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module AuditedTimeline
|
2
|
+
module ViewHelpers
|
3
|
+
def audited_timeline_action_icon(audit)
|
4
|
+
case audit.action
|
5
|
+
when 'create'
|
6
|
+
fa_icon 'plus-circle', class: 'action create'
|
7
|
+
when 'update'
|
8
|
+
fa_icon 'pencil', class: 'action update'
|
9
|
+
when 'destroy'
|
10
|
+
fa_icon 'trash-o', class: 'action destroy'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def audited_timeline_gravatar_url(email)
|
15
|
+
email_hash = Digest::MD5.hexdigest(email.to_s)
|
16
|
+
"https://www.gravatar.com/avatar/#{email_hash}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def audited_timeline_user_gravatar(user, options = {})
|
20
|
+
options.reverse_merge! class: 'avatar', alt: user.to_s, size: '48x48'
|
21
|
+
image_tag audited_timeline_gravatar_url(user.email), options
|
22
|
+
end
|
23
|
+
|
24
|
+
def audited_timeline_partial_for(audit)
|
25
|
+
"audits/#{audit.auditable_type.underscore}_#{audit.action}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: audited-timeline
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- nine.ch Development
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-02-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: audited
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.3'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rails
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 4.0.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 4.0.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: draper
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.1.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.1.0
|
69
|
+
description: audited-timeline provides timeline frontend to audited
|
70
|
+
email:
|
71
|
+
- development@nine.ch
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".github/dependabot.yml"
|
77
|
+
- ".github/workflows/codeql-analysis.yml"
|
78
|
+
- ".github/workflows/gem-build.yml"
|
79
|
+
- ".github/workflows/gem-push.yml"
|
80
|
+
- ".ruby-gemset"
|
81
|
+
- ".ruby-version"
|
82
|
+
- Dockerfile
|
83
|
+
- Gemfile
|
84
|
+
- Gemfile.lock
|
85
|
+
- README.md
|
86
|
+
- Rakefile
|
87
|
+
- app/assets/stylesheets/audited-timeline.scss
|
88
|
+
- app/assets/stylesheets/audited-timeline/_audits.scss
|
89
|
+
- app/assets/stylesheets/audited-timeline/_timeline.scss
|
90
|
+
- app/assets/stylesheets/audited-timeline/_variables.scss
|
91
|
+
- app/views/audited_timeline/_diff.html.erb
|
92
|
+
- app/views/audited_timeline/_diff_create.html.erb
|
93
|
+
- app/views/audited_timeline/_diff_destroy.html.erb
|
94
|
+
- app/views/audited_timeline/_diff_update.html.erb
|
95
|
+
- app/views/audited_timeline/_list.html.erb
|
96
|
+
- audited_timeline.gemspec
|
97
|
+
- config/locales/audited_timeline.de.yml
|
98
|
+
- config/locales/audited_timeline.en.yml
|
99
|
+
- docker-compose.yml
|
100
|
+
- images/screenshot.png
|
101
|
+
- lib/audited-timeline.rb
|
102
|
+
- lib/audited_timeline.rb
|
103
|
+
- lib/audited_timeline/audit.rb
|
104
|
+
- lib/audited_timeline/audit_decorator.rb
|
105
|
+
- lib/audited_timeline/audited_concern.rb
|
106
|
+
- lib/audited_timeline/railtie.rb
|
107
|
+
- lib/audited_timeline/view_helpers.rb
|
108
|
+
homepage: https://github.com/ninech/audited-timeline
|
109
|
+
licenses:
|
110
|
+
- MIT
|
111
|
+
metadata: {}
|
112
|
+
post_install_message:
|
113
|
+
rdoc_options: []
|
114
|
+
require_paths:
|
115
|
+
- lib
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
requirements: []
|
127
|
+
rubygems_version: 3.4.1
|
128
|
+
signing_key:
|
129
|
+
specification_version: 4
|
130
|
+
summary: Frontent to audited
|
131
|
+
test_files: []
|