locomotivecms 4.0.3 → 4.1.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +3 -0
- data/app/api/locomotive/api/entities/content_type_entity.rb +1 -1
- data/app/api/locomotive/api/entities/site_entity.rb +1 -1
- data/app/api/locomotive/api/forms/content_type_form.rb +2 -1
- data/app/api/locomotive/api/forms/site_form.rb +1 -0
- data/app/api/locomotive/api/helpers/persistence_helper.rb +1 -1
- data/app/api/locomotive/api/resources/content_asset_resource.rb +6 -0
- data/app/api/locomotive/api/resources/content_type_resource.rb +2 -0
- data/app/api/locomotive/api/resources/current_site_resource.rb +1 -1
- data/app/api/locomotive/api/resources/site_resource.rb +3 -1
- data/app/assets/javascripts/locomotive/editor.js +7819 -100
- data/app/assets/javascripts/locomotive/views/content_entry_imports/new_view.js.coffee +12 -0
- data/app/assets/javascripts/locomotive/views/content_entry_imports/show_view.js.coffee +8 -0
- data/app/assets/stylesheets/locomotive/application.scss +2 -0
- data/app/assets/stylesheets/locomotive/editor.css +105 -12
- data/app/assets/stylesheets/locomotive/new/_dashboard.scss +20 -0
- data/app/assets/stylesheets/locomotive/old/_content_assets.scss +1 -1
- data/app/controllers/locomotive/content_assets_controller.rb +1 -1
- data/app/controllers/locomotive/content_entry_imports_controller.rb +50 -0
- data/app/helpers/locomotive/base_helper.rb +1 -1
- data/app/helpers/locomotive/shared/pages_helper.rb +1 -1
- data/app/jobs/locomotive/import_content_entry_job.rb +12 -0
- data/app/mailers/locomotive/notifications.rb +37 -11
- data/app/models/locomotive/account.rb +1 -0
- data/app/models/locomotive/concerns/asset/vignette.rb +7 -5
- data/app/models/locomotive/concerns/content_type/import.rb +124 -0
- data/app/models/locomotive/concerns/site/metafields.rb +26 -0
- data/app/models/locomotive/content_asset.rb +9 -2
- data/app/models/locomotive/content_type.rb +1 -0
- data/app/models/locomotive/section.rb +3 -1
- data/app/models/locomotive/site.rb +2 -0
- data/app/policies/locomotive/content_entry_policy.rb +1 -2
- data/app/policies/locomotive/content_type_policy.rb +3 -0
- data/app/policies/locomotive/site_policy.rb +5 -3
- data/app/services/locomotive/content_asset_service.rb +27 -4
- data/app/services/locomotive/content_entry_import_service.rb +107 -0
- data/app/services/locomotive/content_entry_service.rb +1 -1
- data/app/uploaders/locomotive/picture_uploader.rb +1 -1
- data/app/uploaders/locomotive/theme_asset_uploader.rb +1 -1
- data/app/views/locomotive/content_assets/_dropzone.html.slim +5 -1
- data/app/views/locomotive/content_entries/index.html.slim +8 -0
- data/app/views/locomotive/content_entry_imports/new.html.slim +23 -0
- data/app/views/locomotive/content_entry_imports/show.html.slim +54 -0
- data/app/views/locomotive/current_site/form/_advanced.html.slim +2 -0
- data/app/views/locomotive/page_content/edit.html.erb +1 -0
- data/config/locales/editor.en.yml +22 -0
- data/config/locales/editor.fr.yml +22 -0
- data/config/locales/en.yml +19 -0
- data/config/locales/es.yml +2 -0
- data/config/locales/flash.en.yml +6 -0
- data/config/locales/mongoid.en.yml +5 -1
- data/config/locales/mongoid.es.yml +4 -0
- data/config/locales/simple_form.en.yml +13 -1
- data/config/locales/simple_form.es.yml +2 -0
- data/config/routes.rb +3 -2
- data/lib/locomotive/configuration.rb +1 -0
- data/lib/locomotive/dragonfly.rb +6 -4
- data/lib/locomotive/version.rb +1 -1
- metadata +38 -29
@@ -0,0 +1,124 @@
|
|
1
|
+
module Locomotive
|
2
|
+
module Concerns
|
3
|
+
module ContentType
|
4
|
+
module Import
|
5
|
+
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
field :import_enabled, type: Boolean, default: false
|
10
|
+
field :raw_import_state, type: Hash, default: nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def import_state
|
14
|
+
@import_state ||= ImportState.new(raw_import_state)
|
15
|
+
end
|
16
|
+
|
17
|
+
def can_import?
|
18
|
+
import_enabled? && import_state.can_start?
|
19
|
+
end
|
20
|
+
|
21
|
+
def importing?
|
22
|
+
import_state.running?
|
23
|
+
end
|
24
|
+
|
25
|
+
def import_status
|
26
|
+
import_state.status
|
27
|
+
end
|
28
|
+
|
29
|
+
def start_import(total:)
|
30
|
+
change_import_state({
|
31
|
+
'status' => 'in_progress', 'total_rows' => total
|
32
|
+
}, true)
|
33
|
+
end
|
34
|
+
|
35
|
+
def finish_import
|
36
|
+
change_import_state({ 'status' => 'done' })
|
37
|
+
end
|
38
|
+
|
39
|
+
def cancel_import(error_message)
|
40
|
+
change_import_state({ 'status' => 'canceled', 'error' => error_message })
|
41
|
+
end
|
42
|
+
|
43
|
+
def on_imported_row(index, row_status)
|
44
|
+
change_import_state({
|
45
|
+
row_status.to_s => import_state.rows_count(row_status.to_s) + 1,
|
46
|
+
'failed_ids' => import_state.failed_rows_ids + (row_status.to_s == 'failed' ? [index] : []),
|
47
|
+
})
|
48
|
+
end
|
49
|
+
|
50
|
+
def change_import_state(attributes, clear_state = false)
|
51
|
+
new_attributes = ((clear_state ? nil : raw_import_state) || {}).merge(attributes)
|
52
|
+
update(raw_import_state: new_attributes.merge('updated_at' => Time.zone.now)).tap do
|
53
|
+
@import_state = nil # reset the state object
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class ImportState
|
58
|
+
|
59
|
+
def initialize(raw_state)
|
60
|
+
@raw_state = raw_state || { 'status' => 'ready' }
|
61
|
+
end
|
62
|
+
|
63
|
+
def can_start?
|
64
|
+
!running?
|
65
|
+
end
|
66
|
+
|
67
|
+
def running?
|
68
|
+
status == :in_progress
|
69
|
+
end
|
70
|
+
|
71
|
+
def status
|
72
|
+
@raw_state['status'].to_sym
|
73
|
+
end
|
74
|
+
|
75
|
+
def total_rows
|
76
|
+
@raw_state['total_rows']
|
77
|
+
end
|
78
|
+
|
79
|
+
def processed_rows_count
|
80
|
+
created_rows_count + updated_rows_count + failed_rows_count
|
81
|
+
end
|
82
|
+
|
83
|
+
def rows_count(topic)
|
84
|
+
@raw_state[topic] || 0
|
85
|
+
end
|
86
|
+
|
87
|
+
def created_rows_count
|
88
|
+
rows_count('created')
|
89
|
+
end
|
90
|
+
|
91
|
+
def updated_rows_count
|
92
|
+
rows_count('updated')
|
93
|
+
end
|
94
|
+
|
95
|
+
def failed_rows_count
|
96
|
+
rows_count('failed')
|
97
|
+
end
|
98
|
+
|
99
|
+
def failed_rows_ids
|
100
|
+
@raw_state['failed_ids'] || []
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class ContentEntryImport
|
108
|
+
include ActiveModel::Model
|
109
|
+
|
110
|
+
attr_accessor :file, :col_sep, :quote_char
|
111
|
+
|
112
|
+
validates_each :file do |record, attr, value|
|
113
|
+
record.errors.add attr, :blank if value.blank?
|
114
|
+
end
|
115
|
+
|
116
|
+
def options
|
117
|
+
{ col_sep: col_sep || ',', quote_char: quote_char || "\"" }
|
118
|
+
end
|
119
|
+
|
120
|
+
def file?
|
121
|
+
file.present?
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -41,6 +41,21 @@ module Locomotive
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
+
def cast_metafields(namespace)
|
45
|
+
return nil if namespace.blank? || !has_metafields?
|
46
|
+
|
47
|
+
schema = self.metafields_schema.find { |s| s['name'] == namespace }
|
48
|
+
values = self.metafields[namespace]
|
49
|
+
|
50
|
+
return nil if schema.blank? || values.blank?
|
51
|
+
|
52
|
+
values.map do |name, value|
|
53
|
+
field = schema['fields'].find { |f| f['name'] == name }
|
54
|
+
next unless field
|
55
|
+
[name, cast_metafield_value(field, value)]
|
56
|
+
end.compact.to_h
|
57
|
+
end
|
58
|
+
|
44
59
|
protected
|
45
60
|
|
46
61
|
def _metafields_schema_schema
|
@@ -75,6 +90,17 @@ module Locomotive
|
|
75
90
|
}
|
76
91
|
end
|
77
92
|
|
93
|
+
def cast_metafield_value(field, value)
|
94
|
+
case field['type']
|
95
|
+
when 'boolean'
|
96
|
+
['1', 'true', true].include?(value)
|
97
|
+
when 'integer'
|
98
|
+
Integer(value)
|
99
|
+
else
|
100
|
+
value
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
78
104
|
end
|
79
105
|
|
80
106
|
end
|
@@ -1,12 +1,13 @@
|
|
1
1
|
module Locomotive
|
2
2
|
class ContentAsset
|
3
3
|
|
4
|
-
include Locomotive::Mongoid::Document
|
4
|
+
include Locomotive::Mongoid::Document
|
5
5
|
|
6
6
|
## extensions ##
|
7
7
|
include Concerns::Asset::Types
|
8
8
|
include Concerns::Asset::Vignette
|
9
9
|
include Concerns::Asset::Checksum
|
10
|
+
include ActionView::Helpers::NumberHelper
|
10
11
|
|
11
12
|
## fields ##
|
12
13
|
field :content_type, type: String
|
@@ -20,6 +21,7 @@ module Locomotive
|
|
20
21
|
|
21
22
|
## validations ##
|
22
23
|
validates_presence_of :source
|
24
|
+
validate :maximum_file_size
|
23
25
|
|
24
26
|
## behaviours ##
|
25
27
|
mount_uploader :source, ContentAssetUploader, mount_on: :source_filename
|
@@ -27,6 +29,7 @@ module Locomotive
|
|
27
29
|
## scopes ##
|
28
30
|
scope :ordered, -> { order_by(created_at: :desc) }
|
29
31
|
scope :by_filename, ->(query) { where(source_filename: /.*#{query}.*/i) }
|
32
|
+
scope :by_exact_filename, ->(filename) { where(source_filename: filename) }
|
30
33
|
|
31
34
|
## methods ##
|
32
35
|
|
@@ -39,9 +42,13 @@ module Locomotive
|
|
39
42
|
|
40
43
|
def as_json(options = nil)
|
41
44
|
super.merge(
|
42
|
-
thumbnail_url: self.big_vignette_url
|
45
|
+
thumbnail_url: self.big_vignette_url,
|
46
|
+
size_to_human: number_to_human_size(self.size)
|
43
47
|
)
|
44
48
|
end
|
45
49
|
|
50
|
+
def maximum_file_size
|
51
|
+
errors.add(:source, :maximum_file_size_exceeded) if size_changed? && size > site.maximum_uploaded_file_size
|
52
|
+
end
|
46
53
|
end
|
47
54
|
end
|
@@ -76,7 +76,7 @@ module Locomotive
|
|
76
76
|
properties: {
|
77
77
|
id: { type: 'string' },
|
78
78
|
label: { '$ref': '#/definitions/locale_string' },
|
79
|
-
type: { enum: ['text', 'image_picker', 'checkbox', 'select', 'url', 'radio', 'content_type', 'hint', 'integer'] },
|
79
|
+
type: { enum: ['text', 'image_picker', 'asset_picker', 'checkbox', 'select', 'url', 'radio', 'content_type', 'content_entry', 'hint', 'integer'] },
|
80
80
|
default: {}
|
81
81
|
},
|
82
82
|
required: [:id, :type]
|
@@ -129,6 +129,8 @@ module Locomotive
|
|
129
129
|
presets: { type: 'array', items: { '$ref': '#/definitions/preset' } },
|
130
130
|
blocks: { type: 'array', items: { '$ref': '#/definitions/blocks' } },
|
131
131
|
max_blocks: { type: 'integer' },
|
132
|
+
blocks_display: { enum: ['list', 'tree'] },
|
133
|
+
max_blocks_depth: { type: 'integer' },
|
132
134
|
default: {
|
133
135
|
type: 'object',
|
134
136
|
properties: {
|
@@ -18,6 +18,8 @@ module Locomotive
|
|
18
18
|
## fields ##
|
19
19
|
field :name
|
20
20
|
field :robots_txt
|
21
|
+
field :maximum_uploaded_file_size, type: ::Integer, default: Locomotive.config.default_maximum_uploaded_file_size
|
22
|
+
field :overwrite_same_content_assets, type: Boolean, default: false
|
21
23
|
|
22
24
|
mount_uploader :picture, PictureUploader, validate_integrity: true
|
23
25
|
|
@@ -55,16 +55,18 @@ module Locomotive
|
|
55
55
|
|
56
56
|
def permitted_attributes
|
57
57
|
plain = [
|
58
|
-
:name, :handle, :picture, :remove_picture, :seo_title, :meta_keywords, :meta_description, :robots_txt,
|
58
|
+
:name, :handle, :picture, :remove_picture, :seo_title, :meta_keywords, :meta_description, :robots_txt, :maximum_uploaded_file_size,
|
59
59
|
:timezone_name, :timezone,
|
60
60
|
:cache_enabled, :cache_control, :cache_vary,
|
61
61
|
:asset_host, :redirect_to_first_domain, :redirect_to_https,
|
62
|
-
:private_access, :password, :prefix_default_locale, :bypass_browser_locale
|
62
|
+
:private_access, :password, :prefix_default_locale, :bypass_browser_locale,
|
63
|
+
:overwrite_same_content_assets,
|
64
|
+
:permitted_params_from_policy
|
63
65
|
]
|
64
66
|
hash = { domains: [], locales: [], url_redirections: [] }
|
65
67
|
|
66
68
|
if persisted? && !update_advanced?
|
67
|
-
plain -= [:timezone_name, :timezone, :robots_txt, :cache_enabled, :cache_control, :cache_vary, :prefix_default_locale, :bypass_browser_locale, :asset_host]
|
69
|
+
plain -= [:timezone_name, :timezone, :robots_txt, :cache_enabled, :cache_control, :cache_vary, :prefix_default_locale, :bypass_browser_locale, :asset_host, :maximum_uploaded_file_size]
|
68
70
|
hash.delete(:locales)
|
69
71
|
hash.delete(:url_redirections)
|
70
72
|
end
|
@@ -13,13 +13,15 @@ module Locomotive
|
|
13
13
|
.page(options[:page] || 1).per(options[:per_page])
|
14
14
|
end
|
15
15
|
|
16
|
+
def create(params)
|
17
|
+
create_or_update(params)
|
18
|
+
end
|
19
|
+
|
16
20
|
def bulk_create(list)
|
17
21
|
list = list.values if list.is_a?(Hash)
|
18
22
|
|
19
|
-
assets = list.map
|
20
|
-
|
21
|
-
end
|
22
|
-
|
23
|
+
assets = list.map { |params| create_or_update(params) }
|
24
|
+
|
23
25
|
valid_assets = assets.map { |a| a.errors.empty? ? { name: a.source_filename, url: a.source.url, image: a.image?, id: a._id } : nil }.compact
|
24
26
|
track_activity 'content_asset.created_bulk', parameters: { assets: valid_assets } unless valid_assets.empty?
|
25
27
|
|
@@ -32,5 +34,26 @@ module Locomotive
|
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
37
|
+
private
|
38
|
+
|
39
|
+
def create_or_update(params)
|
40
|
+
return site.content_assets.create(params) unless site.overwrite_same_content_assets?
|
41
|
+
|
42
|
+
asset = site.content_assets.build(params)
|
43
|
+
filename = asset.source.filename
|
44
|
+
|
45
|
+
existing_asset = site.content_assets.by_exact_filename(filename).first
|
46
|
+
|
47
|
+
return asset.tap { asset.save } unless existing_asset
|
48
|
+
|
49
|
+
existing_asset.tap do
|
50
|
+
# can't find out another way to replace the file when it has the same filename
|
51
|
+
existing_asset.destroy
|
52
|
+
|
53
|
+
# very important to keep the same asset id
|
54
|
+
asset._id = existing_asset._id
|
55
|
+
asset.save
|
56
|
+
end
|
57
|
+
end
|
35
58
|
end
|
36
59
|
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'csv'
|
2
|
+
|
3
|
+
module Locomotive
|
4
|
+
class ContentEntryImportService < Struct.new(:content_type)
|
5
|
+
|
6
|
+
class WrongImportFileException < StandardError; end
|
7
|
+
|
8
|
+
def async_import(file, csv_options = nil)
|
9
|
+
csv_asset = content_assets.create(source: file)
|
10
|
+
Locomotive::ImportContentEntryJob.perform_later(
|
11
|
+
content_type.id.to_s,
|
12
|
+
csv_asset.id.to_s,
|
13
|
+
csv_options
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
def import(csv_asset_id, csv_options = nil)
|
18
|
+
begin
|
19
|
+
csv = load_csv(csv_asset_id, csv_options)
|
20
|
+
rescue WrongImportFileException => e
|
21
|
+
content_type.cancel_import(e.message)
|
22
|
+
return false
|
23
|
+
end
|
24
|
+
|
25
|
+
content_type.start_import(total: csv.count)
|
26
|
+
import_rows(csv)
|
27
|
+
content_type.finish_import
|
28
|
+
|
29
|
+
content_assets.destroy_all(id: csv_asset_id)
|
30
|
+
end
|
31
|
+
|
32
|
+
def cancel(reason)
|
33
|
+
content_type.cancel_import(reason)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def import_rows(csv)
|
39
|
+
csv.each_with_index do |row, index|
|
40
|
+
entry = content_type.entries.where(_slug: row['_slug']).first || content_type.entries.build
|
41
|
+
import_row(row, index, entry)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def import_row(row, index, entry)
|
46
|
+
is_new_entry = !entry.persisted?
|
47
|
+
entry.attributes = attributes_from_row(row)
|
48
|
+
|
49
|
+
if entry.save
|
50
|
+
content_type.on_imported_row(index, is_new_entry ? :created : :updated)
|
51
|
+
else
|
52
|
+
content_type.on_imported_row(index, :failed)
|
53
|
+
end
|
54
|
+
rescue Exception => e
|
55
|
+
Rails.logger.error e.message # don't hide the exception
|
56
|
+
Rails.logger.error e.backtrace.join("\n")
|
57
|
+
content_type.on_imported_row(index, :failed)
|
58
|
+
end
|
59
|
+
|
60
|
+
def attributes_from_row(row)
|
61
|
+
attributes = {}
|
62
|
+
content_type.entries_custom_fields.each do |field|
|
63
|
+
next if row[field.name].blank?
|
64
|
+
name, value = transform_attribute(field, row[field.name])
|
65
|
+
attributes[name] = value
|
66
|
+
end
|
67
|
+
attributes
|
68
|
+
end
|
69
|
+
|
70
|
+
def load_csv(csv_asset_id, csv_options = nil)
|
71
|
+
csv_options = { headers: true, col_sep: ';', quote_char: "\"" }.merge(csv_options || {})
|
72
|
+
asset = content_assets.where(id: csv_asset_id).first
|
73
|
+
raise 'The CSV file doesn\'t exist anymore' unless asset
|
74
|
+
CSV.parse(asset.source.read, csv_options)
|
75
|
+
rescue Exception => e
|
76
|
+
raise WrongImportFileException.new e.message
|
77
|
+
end
|
78
|
+
|
79
|
+
def transform_attribute(field, value)
|
80
|
+
case field.type
|
81
|
+
when 'string'
|
82
|
+
field.name =~ /_asset_url$/ ?
|
83
|
+
[field.name, content_assets.where(source_filename: value).order_by(:created_at.desc).first&.source&.url] :
|
84
|
+
[field.name, value]
|
85
|
+
when 'belongs_to'
|
86
|
+
[field.name, fetch_entry_ids(field.class_name, value).first]
|
87
|
+
when 'many_to_many'
|
88
|
+
["#{field.name.singularize}_ids", fetch_entry_ids(field.class_name, value.split(','))]
|
89
|
+
else
|
90
|
+
[field.name, value]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def content_assets
|
95
|
+
content_type.site.content_assets
|
96
|
+
end
|
97
|
+
|
98
|
+
def fetch_entry_ids(class_name, ids_or_slugs)
|
99
|
+
return [] if ids_or_slugs.blank?
|
100
|
+
|
101
|
+
ids_or_slugs = [*ids_or_slugs]
|
102
|
+
klass = class_name.constantize
|
103
|
+
|
104
|
+
klass.by_ids_or_slugs(ids_or_slugs).pluck(:_id)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -173,7 +173,7 @@ module Locomotive
|
|
173
173
|
{ :_id.in => self.content_type.public_submission_accounts || [] },
|
174
174
|
{ :email.in => emails || [] }
|
175
175
|
).each do |account|
|
176
|
-
Locomotive::Notifications.new_content_entry(account, entry).deliver
|
176
|
+
Locomotive::Notifications.new_content_entry(site, account, entry).deliver
|
177
177
|
end
|
178
178
|
end
|
179
179
|
|
@@ -10,7 +10,7 @@ module Locomotive
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def extension_whitelist
|
13
|
-
%w(jpg jpeg gif png css js swf flv mp4 eot svg svgz ttf ttc woff woff2 otf ico htc map html cur txt xml json ogv)
|
13
|
+
%w(jpg jpeg gif png css js swf flv mp4 eot svg svgz ttf ttc woff woff2 otf ico htc map html cur txt xml json ogv webm)
|
14
14
|
end
|
15
15
|
|
16
16
|
def apply_content_type_exception(value)
|
@@ -1,9 +1,13 @@
|
|
1
1
|
.instructions
|
2
|
-
i.
|
2
|
+
i.fas.fa-cloud-upload-alt
|
3
3
|
br
|
4
4
|
= t('.instructions').html_safe
|
5
5
|
|
|
6
6
|
= link_to t('.browse'), '#', class: 'upload'
|
7
|
+
br
|
8
|
+
br
|
9
|
+
i
|
10
|
+
= t('.maximum_file_size', maximum: number_to_human_size(current_site.maximum_uploaded_file_size)).html_safe
|
7
11
|
|
8
12
|
= form_tag('', class: 'hide') do
|
9
13
|
= file_field_tag :source, multiple: true
|
@@ -41,6 +41,14 @@
|
|
41
41
|
|
|
42
42
|
= t('.new')
|
43
43
|
|
44
|
+
- if @content_type.import_enabled?
|
45
|
+
|
|
46
|
+
|
|
47
|
+
= link_to new_content_entry_import_path(current_site, @content_type.slug), class: 'btn btn-primary btn-sm' do
|
48
|
+
i.fa.fa-file-import
|
49
|
+
|
|
50
|
+
= t('.import')
|
51
|
+
|
44
52
|
- if @content_type.groupable?
|
45
53
|
.row.list-groups
|
46
54
|
.nav-container.nav-container--scroll
|
@@ -0,0 +1,23 @@
|
|
1
|
+
- title t('.title', type: @content_type.name.capitalize)
|
2
|
+
|
3
|
+
- content_for :actions do
|
4
|
+
.main-action
|
5
|
+
= link_to content_entry_import_path(current_site, @content_type.slug), class: 'btn btn-primary btn-sm' do
|
6
|
+
i.fas.fa-tachometer-alt
|
7
|
+
|
|
8
|
+
= t('.show')
|
9
|
+
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
13
|
+
= link_to t(:back, scope: 'locomotive.content_entries.shared').html_safe, content_entries_path(current_site, @content_type.slug), class: 'btn btn-sm btn-default'
|
14
|
+
|
15
|
+
= locomotive_form_for @import, url: content_entry_import_path(current_site, @content_type.slug) do |f|
|
16
|
+
|
17
|
+
= f.inputs :information do
|
18
|
+
= f.input :file, as: :file
|
19
|
+
|
20
|
+
= f.input :col_sep
|
21
|
+
= f.input :quote_char
|
22
|
+
|
23
|
+
= f.actions back_url: content_entries_path(current_site, @content_type.slug), use_stored_location: true
|
@@ -0,0 +1,54 @@
|
|
1
|
+
- title t('.title', type: @content_type.name.capitalize)
|
2
|
+
|
3
|
+
- content_for :actions do
|
4
|
+
.main-action
|
5
|
+
- if @content_type.importing?
|
6
|
+
= link_to content_entry_import_path(current_site, @content_type.slug), class: 'btn btn-primary btn-sm' do
|
7
|
+
i.fas.fa-sync
|
8
|
+
|
|
9
|
+
= t('.refresh')
|
10
|
+
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
14
|
+
= link_to content_entry_import_path(current_site, @content_type.slug), class: 'btn btn-danger btn-sm', method: :delete, data: { confirm: t('locomotive.messages.confirm') } do
|
15
|
+
i.far.fa-trash-alt
|
16
|
+
|
|
17
|
+
= t('.cancel')
|
18
|
+
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
22
|
+
= link_to t(:back, scope: 'locomotive.content_entries.shared').html_safe, content_entries_path(current_site, @content_type.slug), class: 'btn btn-sm btn-default'
|
23
|
+
|
24
|
+
br
|
25
|
+
br
|
26
|
+
br
|
27
|
+
br
|
28
|
+
|
29
|
+
.row
|
30
|
+
.col-md-3
|
31
|
+
.metric
|
32
|
+
h2= t('.report.status')
|
33
|
+
h3= t(".statuses.#{@content_type.import_status}")
|
34
|
+
|
35
|
+
.col-md-3
|
36
|
+
.metric
|
37
|
+
h2= t('.report.created_rows')
|
38
|
+
h3= @content_type.import_state.created_rows_count
|
39
|
+
|
40
|
+
.col-md-3
|
41
|
+
.metric
|
42
|
+
h2= t('.report.updated_rows')
|
43
|
+
h3= @content_type.import_state.updated_rows_count
|
44
|
+
|
45
|
+
.col-md-3
|
46
|
+
.metric
|
47
|
+
h2= t('.report.failed_rows')
|
48
|
+
h3= @content_type.import_state.failed_rows_count
|
49
|
+
|
50
|
+
br
|
51
|
+
br
|
52
|
+
|
53
|
+
pre
|
54
|
+
code= @content_type.raw_import_state
|
@@ -9,6 +9,8 @@
|
|
9
9
|
|
10
10
|
= f.input :robots_txt, as: :code, wrapper_html: { class: 'small' }
|
11
11
|
|
12
|
+
= f.input :maximum_uploaded_file_size
|
13
|
+
|
12
14
|
= f.inputs :cache_enabled do
|
13
15
|
= f.input :cache_enabled, as: :toggle
|
14
16
|
= f.input :cache_control, as: :string, wrapper_html: { class: "#{'hide' unless f.object.cache_enabled?}" }
|
@@ -35,9 +35,19 @@ en:
|
|
35
35
|
remove_button: "Remove"
|
36
36
|
crop_button: "Crop"
|
37
37
|
|
38
|
+
asset_picker:
|
39
|
+
select_button: "Select"
|
40
|
+
change_button: "Change"
|
41
|
+
remove_button: "Remove"
|
42
|
+
|
38
43
|
content_type:
|
39
44
|
show: "Show"
|
40
45
|
|
46
|
+
content_entry:
|
47
|
+
select_button: "Select"
|
48
|
+
change_button: "Change"
|
49
|
+
remove_button: "Remove"
|
50
|
+
|
41
51
|
views:
|
42
52
|
action_bar:
|
43
53
|
header:
|
@@ -54,6 +64,12 @@ en:
|
|
54
64
|
seo: "SEO"
|
55
65
|
|
56
66
|
pickers:
|
67
|
+
assets:
|
68
|
+
title: "Assets"
|
69
|
+
loading: "Loading the assets. Please wait!"
|
70
|
+
add: "+ add"
|
71
|
+
upload_in_progress: "Uploading..."
|
72
|
+
search_placeholder: "Name of your asset"
|
57
73
|
images:
|
58
74
|
title: "Images"
|
59
75
|
loading: "Loading the images. Please wait!"
|
@@ -82,9 +98,15 @@ en:
|
|
82
98
|
email:
|
83
99
|
label: Email address
|
84
100
|
placeholder: "name@example.com"
|
101
|
+
content_entry:
|
102
|
+
title: "Pick an entry"
|
103
|
+
input:
|
104
|
+
label: Instance
|
105
|
+
placeholder: Type the label of the instance
|
85
106
|
|
86
107
|
preview:
|
87
108
|
view: "View"
|
109
|
+
errorMessage: "The page couldn't be loaded. Please contact the developer of the site."
|
88
110
|
|
89
111
|
sections:
|
90
112
|
edit:
|