avo 1.3.1 → 1.3.5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of avo might be problematic. Click here for more details.

Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +2 -2
  3. data/app/components/avo/common/key_value_component.html.erb +53 -0
  4. data/app/components/avo/common/key_value_component.rb +11 -0
  5. data/app/components/avo/edit/fields/key_value_field_component.html.erb +3 -0
  6. data/app/components/avo/edit/fields/key_value_field_component.rb +4 -0
  7. data/app/components/avo/edit/fields/trix_field_component.html.erb +1 -1
  8. data/app/components/avo/show/fields/key_value_field_component.html.erb +3 -0
  9. data/app/components/avo/show/fields/key_value_field_component.rb +4 -0
  10. data/app/helpers/avo/application_helper.rb +1 -1
  11. data/app/packs/entrypoints/application.js +14 -10
  12. data/app/packs/js/controllers/fields/code_field_controller.js +1 -0
  13. data/app/packs/js/controllers/fields/key_value_controller.js +137 -0
  14. data/lib/avo.rb +1 -1
  15. data/lib/avo/fields/key_value_field.rb +24 -1
  16. data/lib/avo/version.rb +1 -1
  17. data/lib/generators/avo/action_generator.rb +1 -1
  18. data/lib/generators/avo/locales_generator.rb +2 -2
  19. data/lib/generators/avo/templates/action.tt +5 -9
  20. data/lib/generators/avo/templates/locales/avo.en.yml +1 -0
  21. data/lib/generators/avo/templates/locales/avo.nb-NO.yml +81 -0
  22. data/lib/generators/avo/templates/locales/avo.pt-BR.yml +82 -0
  23. data/lib/generators/avo/templates/locales/avo.ro.yml +70 -0
  24. data/public/avo-packs/css/{application-af3e670d.css → application-0b91a712.css} +85 -18
  25. data/public/avo-packs/css/application-0b91a712.css.br +0 -0
  26. data/public/avo-packs/css/application-0b91a712.css.gz +0 -0
  27. data/public/avo-packs/css/application-0b91a712.css.map +1 -0
  28. data/public/avo-packs/css/application-0b91a712.css.map.br +0 -0
  29. data/public/avo-packs/css/application-0b91a712.css.map.gz +0 -0
  30. data/public/avo-packs/js/application-c2a8a64ca8f5d2805d79.js +26 -0
  31. data/public/avo-packs/js/{application-801f1297670a4c6df1b6.js.LICENSE.txt → application-c2a8a64ca8f5d2805d79.js.LICENSE.txt} +0 -0
  32. data/public/avo-packs/js/application-c2a8a64ca8f5d2805d79.js.br +0 -0
  33. data/public/avo-packs/js/application-c2a8a64ca8f5d2805d79.js.gz +0 -0
  34. data/public/avo-packs/js/application-c2a8a64ca8f5d2805d79.js.map +1 -0
  35. data/public/avo-packs/js/application-c2a8a64ca8f5d2805d79.js.map.br +0 -0
  36. data/public/avo-packs/js/application-c2a8a64ca8f5d2805d79.js.map.gz +0 -0
  37. data/public/avo-packs/manifest.json +15 -15
  38. metadata +25 -15
  39. data/public/avo-packs/css/application-af3e670d.css.br +0 -0
  40. data/public/avo-packs/css/application-af3e670d.css.gz +0 -0
  41. data/public/avo-packs/css/application-af3e670d.css.map +0 -1
  42. data/public/avo-packs/css/application-af3e670d.css.map.br +0 -0
  43. data/public/avo-packs/css/application-af3e670d.css.map.gz +0 -0
  44. data/public/avo-packs/js/application-801f1297670a4c6df1b6.js +0 -26
  45. data/public/avo-packs/js/application-801f1297670a4c6df1b6.js.br +0 -0
  46. data/public/avo-packs/js/application-801f1297670a4c6df1b6.js.gz +0 -0
  47. data/public/avo-packs/js/application-801f1297670a4c6df1b6.js.map +0 -1
  48. data/public/avo-packs/js/application-801f1297670a4c6df1b6.js.map.br +0 -0
  49. data/public/avo-packs/js/application-801f1297670a4c6df1b6.js.map.gz +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92c5c1023654c2cd64f3d1873aa30288a3ea03e84c274b73b19c33cecbae0c90
4
- data.tar.gz: 669c555d15547f2e2003d0a58020841d171f3593455f6e21dff6303b68a63649
3
+ metadata.gz: f31ebc9caf8e281af2cb0e8ce4d0423ab4852f3475843af1d632e795930f5df0
4
+ data.tar.gz: 8117f6fca30c9f9f90ff61f5c7bdeb2908cb13fd731e3168c6678b5c4427f0a9
5
5
  SHA512:
6
- metadata.gz: '09409a21957aced0968d00c5486051369ed108ffa57b17745822c71b00fe0b49c5ede3ce9f1d617b3e7914d44dab5e4bec3ea27df098af8b77b1d0aec256b119'
7
- data.tar.gz: 152a5e71bf27c50d4448548994b4efeb794d86bc28a2941c806c2e9cb2c1fb55409ed8f625fba298199f89a054909d3cdbbc93ef477d94b86a28e7dbc7944eab
6
+ metadata.gz: 4d1deeabbc3538d4094312e9c08b384355882e55d1124976981e4e8f5356ed8d032f6a595261065a9fc567ca7529e639926f627e72231baf409709b2d19626d0
7
+ data.tar.gz: 036e731952aaf067ba2397fefa5d79a714332f39e7779a6586bee49e247c17ceb80f4e4226f4fa4cbb73be45c8d4573b09e5d4d7df29e921df1a767b980aca1e
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- avo (1.3.1)
4
+ avo (1.3.5)
5
5
  active_link_to
6
6
  addressable
7
7
  breadcrumbs_on_rails
@@ -187,7 +187,7 @@ GEM
187
187
  nokogiri (1.11.3-x86_64-linux)
188
188
  racc (~> 1.4)
189
189
  orm_adapter (0.5.0)
190
- pagy (3.12.0)
190
+ pagy (3.13.0)
191
191
  parallel (1.20.1)
192
192
  parser (3.0.0.0)
193
193
  ast (~> 2.4.1)
@@ -0,0 +1,53 @@
1
+ <div class="w-full shadow-lg rounded-lg overflow-hidden"
2
+ data-controller="key-value"
3
+ data-key-value-target="controller"
4
+ data-options="<%= @field.options.to_json %>"
5
+ data-input-classes="<%= input_classes %>"
6
+ data-editable="<%= @view.in?([:edit, :create]) %>"
7
+ >
8
+ <div class="w-full flex flex-col">
9
+ <div class="flex w-full">
10
+ <div class="flex w-full bg-gray-800 shadow overflow-hidden">
11
+ <div class="w-1/2 py-3 px-3 uppercase font-semibold text-xs text-white border-gray-600 border-r">
12
+ <%= @field.key_label %>
13
+ </div>
14
+ <div class="w-1/2 py-3 px-3 uppercase font-semibold text-xs text-white">
15
+ <%= @field.value_label %>
16
+ </div>
17
+ <% if @view.in?([:edit, :create]) %>
18
+ <div class="flex items-center justify-center p-2 px-3 border-l border-gray-600">
19
+ <a href="javascript:void(0);"
20
+ title="<%= @field.action_text %>"
21
+ data-tippy="tooltip"
22
+ data-button="add-row"
23
+ data-action="click->key-value#addRow"
24
+ <% if @field.disable_adding_rows %>
25
+ class="cursor-not-allowed"
26
+ <% end %>
27
+ >
28
+ <%= svg 'plus-circle', class: 'text-gray-400 h-5 hover:text-gray-500' %>
29
+ </a>
30
+ </div>
31
+ <% end %>
32
+ </div>
33
+ </div>
34
+ <div data-key-value-target="rows"></div>
35
+ </div>
36
+ <% if @form.present? %>
37
+ <%= @form.text_area @field.id,
38
+ value: @field.parsed_value,
39
+ class: 'hidden',
40
+ placeholder: @field.placeholder,
41
+ 'data-key-value-target': 'input',
42
+ 'data-view': :edit
43
+ %>
44
+ <% else %>
45
+ <%= text_area_tag @field.id,
46
+ @field.parsed_value,
47
+ class: 'hidden',
48
+ placeholder: @field.placeholder,
49
+ 'data-key-value-target': 'input',
50
+ 'data-view': :edit
51
+ %>
52
+ <% end %>
53
+ </div>
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avo::Common::KeyValueComponent < ViewComponent::Base
4
+ include Avo::ApplicationHelper
5
+
6
+ def initialize(field:, form: nil, view: :show)
7
+ @field = field
8
+ @form = form
9
+ @view = view
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ <%= edit_field_wrapper field: @field, index: @index, form: @form, resource: @resource, displayed_in_modal: @displayed_in_modal, full_width: true do %>
2
+ <%= render Avo::Common::KeyValueComponent.new field: @field, form: @form, view: :edit %>
3
+ <% end %>
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avo::Edit::Fields::KeyValueFieldComponent < Avo::Edit::Fields::FieldComponent
4
+ end
@@ -1,6 +1,6 @@
1
1
  <%= edit_field_wrapper field: @field, index: @index, form: @form, resource: @resource, displayed_in_modal: @displayed_in_modal do %>
2
2
  <% trix_id = "trix_#{@resource.name.underscore}_#{@field.id}" %>
3
- <trix-editor input="<%= trix_id %>" value="<%= @field.value %>" placeholder="<%= @field.placeholder %>"><%== @field.value %></trix-editor>
3
+ <trix-editor input="<%= trix_id %>" placeholder="<%= @field.placeholder %>"><%== @field.value %></trix-editor>
4
4
  <%= @form.text_area @field.id,
5
5
  id: trix_id,
6
6
  class: helpers.input_classes('w-full hidden', has_error: (@resource.model.present? and @resource.model.errors.include?(@field.id))),
@@ -0,0 +1,3 @@
1
+ <%= show_field_wrapper field: @field, index: @index, full_width: true do %>
2
+ <%= render Avo::Common::KeyValueComponent.new field: @field, view: :show %>
3
+ <% end %>
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avo::Show::Fields::KeyValueFieldComponent < Avo::Show::Fields::FieldComponent
4
+ end
@@ -4,7 +4,7 @@ module Avo
4
4
  include ::Pagy::Frontend
5
5
 
6
6
  def current_webpacker_instance
7
- return Avo.webpacker if Avo::IN_DEVELOPMENT || Rails.env.test?
7
+ return Avo.webpacker if Avo::IN_DEVELOPMENT
8
8
 
9
9
  super
10
10
  end
@@ -19,6 +19,19 @@ window.Turbolinks = Turbo
19
19
 
20
20
  Mousetrap.bind('r r r', () => Turbo.visit(window.location.href, { action: 'replace' }))
21
21
 
22
+ function initTippy() {
23
+ tippy('[data-tippy="tooltip"]', {
24
+ theme: 'light',
25
+ content(reference) {
26
+ const title = reference.getAttribute('title')
27
+ reference.removeAttribute('title')
28
+
29
+ return title
30
+ },
31
+ })
32
+ }
33
+ window.initTippy = initTippy
34
+
22
35
  const application = Application.start()
23
36
 
24
37
  const context = require.context('./../js/controllers', true, /\.js$/)
@@ -29,16 +42,7 @@ application.load(definitionsFromContext(fieldsContext))
29
42
 
30
43
  document.addEventListener('turbo:load', () => {
31
44
  document.body.classList.remove('turbo-loading')
32
-
33
- tippy('[data-tippy="tooltip"]', {
34
- theme: 'light',
35
- content(reference) {
36
- const title = reference.getAttribute('title')
37
- reference.removeAttribute('title')
38
-
39
- return title
40
- },
41
- })
45
+ initTippy()
42
46
  })
43
47
  document.addEventListener('turbo:visit', () => document.body.classList.add('turbo-loading'))
44
48
  document.addEventListener('turbo:submit-start', () => document.body.classList.add('turbo-loading'))
@@ -12,6 +12,7 @@ import 'codemirror/mode/shell/shell'
12
12
  import 'codemirror/mode/sql/sql'
13
13
  import 'codemirror/mode/vue/vue'
14
14
  import 'codemirror/mode/xml/xml'
15
+ import 'codemirror/mode/yaml/yaml'
15
16
 
16
17
  import { Controller } from 'stimulus'
17
18
  import { castBoolean } from '@/js/helpers/cast_boolean'
@@ -0,0 +1,137 @@
1
+ /* eslint-disable max-len */
2
+ import { Controller } from 'stimulus'
3
+ import { castBoolean } from '@/js/helpers/cast_boolean'
4
+
5
+ export default class extends Controller {
6
+ static targets = ['input', 'controller', 'rows']
7
+
8
+ fieldValue = []
9
+
10
+ options = {}
11
+
12
+ get keyInputDisabled() {
13
+ return !this.options.editable || this.options.disable_editing_keys
14
+ }
15
+
16
+ get valueInputDisabled() {
17
+ return !this.options.editable
18
+ }
19
+
20
+ connect() {
21
+ this.setOptions()
22
+
23
+ try {
24
+ const objectValue = JSON.parse(this.inputTarget.value)
25
+ Object.keys(objectValue).forEach((key) => this.fieldValue.push([key, objectValue[key]]))
26
+ } catch (error) {
27
+ this.fieldValue = []
28
+ }
29
+
30
+ this.updateKeyValueComponent()
31
+ }
32
+
33
+ addRow() {
34
+ if (this.options.disable_adding_rows || !this.options.editable) return
35
+ this.fieldValue.push(['', ''])
36
+ this.updateKeyValueComponent()
37
+ this.focusLastRow()
38
+ }
39
+
40
+ deleteRow(event) {
41
+ if (this.options.disable_deleting_rows || !this.options.editable) return
42
+ const { index } = event.target.dataset
43
+ this.fieldValue.splice(index, 1)
44
+ this.updateTextareaInput()
45
+ this.updateKeyValueComponent()
46
+ }
47
+
48
+ focusLastRow() {
49
+ return this.rowsTarget.querySelector('.flex.key-value-row:last-child .key-value-input-key').focus()
50
+ }
51
+
52
+ valueFieldUpdated(event) {
53
+ const { value } = event.target
54
+ const { index } = event.target.dataset
55
+ this.fieldValue[index][1] = value
56
+
57
+ this.updateTextareaInput()
58
+ }
59
+
60
+ keyFieldUpdated(event) {
61
+ const { value } = event.target
62
+ const { index } = event.target.dataset
63
+ this.fieldValue[index][0] = value
64
+
65
+ this.updateTextareaInput()
66
+ }
67
+
68
+ updateTextareaInput() {
69
+ if (!this.hasInputTarget) return
70
+ let result = {}
71
+ if (this.fieldValue && this.fieldValue.length > 0) {
72
+ result = Object.assign(...this.fieldValue.map(([key, val]) => ({ [key]: val })))
73
+ }
74
+ this.inputTarget.innerText = JSON.stringify(result)
75
+ }
76
+
77
+ updateKeyValueComponent() {
78
+ let result = ''
79
+ let index = 0
80
+ this.fieldValue.forEach((row) => {
81
+ const [key, value] = row
82
+ result += this.interpolatedRow(key, value, index)
83
+ index++
84
+ })
85
+ this.rowsTarget.innerHTML = result
86
+ window.initTippy()
87
+ }
88
+
89
+ interpolatedRow(key, value, index) {
90
+ let result = `<div class="flex key-value-row">
91
+ ${this.inputField('key', index, key, value)}
92
+ ${this.inputField('value', index, key, value)}`
93
+ if (this.options.editable) {
94
+ result += `<a
95
+ href="javascript:void(0);"
96
+ data-index="${index}"
97
+ data-action="click->key-value#deleteRow"
98
+ title="${this.options.delete_text}"
99
+ data-tippy="tooltip"
100
+ data-button="delete-row"
101
+ tabindex="-1"
102
+ ${this.options.disable_deleting_rows ? "disabled='disabled'" : ''}
103
+ class="flex items-center justify-center p-2 px-3 border-none ${this.options.disable_deleting_rows ? 'cursor-not-allowed' : ''}"
104
+ ><svg class="pointer-events-none text-gray-500 h-5 hover:text-gray-500" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" stroke="currentColor"><path d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path></svg></a>`
105
+ }
106
+ result += '</div>'
107
+
108
+ return result
109
+ }
110
+
111
+ inputField(id = 'key', index, key, value) {
112
+ return `<input
113
+ class="${this.options.inputClasses} !rounded-none border-gray-600 border-r border-l-0 border-b-0 border-t-0 focus:border-gray-300 w-1/2 focus:outline-none outline-none key-value-input-${id}"
114
+ data-action="input->key-value#${id}FieldUpdated"
115
+ placeholder="${this.options[`${id}_label`]}"
116
+ data-index="${index}"
117
+ ${this[`${id}InputDisabled`] ? "disabled='disabled'" : ''}
118
+ value="${id === 'key' ? key : value}"
119
+ autofocus
120
+ />`
121
+ }
122
+
123
+ setOptions() {
124
+ let fieldOptions
125
+
126
+ try {
127
+ fieldOptions = JSON.parse(this.controllerTarget.dataset.options)
128
+ } catch (error) {
129
+ fieldOptions = {}
130
+ }
131
+ this.options = {
132
+ ...fieldOptions,
133
+ inputClasses: this.controllerTarget.dataset.inputClasses,
134
+ editable: castBoolean(this.controllerTarget.dataset.editable),
135
+ }
136
+ }
137
+ }
data/lib/avo.rb CHANGED
@@ -27,7 +27,7 @@ module Avo
27
27
  root_path: ROOT_PATH,
28
28
  public_output_dir: "avo-packs",
29
29
  cache_manifest: Rails.env.production?,
30
- fallback_to_webpacker: -> { Avo::IN_DEVELOPMENT || Rails.env.test?}
30
+ fallback_to_webpacker: -> { Avo::IN_DEVELOPMENT }
31
31
  )
32
32
  end
33
33
  end
@@ -3,6 +3,11 @@ require "json"
3
3
  module Avo
4
4
  module Fields
5
5
  class KeyValueField < BaseField
6
+ attr_reader :key_label
7
+ attr_reader :value_label
8
+ attr_reader :action_text
9
+ attr_reader :disable_adding_rows
10
+
6
11
  def initialize(name, **args, &block)
7
12
  @defaults = {
8
13
  partial_name: "key-value-field"
@@ -33,7 +38,13 @@ module Avo
33
38
  [:"#{id}", "#{id}": {}]
34
39
  end
35
40
 
36
- def hydrate_field(fields, model, resource, view)
41
+ def parsed_value
42
+ value.to_json
43
+ rescue
44
+ {}
45
+ end
46
+
47
+ def options
37
48
  {
38
49
  key_label: @key_label,
39
50
  value_label: @value_label,
@@ -44,6 +55,18 @@ module Avo
44
55
  disable_deleting_rows: @disable_deleting_rows
45
56
  }
46
57
  end
58
+
59
+ def fill_field(model, key, value)
60
+ begin
61
+ new_value = JSON.parse(value)
62
+ rescue
63
+ new_value = {}
64
+ end
65
+
66
+ model[key] = new_value
67
+
68
+ model
69
+ end
47
70
  end
48
71
  end
49
72
  end
data/lib/avo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Avo
2
- VERSION = "1.3.1"
2
+ VERSION = "1.3.5"
3
3
  end
@@ -7,7 +7,7 @@ module Generators
7
7
  namespace "avo:action"
8
8
 
9
9
  def create_resource_file
10
- template "action.rb", "app/avo/actions/#{singular_name}.rb"
10
+ template "action.tt", "app/avo/actions/#{singular_name}.rb"
11
11
  end
12
12
  end
13
13
  end
@@ -6,10 +6,10 @@ module Generators
6
6
  source_root File.expand_path("templates", __dir__)
7
7
 
8
8
  namespace "avo:locales"
9
- desc "Creates an Avo initializer adds the route to the routes file."
9
+ desc "Add Avo locale files to your project."
10
10
 
11
11
  def create_files
12
- template "locales/avo.en.yml", "config/locales/avo.en.yml"
12
+ directory File.join(__dir__, "templates", "locales"), "config/locales"
13
13
  end
14
14
  end
15
15
  end
@@ -1,13 +1,9 @@
1
- module Avo
2
- module Actions
3
- class <%= class_name.camelize %> < Action
4
- self.name = '<%= name.underscore.humanize %>'
1
+ class <%= class_name.camelize %> < Avo::BaseAction
2
+ self.name = '<%= name.underscore.humanize %>'
5
3
 
6
- def handle(models:, fields:)
7
- models.each do |model|
8
- # Do something with your models.
9
- end
10
- end
4
+ def handle(models:, fields:)
5
+ models.each do |model|
6
+ # Do something with your models.
11
7
  end
12
8
  end
13
9
  end
@@ -59,6 +59,7 @@ en:
59
59
  and_x_other_resources: 'and %{count} other resources'
60
60
  go_back: 'Go back'
61
61
  home: 'Home'
62
+ new: 'new'
62
63
  attach_item: 'Attach %{item}'
63
64
  choose_item: 'Choose %{item}'
64
65
  create_new_item: 'Create new %{item}'
@@ -0,0 +1,81 @@
1
+ nb:
2
+ avo:
3
+ dashboard: 'Dashboard'
4
+ choose_a_country: 'Velg et land'
5
+ choose_an_option: 'Velg et alternativ'
6
+ are_you_sure_you_want_to_run_this_option: 'Er du sikker?'
7
+ are_you_sure_detach_item: 'Er du sikker på at du vil koble fra %{item}.'
8
+ run: 'Kjør'
9
+ cancel: 'Avslutt'
10
+ action_ran_successfully: 'Suksess!'
11
+ resource_details: "%{item} detaljer: %{title}"
12
+ update_item: 'Oppdatert %{item}: %{title}'
13
+ unauthorized: 'Ikke autorisert'
14
+ attachment_class_attached: '%{attachment_class} lagt til.'
15
+ attachment_class_detached: '%{attachment_class} fjernet.'
16
+ resource_updated: 'Ressurs oppdatert'
17
+ resource_created: 'Ressurs generert'
18
+ resource_destroyed: 'Ressurs slettet'
19
+ switch_to_view: "Bytt til %{view_type} vis"
20
+ click_to_reveal_filters: "Vis filter"
21
+ attachment_destroyed: 'Vedlett slettet'
22
+ failed_to_find_attachment: 'Fant ikke vedlegg'
23
+ you_missed_something_check_form: 'Her mangler du noe. Vennligst sjekk skjemaet.'
24
+ remove_selection: 'Fjern valg'
25
+ select_item: 'Velg'
26
+ delete_file: 'Slett fil'
27
+ delete: 'slett'
28
+ delete_item: 'Slett %{item}'
29
+ download_item: 'Last ned %{item}'
30
+ download_file: 'Last ned fil'
31
+ download: 'Last ned'
32
+ view: 'Vis'
33
+ view_item: 'vis %{item}'
34
+ edit: 'endre'
35
+ edit_item: 'endre %{item}'
36
+ detach_item: 'koble fra %{item}'
37
+ number_of_items:
38
+ zero: 'ingen %{item}'
39
+ one: 'en %{item}'
40
+ other: '%{count} %{item}'
41
+ are_you_sure: 'Er du sikker?'
42
+ filters: 'Filter'
43
+ per_page: 'Per side'
44
+ more: 'Mer'
45
+ attach: 'Legg til'
46
+ cancel: 'Avslutt'
47
+ save: 'Lagre'
48
+ attach_and_attach_another: 'Legg til & Legg til ny'
49
+ hide_content: 'Skjul innhold'
50
+ show_content: 'Vis innhold'
51
+ no_related_item_found: 'Ingen relaterte %{item} funnet'
52
+ no_item_found: 'Ingen %{item} funnet'
53
+ loading: 'Laster'
54
+ confirm: 'Bekreft'
55
+ actions: 'Handlinger'
56
+ resources: 'Ressurser'
57
+ oops_nothing_found: 'Oops! Ingen ting funnet...'
58
+ type_to_search: 'Søk.'
59
+ and_x_other_resources: 'og %{count} andre ressurser'
60
+ go_back: 'Gå tilbake'
61
+ home: 'Hjem'
62
+ attach_item: 'Legg til %{item}'
63
+ choose_item: 'Velge %{item}'
64
+ create_new_item: 'Lag ny %{item}'
65
+ table_view: 'Tabell visning'
66
+ grid_view: 'Grid visning'
67
+ next_page: 'Neste side'
68
+ prev_page: 'Forrige side'
69
+ list_is_empty: 'Listen er tom'
70
+ field_translations:
71
+ file:
72
+ zero: 'filer'
73
+ one: 'fil'
74
+ other: 'filer'
75
+ resource_translations:
76
+ user:
77
+ zero: 'brukere'
78
+ one: 'bruker'
79
+ other: 'brukere'
80
+ reset_filters: 'Nullstill filter'
81
+ not_authorized: 'Du er ikke autorisert til å gjøre denne handlingen.'