doc_contract 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +191 -0
- data/Rakefile +8 -0
- data/app/assets/config/doc_contract_manifest.js +3 -0
- data/app/assets/javascripts/doc_contract/application.coffee +68 -0
- data/app/assets/stylesheets/doc_contract/application.sass +52 -0
- data/app/assets/stylesheets/doc_contract/pandoc.css +15 -0
- data/app/controllers/concerns/doc_contract/shared_template_and_instance_methods.rb +71 -0
- data/app/controllers/doc_contract/application_controller.rb +20 -0
- data/app/controllers/doc_contract/contract_instances_controller.rb +56 -0
- data/app/controllers/doc_contract/contract_templates_controller.rb +69 -0
- data/app/helpers/doc_contract/application_helper.rb +178 -0
- data/app/models/concerns/yaml_validator.rb +9 -0
- data/app/models/doc_contract/contract_instance.rb +39 -0
- data/app/models/doc_contract/contract_template.rb +37 -0
- data/app/views/doc_contract/application/_button-destroy-record.html.slim +1 -0
- data/app/views/doc_contract/application/_button-edit-record.html.slim +1 -0
- data/app/views/doc_contract/application/_button-new-record.html.slim +1 -0
- data/app/views/doc_contract/application/_button-preview-html.html.slim +9 -0
- data/app/views/doc_contract/application/_button-preview-markdown.html.slim +9 -0
- data/app/views/doc_contract/application/_button-preview-pdf.html.slim +1 -0
- data/app/views/doc_contract/application/_definition_table_attribute_errors.html.slim +7 -0
- data/app/views/doc_contract/application/_messages.html.slim +4 -0
- data/app/views/doc_contract/application/_navigation.html.slim +18 -0
- data/app/views/doc_contract/application/main.html.slim +6 -0
- data/app/views/doc_contract/contract_instances/_form.html.slim +25 -0
- data/app/views/doc_contract/contract_instances/edit.html.slim +3 -0
- data/app/views/doc_contract/contract_instances/index.html.slim +34 -0
- data/app/views/doc_contract/contract_instances/new.html.slim +3 -0
- data/app/views/doc_contract/contract_instances/show.html.slim +25 -0
- data/app/views/doc_contract/contract_templates/_form.html.slim +34 -0
- data/app/views/doc_contract/contract_templates/edit.html.slim +3 -0
- data/app/views/doc_contract/contract_templates/index.html.slim +31 -0
- data/app/views/doc_contract/contract_templates/new.html.slim +3 -0
- data/app/views/doc_contract/contract_templates/show.html.slim +28 -0
- data/app/views/doc_contract/kaminari/_first_page.html.slim +2 -0
- data/app/views/doc_contract/kaminari/_gap.html.slim +2 -0
- data/app/views/doc_contract/kaminari/_last_page.html.slim +2 -0
- data/app/views/doc_contract/kaminari/_next_page.html.slim +2 -0
- data/app/views/doc_contract/kaminari/_page.html.slim +6 -0
- data/app/views/doc_contract/kaminari/_paginator.html.slim +11 -0
- data/app/views/doc_contract/kaminari/_prev_page.html.slim +2 -0
- data/app/views/layouts/doc_contract/application.html.slim +23 -0
- data/config/initializers/human_plural.rb +16 -0
- data/config/locales/en.yml +30 -0
- data/config/routes.rb +17 -0
- data/db/migrate/20220118150923_create_doc_contract_contract_templates.rb +10 -0
- data/db/migrate/20220121160034_add_markdown_to_doc_contract_contract_templates.rb +5 -0
- data/db/migrate/20220121165825_add_config_yml_to_doc_contract_contract_templates.rb +5 -0
- data/db/migrate/20220122151402_create_doc_contract_contract_instances.rb +11 -0
- data/db/migrate/20220125183437_add_titlepage_background_to_contract_templates.rb +5 -0
- data/lib/doc_contract/engine.rb +24 -0
- data/lib/doc_contract/handlebars.rb +99 -0
- data/lib/doc_contract/version.rb +3 -0
- data/lib/doc_contract.rb +9 -0
- data/lib/tasks/doc_contract_tasks.rake +4 -0
- metadata +254 -0
@@ -0,0 +1,178 @@
|
|
1
|
+
module DocContract
|
2
|
+
module ApplicationHelper
|
3
|
+
# Return active or nil based on the given route spec
|
4
|
+
# %li{ class: active_class('users') # true if controller is users, false otherwise
|
5
|
+
# %li{ class: active_class('pages#about') # true if controller is pages and action is about
|
6
|
+
#NOTE: Taken from the dunlop-core gem. That is the best maintained version
|
7
|
+
def active_class(*route_specs)
|
8
|
+
options = route_specs.extract_options!
|
9
|
+
return nil if Array.wrap(options[:except]).any?{|exception| current_route_spec?(exception) }
|
10
|
+
return 'active' if route_specs.any?{|rs| current_route_spec?(rs, options) }
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
|
14
|
+
# Check if the current route matches the route given as argument.
|
15
|
+
# The syntax is meant to be a bit similar to specifying routes in
|
16
|
+
# `config/routes.rb`.
|
17
|
+
# current_route_spec?('products') #=> true if controller name is products, false otherwise
|
18
|
+
# current_route_spec?('products#show') #=> true if controller_name is products AND action_name is show
|
19
|
+
# current_route_spec?('#show') #=> true if action_name is show, false otherwise
|
20
|
+
#NOTE: this helper is tested through the active_class helper
|
21
|
+
#NOTE: Taken from the dunlop-core gem. That is the best maintained version
|
22
|
+
def current_route_spec?(route_spec, options = {})
|
23
|
+
return route_spec.match([controller_path, action_name].join('#')) if route_spec.is_a?(Regexp)
|
24
|
+
controller, action = route_spec.split('#')
|
25
|
+
return action == params[:id] if controller_path == 'high_voltage/pages'
|
26
|
+
actual_controller_parts = controller_path.split('/')
|
27
|
+
if controller #and controller_path == controller
|
28
|
+
tested_controller_parts = controller.split('/')
|
29
|
+
return if tested_controller_parts.size > actual_controller_parts.size
|
30
|
+
if actual_controller_parts[0...tested_controller_parts.size] == tested_controller_parts
|
31
|
+
# controller spec matches
|
32
|
+
return true unless action
|
33
|
+
action_name == action
|
34
|
+
end
|
35
|
+
else
|
36
|
+
action_name == action
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
#NOTE: Taken from the dunlop-core gem. That is the best maintained version
|
41
|
+
def page_title(*args, &blk)
|
42
|
+
extra_content = capture(&blk) if blk.present?
|
43
|
+
if resource_title?(args)
|
44
|
+
@scope_model = args[1].is_a?(ActiveRecord::Base) ? args[1].class : args[1]
|
45
|
+
content = page_title_for_resource(args)
|
46
|
+
else
|
47
|
+
content = page_title_for_string(args)
|
48
|
+
end
|
49
|
+
content += extra_content if extra_content.present?
|
50
|
+
title_tag = content_tag(:h2, content, class: 'page-title ui header')
|
51
|
+
content_for :page_title, title_tag
|
52
|
+
title_tag
|
53
|
+
end
|
54
|
+
|
55
|
+
def resource_title?(args)
|
56
|
+
args.first.is_a?(Symbol) &&
|
57
|
+
(args[1].respond_to?(:model_name) || args[1].class.respond_to?(:model_name))
|
58
|
+
end
|
59
|
+
|
60
|
+
def page_title_for_string(args)
|
61
|
+
title = html_escape(args.first)
|
62
|
+
options = args.last.is_a?(Hash) ? args.last : {}
|
63
|
+
if back_options = options[:back]
|
64
|
+
url =
|
65
|
+
case back_options
|
66
|
+
when Array then polymorphic_path(back_options)
|
67
|
+
when true then :back
|
68
|
+
else back_options
|
69
|
+
end
|
70
|
+
if url
|
71
|
+
back_link = link_to content_tag(:i, nil, class: 'left arrow icon'), url, class: 'title-back-link'
|
72
|
+
title = back_link.safe_concat(title)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
title
|
76
|
+
end
|
77
|
+
|
78
|
+
def page_title_for_resource(args)
|
79
|
+
options = args.extract_options!
|
80
|
+
model = args[1].respond_to?(:model_name) ? args[1] : args[1].class
|
81
|
+
if args.first == :index
|
82
|
+
title = t('action.index.label', models: model.model_name.human_plural).html_safe
|
83
|
+
else
|
84
|
+
title = t("action.#{args.first}.label", model: model.model_name.human).html_safe
|
85
|
+
end
|
86
|
+
if back_options = options[:back]
|
87
|
+
url =
|
88
|
+
case back_options
|
89
|
+
when Array then polymorphic_path(back_options)
|
90
|
+
when true then :back
|
91
|
+
else back_options
|
92
|
+
end
|
93
|
+
if url
|
94
|
+
back_link = link_to content_tag(:i, nil, class: 'left arrow icon'), url, class: 'title-back-link'
|
95
|
+
title = back_link.safe_concat(title)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
title
|
99
|
+
end
|
100
|
+
|
101
|
+
def search_result_info(records)
|
102
|
+
from_item = (records.current_page - 1) * records.limit_value + 1
|
103
|
+
to_item = [from_item + records.size - 1, records.total_count].min
|
104
|
+
from_item = 0 if records.total_count.zero?
|
105
|
+
"#{from_item} - #{to_item} / #{records.total_count}"
|
106
|
+
end
|
107
|
+
|
108
|
+
def at(attribute_name, scope_model=nil)
|
109
|
+
scope_model ||= @scope_model
|
110
|
+
scope_model.human_attribute_name(attribute_name)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Search helpers from dunlop
|
114
|
+
def search_row(options = {}, &blk)
|
115
|
+
classes = Array.wrap(options[:class])
|
116
|
+
classes |= ['search']
|
117
|
+
classes << 'conditions-present' if @q.conditions.present?
|
118
|
+
content = capture(&blk)
|
119
|
+
content_tag(:tr, content, class: classes )
|
120
|
+
end
|
121
|
+
|
122
|
+
# This helper returns the link for showing a record inside a table
|
123
|
+
def table_show_link(record, path = nil, options = {})
|
124
|
+
if options.has_key?(:authorized)
|
125
|
+
return unless options[:authorized]
|
126
|
+
else
|
127
|
+
return unless can? :show, record
|
128
|
+
end
|
129
|
+
link_to(content_tag(:i,nil, class: 'folder open icon'), path || record, class: 'table-link show ui mini basic primary icon button')
|
130
|
+
end
|
131
|
+
|
132
|
+
# This helper returns the link for showing a record inside a table
|
133
|
+
def table_download_link(record, path = nil, options = {})
|
134
|
+
if options.has_key?(:authorized)
|
135
|
+
return unless options[:authorized]
|
136
|
+
else
|
137
|
+
return unless can? :download, record
|
138
|
+
end
|
139
|
+
link_to(content_tag(:i,nil, class: 'download icon'), path || [:download, record], class: 'table-link download ui mini violet icon button')
|
140
|
+
end
|
141
|
+
|
142
|
+
# This helper returns the link for editing a record inside a table
|
143
|
+
def table_edit_link(record, path = nil, options = {})
|
144
|
+
if options.has_key?(:authorized)
|
145
|
+
return unless options[:authorized]
|
146
|
+
else
|
147
|
+
return unless can? :update, record
|
148
|
+
end
|
149
|
+
link_to(content_tag(:i, nil, class: 'write icon'), path || [:edit, record], class: 'table-link edit ui mini basic yellow icon button')
|
150
|
+
end
|
151
|
+
|
152
|
+
def table_destroy_link(record, path = nil, options = {})
|
153
|
+
if options.has_key?(:authorized)
|
154
|
+
return unless options[:authorized]
|
155
|
+
else
|
156
|
+
return unless can? :destroy, record
|
157
|
+
end
|
158
|
+
confirm_text = "Are you sure you want to delete #{record.class.model_name.human}"
|
159
|
+
record_name = nil
|
160
|
+
record_name = record.presentation_name if record.respond_to?(:presentation_name)
|
161
|
+
record_name ||= record.name if record.respond_to?(:name)
|
162
|
+
record_name ||= record.title if record.respond_to?(:title)
|
163
|
+
confirm_text << " #{record_name}" if record_name.present?
|
164
|
+
confirm_text << "?"
|
165
|
+
link_to(content_tag(:i, nil, class: 'trash icon'), path || record, method: :delete, data: { confirm: confirm_text }, class: 'table-link destroy ui mini negative icon button')
|
166
|
+
end
|
167
|
+
|
168
|
+
# https://coderwall.com/p/7gqmog/display-flash-messages-with-semantic-ui-in-rails
|
169
|
+
def flash_class(level)
|
170
|
+
case level.to_sym
|
171
|
+
when :success then "ui positive message"
|
172
|
+
when :error, :alert then "ui negative message"
|
173
|
+
when :notice then "ui info message"
|
174
|
+
else "ui #{level} message"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class YamlValidator < ActiveModel::EachValidator
|
2
|
+
def validate_each(record, attribute, value)
|
3
|
+
return if value.blank?
|
4
|
+
object = YAML.load(value) rescue nil
|
5
|
+
unless object
|
6
|
+
record.errors.add attribute, (options[:message] || "is not valid YAML")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module DocContract
|
2
|
+
class ContractInstance < ApplicationRecord
|
3
|
+
validates :name, presence: true
|
4
|
+
belongs_to :contract_template
|
5
|
+
|
6
|
+
def config
|
7
|
+
own_config = YAML.load(config_yml.to_s) || {}
|
8
|
+
own_config.reverse_merge contract_template.config
|
9
|
+
end
|
10
|
+
|
11
|
+
def markdown
|
12
|
+
contract_template.markdown
|
13
|
+
end
|
14
|
+
|
15
|
+
def markdown=(value)
|
16
|
+
contract_template.markdown = value
|
17
|
+
end
|
18
|
+
|
19
|
+
def processed_markdown(config_addittions = {})
|
20
|
+
config = self.config
|
21
|
+
config.merge! config_addittions unless config_addittions.blank?
|
22
|
+
DocContract::Handlebars.compile(markdown, config)
|
23
|
+
end
|
24
|
+
|
25
|
+
def template_markdown(config_addittions = {})
|
26
|
+
config = self.config
|
27
|
+
config.merge! config_addittions unless config_addittions.blank?
|
28
|
+
result = DocContract::Handlebars.compile(markdown, config)
|
29
|
+
# prefix the markdown with the config (eisvogel pandoc)
|
30
|
+
"#{config.to_yaml}...\n\n"+result
|
31
|
+
end
|
32
|
+
|
33
|
+
def processed_html
|
34
|
+
result = processed_markdown.sub(/.*\n...\n\n/m, '')
|
35
|
+
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, tables: true)
|
36
|
+
markdown.render result
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module DocContract
|
2
|
+
class ContractTemplate < ApplicationRecord
|
3
|
+
HANDLEBARS_REGEX = /{{((#)?[a-z\._ ]+)}}/
|
4
|
+
has_many :contract_instances, dependent: :delete_all
|
5
|
+
|
6
|
+
validates :name, presence: true
|
7
|
+
validates :config_yml, yaml: true
|
8
|
+
|
9
|
+
def config
|
10
|
+
YAML.load(config_yml.to_s) || {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def processed_markdown(config_addittions = {})
|
14
|
+
config = self.config
|
15
|
+
config.merge! config_addittions unless config_addittions.blank?
|
16
|
+
DocContract::Handlebars.compile(markdown, config)
|
17
|
+
end
|
18
|
+
|
19
|
+
def template_markdown(config_addittions = {})
|
20
|
+
config = self.config
|
21
|
+
config.merge! config_addittions unless config_addittions.blank?
|
22
|
+
result = DocContract::Handlebars.compile(markdown, config)
|
23
|
+
# prefix the markdown with the config (eisvogel pandoc)
|
24
|
+
"#{config.to_yaml}...\n\n"+result
|
25
|
+
end
|
26
|
+
|
27
|
+
def processed_html
|
28
|
+
result = processed_markdown.sub(/.*\n...\n\n/m, '')
|
29
|
+
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, tables: true)
|
30
|
+
markdown.render result
|
31
|
+
end
|
32
|
+
|
33
|
+
def present_handlebars_expressions
|
34
|
+
markdown.scan(HANDLEBARS_REGEX).map(&:first).uniq
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
= link_to t('action.destroy.label', model: (record_class).model_name.human), record, class: 'ui red button', method: :delete, data: { confirm: t('general.are_you_sure') }
|
@@ -0,0 +1 @@
|
|
1
|
+
= link_to t('action.edit.label', model: (record_class).model_name.human), polymorphic_path(record, action: :edit), class: 'ui yellow button'
|
@@ -0,0 +1 @@
|
|
1
|
+
= link_to t('action.new.label', model: (record_class).model_name.human), polymorphic_path(record_class, action: :new), class: 'ui primary basic button'
|
@@ -0,0 +1,9 @@
|
|
1
|
+
.ui.pink.button.preview-html data-target=polymorphic_path(record, action: :processed_html) Preview html
|
2
|
+
#html-preview-modal.ui.overlay.fullscreen.modal
|
3
|
+
.header html preview handlebars interpreted
|
4
|
+
pre.scrolling.content
|
5
|
+
.ui.active.inline.loader
|
6
|
+
.actions
|
7
|
+
- unless params[:action] == 'edit'
|
8
|
+
= link_to t('Edit'), [record, action: :edit], class: 'ui yellow button'
|
9
|
+
.ui.cancel.button Close
|
@@ -0,0 +1,9 @@
|
|
1
|
+
.ui.pink.button.preview-markdown data-target=polymorphic_path(record, action: :processed_markdown) Preview markdown
|
2
|
+
#markdown-preview-modal.ui.overlay.fullscreen.modal
|
3
|
+
.header Markdown preview handlebars interpreted
|
4
|
+
pre.scrolling.content
|
5
|
+
.ui.active.inline.loader
|
6
|
+
.actions
|
7
|
+
- unless params[:action] == 'edit'
|
8
|
+
= link_to t('Edit'), [record, action: :edit], class: 'ui yellow button'
|
9
|
+
.ui.cancel.button Close
|
@@ -0,0 +1 @@
|
|
1
|
+
= link_to 'PDF', polymorphic_path(@record, action: :get_pdf), class: 'ui button'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
.ui.inverted.menu.fixed
|
2
|
+
= link_to main_app.root_path, class: 'header item'
|
3
|
+
= Rails.application.config.doc_contract.link_home_content.to_s.html_safe
|
4
|
+
- if current_user.present?
|
5
|
+
= link_to DocContract::ContractTemplate.model_name.human_plural, [DocContract::ContractTemplate], class: ['item', active_class('doc_contract/contract_templates')]
|
6
|
+
= link_to DocContract::ContractInstance.model_name.human_plural, [DocContract::ContractInstance], class: ['item', active_class('doc_contract/contract_instances')]
|
7
|
+
.right.menu
|
8
|
+
- if current_user.present?
|
9
|
+
.ui.dropdown.item
|
10
|
+
span= current_user.respond_to?(:nickname) ? current_user.nickname : current_user.email
|
11
|
+
i.dropdown.icon
|
12
|
+
.menu
|
13
|
+
= link_to main_app.destroy_user_session_path, method: :delete, class: 'item'
|
14
|
+
i.sign.out.icon
|
15
|
+
span.text= t 'user.sign_out'
|
16
|
+
- else
|
17
|
+
= link_to t('devise.sessions.new.sign_in'), main_app.new_user_session_path, class: 'item'
|
18
|
+
|
@@ -0,0 +1,6 @@
|
|
1
|
+
.ui.two.item.menu
|
2
|
+
= link_to DocContract::ContractTemplate.model_name.human_plural, [DocContract::ContractTemplate], class: ['item', active_class('doc_contract/contract_templates')]
|
3
|
+
= link_to DocContract::ContractInstance.model_name.human_plural, [DocContract::ContractInstance], class: ['item', active_class('doc_contract/contract_instances')]
|
4
|
+
- if Rails.application.config.doc_contract.show_readme_on_main_page
|
5
|
+
hr
|
6
|
+
#readme_container== readme_html
|
@@ -0,0 +1,25 @@
|
|
1
|
+
/table.ui.attached.compact.definition.table
|
2
|
+
= form_with model: @record, class: 'ui form' do |f|
|
3
|
+
table.ui.top.attached.compact.definition.table
|
4
|
+
tbody
|
5
|
+
tr
|
6
|
+
td= at :name
|
7
|
+
td: .ui.input= f.text_field :name
|
8
|
+
tr
|
9
|
+
td
|
10
|
+
= DocContract::ContractTemplate.model_name.human
|
11
|
+
= render 'definition_table_attribute_errors', attribute: :contract_template_id
|
12
|
+
td
|
13
|
+
= f.collection_select :contract_template_id, DocContract::ContractTemplate.all, :id, :name, class: 'ui input'
|
14
|
+
tr
|
15
|
+
td
|
16
|
+
= at :config_yml
|
17
|
+
= render 'definition_table_attribute_errors', attribute: :config_yml
|
18
|
+
td
|
19
|
+
= f.text_area :config_yml
|
20
|
+
#contract_config_yml_editor= raw @record.config_yml
|
21
|
+
.ui.bottom.attached.segment
|
22
|
+
= f.submit class: 'ui primary button'
|
23
|
+
- unless @record.new_record?
|
24
|
+
= render 'button-preview-markdown', record: @record
|
25
|
+
= render 'button-destroy-record', record: @record
|
@@ -0,0 +1,34 @@
|
|
1
|
+
.ui.container
|
2
|
+
= page_title :index, record_class
|
3
|
+
- if @records.any? or @q.conditions.present?
|
4
|
+
= search_form_for(@q, html: {class: 'ui form'}) do |f|
|
5
|
+
= hidden_field_tag :per_page, params[:per_page], id: 'q_per_page'
|
6
|
+
table.ui.compact.top.attached.striped.table
|
7
|
+
thead
|
8
|
+
tr
|
9
|
+
th= at :name
|
10
|
+
th= DocContract::ContractTemplate.model_name.human
|
11
|
+
th.column-filter.actions
|
12
|
+
= search_result_info @records
|
13
|
+
= search_row class: 'ui mini form' do
|
14
|
+
th= f.text_field :name_cont, placeholder: 'name contains'
|
15
|
+
th= f.text_field :contract_template_name_cont, placeholder: 'template contains'
|
16
|
+
th.column-filter.actions
|
17
|
+
button.ui.mini.primary.icon.button
|
18
|
+
i.filter.icon
|
19
|
+
= link_to polymorphic_path(record_class, reset_q: true), class: 'clear-filters-button ui mini basic yellow icon button' do
|
20
|
+
i.close.icon
|
21
|
+
tbody
|
22
|
+
- @records.each do |record|
|
23
|
+
tr
|
24
|
+
td= link_to record.name, record
|
25
|
+
td= link_to record.contract_template.name, record.contract_template
|
26
|
+
td.actions
|
27
|
+
= table_show_link record
|
28
|
+
= table_edit_link record
|
29
|
+
.ui.bottom.attached.segment
|
30
|
+
= render 'button-new-record'
|
31
|
+
= paginate @records
|
32
|
+
- else
|
33
|
+
p= t 'collection.empty', models: record_class.model_name.human_plural
|
34
|
+
= render 'button-new-record'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
.ui.container
|
2
|
+
= page_title :show, @record, back: [record_class]
|
3
|
+
table.ui.top.attached.compact.definition.table
|
4
|
+
tbody
|
5
|
+
tr
|
6
|
+
td= at :name
|
7
|
+
td= @record.name
|
8
|
+
tr
|
9
|
+
td= DocContract::ContractTemplate.model_name.human
|
10
|
+
td= link_to @record.contract_template.name, @record.contract_template
|
11
|
+
tr
|
12
|
+
td= at :config_yml
|
13
|
+
td
|
14
|
+
pre=raw @record.config_yml
|
15
|
+
tr
|
16
|
+
td Markdown tags
|
17
|
+
td
|
18
|
+
ul
|
19
|
+
- @record.contract_template.markdown.scan(/{{{?((#[a-z]+ )?[a-z]+.[a-z]*)}?}}/).uniq.each do |founds|
|
20
|
+
li= founds[0]
|
21
|
+
.ui.bottom.attached.segment
|
22
|
+
= render 'button-preview-markdown', record: @record
|
23
|
+
/= render 'button-preview-html', record: @record
|
24
|
+
= render 'button-preview-pdf', record: @record
|
25
|
+
= render 'button-edit-record', record: @record
|
@@ -0,0 +1,34 @@
|
|
1
|
+
/table.ui.attached.compact.definition.table
|
2
|
+
= form_with model: @record, class: 'ui form' do |f|
|
3
|
+
table.ui.top.attached.compact.definition.table
|
4
|
+
tbody
|
5
|
+
tr
|
6
|
+
td.collapsing= at :name
|
7
|
+
td: .ui.input= f.text_field :name
|
8
|
+
tr
|
9
|
+
td.collapsing= at :latex_template
|
10
|
+
td: .ui.input= f.select :latex_template, %w[eisvogel]
|
11
|
+
tr
|
12
|
+
td.collapsing= at :titlepage_background
|
13
|
+
td= f.select :titlepage_background, (1..11), include_blank: ' -- '
|
14
|
+
tr
|
15
|
+
td.collapsing
|
16
|
+
= at :config_yml
|
17
|
+
= render 'definition_table_attribute_errors', attribute: :config_yml
|
18
|
+
td
|
19
|
+
= f.text_area :config_yml
|
20
|
+
#contract_config_yml_editor= raw @record.config_yml
|
21
|
+
tr
|
22
|
+
td.collapsing
|
23
|
+
= at :markdown
|
24
|
+
= render 'definition_table_attribute_errors', attribute: :markdown
|
25
|
+
td
|
26
|
+
= f.text_area :markdown
|
27
|
+
#contract_template_markdown_editor= raw @record.markdown
|
28
|
+
/textarea.hidden= @record.markdown
|
29
|
+
.ui.bottom.attached.segment
|
30
|
+
= f.submit class: 'ui primary button'
|
31
|
+
- unless @record.new_record?
|
32
|
+
= render 'button-preview-markdown', record: @record
|
33
|
+
= render 'button-preview-html', record: @record
|
34
|
+
= render 'button-destroy-record', record: @record
|
@@ -0,0 +1,31 @@
|
|
1
|
+
.ui.container
|
2
|
+
= page_title :index, record_class
|
3
|
+
- if @records.any? or @q.conditions.present?
|
4
|
+
= search_form_for(@q, html: {class: 'ui form'}) do |f|
|
5
|
+
= hidden_field_tag :per_page, params[:per_page], id: 'q_per_page'
|
6
|
+
table.ui.compact.top.attached.striped.table
|
7
|
+
thead
|
8
|
+
tr
|
9
|
+
th= at :name
|
10
|
+
th.column-filter.actions
|
11
|
+
= search_result_info @records
|
12
|
+
= search_row class: 'ui mini form' do
|
13
|
+
th= f.text_field :name_cont, placeholder: 'name contains'
|
14
|
+
th.column-filter.actions
|
15
|
+
button.ui.mini.primary.icon.button
|
16
|
+
i.filter.icon
|
17
|
+
= link_to polymorphic_path(record_class, reset_q: true), class: 'clear-filters-button ui mini basic yellow icon button' do
|
18
|
+
i.close.icon
|
19
|
+
tbody
|
20
|
+
- @records.each do |record|
|
21
|
+
tr
|
22
|
+
td= link_to record.name, record
|
23
|
+
td.actions
|
24
|
+
= table_show_link record
|
25
|
+
= table_edit_link record
|
26
|
+
.ui.bottom.attached.segment
|
27
|
+
= render 'button-new-record'
|
28
|
+
= paginate @records
|
29
|
+
- else
|
30
|
+
p= t 'collection.empty', models: record_class.model_name.human_plural
|
31
|
+
= render 'button-new-record'
|
@@ -0,0 +1,28 @@
|
|
1
|
+
.ui.container
|
2
|
+
= page_title :show, @record, back: [record_class]
|
3
|
+
table.ui.top.attached.compact.definition.table
|
4
|
+
tbody
|
5
|
+
tr
|
6
|
+
td= at :name
|
7
|
+
td= @record.name
|
8
|
+
tr
|
9
|
+
td= at :latex_template
|
10
|
+
td= @record.latex_template
|
11
|
+
tr
|
12
|
+
td= at :config_yml
|
13
|
+
td
|
14
|
+
pre=raw @record.config_yml
|
15
|
+
tr
|
16
|
+
td Markdown tags
|
17
|
+
td
|
18
|
+
ul
|
19
|
+
- @record.present_handlebars_expressions.each do |expression|
|
20
|
+
li= expression
|
21
|
+
tr
|
22
|
+
td Raw preview
|
23
|
+
td: .contract-markdown-show-container=raw @record.processed_html
|
24
|
+
.ui.bottom.attached.segment
|
25
|
+
= render 'button-preview-markdown', record: @record
|
26
|
+
/= render 'button-preview-html', record: @record
|
27
|
+
= render 'button-preview-pdf', record: @record
|
28
|
+
= render 'button-edit-record', record: @record
|
@@ -0,0 +1,11 @@
|
|
1
|
+
= paginator.render do
|
2
|
+
nav.ui.pagination.menu
|
3
|
+
== first_page_tag unless current_page.first?
|
4
|
+
== prev_page_tag unless current_page.first?
|
5
|
+
- each_page do |page|
|
6
|
+
- if page.left_outer? || page.right_outer? || page.inside_window?
|
7
|
+
== page_tag page
|
8
|
+
- elsif !page.was_truncated?
|
9
|
+
== gap_tag
|
10
|
+
== next_page_tag unless current_page.last?
|
11
|
+
== last_page_tag unless current_page.last?
|
@@ -0,0 +1,23 @@
|
|
1
|
+
doctype html
|
2
|
+
html lang="en"
|
3
|
+
head
|
4
|
+
title= content_for?(:title) ? yield(:title) : 'DocContract Engine'
|
5
|
+
meta name="description" content="#{content_for?(:description) ? yield(:description) : 'Application'}"
|
6
|
+
= csrf_meta_tags
|
7
|
+
= csp_meta_tag
|
8
|
+
|
9
|
+
meta charset="utf-8"
|
10
|
+
meta content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" name="viewport"
|
11
|
+
|
12
|
+
= stylesheet_link_tag 'doc_contract/application', media: 'all'
|
13
|
+
= javascript_include_tag 'doc_contract/application'
|
14
|
+
= content_for :head
|
15
|
+
body
|
16
|
+
header= render 'navigation'
|
17
|
+
/.environment-ribbon class=Rails.env
|
18
|
+
span= Rails.env
|
19
|
+
main role="main"
|
20
|
+
= render 'messages'
|
21
|
+
= yield
|
22
|
+
hr
|
23
|
+
p DocContract Engine
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
class Name
|
3
|
+
def human_plural
|
4
|
+
# Try to find the plural name of a model. If none can be found try to find a non namespaced version and return that one
|
5
|
+
default = Proc.new do |path|
|
6
|
+
if path.present? and path['/'] # non namespaced model a/b/c => a
|
7
|
+
unnamespaced_path = path.sub(/\.(\w+)\/[\w\\]+/, '.\1')
|
8
|
+
I18n.t(unnamespaced_path, default: Proc.new{ human.pluralize })
|
9
|
+
else
|
10
|
+
human.pluralize
|
11
|
+
end
|
12
|
+
end
|
13
|
+
I18n.t("#{@klass.i18n_scope}.models.plural.#{i18n_key}", default: default )
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|