foreman_resource_quota 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/LICENSE +619 -0
- data/README.md +51 -0
- data/Rakefile +49 -0
- data/app/controllers/concerns/foreman/controller/parameters/resource_quota.rb +28 -0
- data/app/controllers/foreman_resource_quota/api/v2/resource_quotas_controller.rb +96 -0
- data/app/controllers/foreman_resource_quota/application_controller.rb +9 -0
- data/app/controllers/foreman_resource_quota/resource_quotas_controller.rb +50 -0
- data/app/helpers/foreman_resource_quota/hosts_helper.rb +18 -0
- data/app/helpers/foreman_resource_quota/resource_quota_helper.rb +107 -0
- data/app/models/concerns/foreman_resource_quota/host_managed_extensions.rb +115 -0
- data/app/models/concerns/foreman_resource_quota/user_extensions.rb +15 -0
- data/app/models/concerns/foreman_resource_quota/usergroup_extensions.rb +14 -0
- data/app/models/foreman_resource_quota/resource_quota.rb +83 -0
- data/app/models/foreman_resource_quota/resource_quota_user.rb +10 -0
- data/app/models/foreman_resource_quota/resource_quota_usergroup.rb +10 -0
- data/app/services/foreman_resource_quota/resource_origin.rb +97 -0
- data/app/services/foreman_resource_quota/resource_origins/compute_attributes_origin.rb +64 -0
- data/app/services/foreman_resource_quota/resource_origins/compute_resource_origin.rb +82 -0
- data/app/services/foreman_resource_quota/resource_origins/facts_origin.rb +68 -0
- data/app/services/foreman_resource_quota/resource_origins/vm_attributes_origin.rb +40 -0
- data/app/views/foreman_resource_quota/api/v2/hosts/resource_quota.json.rabl +3 -0
- data/app/views/foreman_resource_quota/api/v2/resource_quotas/base.json.rabl +6 -0
- data/app/views/foreman_resource_quota/api/v2/resource_quotas/create.json.rabl +5 -0
- data/app/views/foreman_resource_quota/api/v2/resource_quotas/hosts.json.rabl +7 -0
- data/app/views/foreman_resource_quota/api/v2/resource_quotas/index.json.rabl +5 -0
- data/app/views/foreman_resource_quota/api/v2/resource_quotas/main.json.rabl +7 -0
- data/app/views/foreman_resource_quota/api/v2/resource_quotas/show.json.rabl +5 -0
- data/app/views/foreman_resource_quota/api/v2/resource_quotas/update.json.rabl +5 -0
- data/app/views/foreman_resource_quota/api/v2/resource_quotas/usergroups.json.rabl +7 -0
- data/app/views/foreman_resource_quota/api/v2/resource_quotas/users.json.rabl +7 -0
- data/app/views/foreman_resource_quota/api/v2/resource_quotas/utilization.json.rabl +7 -0
- data/app/views/foreman_resource_quota/api/v2/usergroups/resource_quota.json.rabl +3 -0
- data/app/views/foreman_resource_quota/api/v2/users/resource_quota.json.rabl +3 -0
- data/app/views/foreman_resource_quota/resource_quotas/_form.html.erb +21 -0
- data/app/views/foreman_resource_quota/resource_quotas/edit.html.erb +12 -0
- data/app/views/foreman_resource_quota/resource_quotas/index.html.erb +55 -0
- data/app/views/foreman_resource_quota/resource_quotas/new.html.erb +10 -0
- data/app/views/foreman_resource_quota/resource_quotas/welcome.html.erb +10 -0
- data/app/views/hosts/_form_quota_fields.html.erb +4 -0
- data/app/views/users/_form_quota_tab.html.erb +45 -0
- data/config/initializers/inflections.rb +5 -0
- data/config/routes.rb +43 -0
- data/db/migrate/20230306120001_create_resource_quotas.rb +31 -0
- data/lib/foreman_resource_quota/engine.rb +56 -0
- data/lib/foreman_resource_quota/exceptions.rb +11 -0
- data/lib/foreman_resource_quota/register.rb +106 -0
- data/lib/foreman_resource_quota/version.rb +5 -0
- data/lib/foreman_resource_quota.rb +6 -0
- data/lib/tasks/foreman_resource_quota_tasks.rake +50 -0
- data/locale/Makefile +60 -0
- data/locale/en/foreman_resource_quota.po +18 -0
- data/locale/foreman_resource_quota.pot +19 -0
- data/locale/gemspec.rb +4 -0
- data/package.json +44 -0
- data/webpack/api_helper.js +113 -0
- data/webpack/api_helper.test.js +96 -0
- data/webpack/components/CreateResourceQuotaModal.js +46 -0
- data/webpack/components/ResourceQuotaEmptyState/index.js +58 -0
- data/webpack/components/ResourceQuotaForm/ResourceQuotaForm.scss +1 -0
- data/webpack/components/ResourceQuotaForm/ResourceQuotaFormConstants.js +71 -0
- data/webpack/components/ResourceQuotaForm/components/Properties/Properties.scss +9 -0
- data/webpack/components/ResourceQuotaForm/components/Properties/StaticDetail.js +72 -0
- data/webpack/components/ResourceQuotaForm/components/Properties/StatusPropertiesLabel.js +71 -0
- data/webpack/components/ResourceQuotaForm/components/Properties/StatusPropertiesLabel.test.js +50 -0
- data/webpack/components/ResourceQuotaForm/components/Properties/TextInputField.js +131 -0
- data/webpack/components/ResourceQuotaForm/components/Properties/index.js +190 -0
- data/webpack/components/ResourceQuotaForm/components/QuotaState.js +157 -0
- data/webpack/components/ResourceQuotaForm/components/Resource/Resource.scss +13 -0
- data/webpack/components/ResourceQuotaForm/components/Resource/UnitInputField.js +224 -0
- data/webpack/components/ResourceQuotaForm/components/Resource/UtilizationProgress.js +151 -0
- data/webpack/components/ResourceQuotaForm/components/Resource/UtilizationProgress.scss +10 -0
- data/webpack/components/ResourceQuotaForm/components/Resource/index.js +239 -0
- data/webpack/components/ResourceQuotaForm/components/Resources.js +105 -0
- data/webpack/components/ResourceQuotaForm/components/Submit.js +72 -0
- data/webpack/components/ResourceQuotaForm/index.js +185 -0
- data/webpack/components/UpdateResourceQuotaModal.js +143 -0
- data/webpack/global_index.js +15 -0
- data/webpack/global_test_setup.js +11 -0
- data/webpack/helper.js +86 -0
- data/webpack/index.js +23 -0
- data/webpack/lib/ActionableDetail.js +115 -0
- data/webpack/lib/ActionableDetail.scss +4 -0
- data/webpack/lib/EditableSwitch.js +47 -0
- data/webpack/lib/EditableTextInput/EditableTextInput.js +206 -0
- data/webpack/lib/EditableTextInput/PencilEditButton.js +27 -0
- data/webpack/lib/EditableTextInput/__tests__/editableTextInput.test.js +193 -0
- data/webpack/lib/EditableTextInput/editableTextInput.scss +38 -0
- data/webpack/lib/EditableTextInput/index.js +4 -0
- data/webpack/lib/react-testing-lib-wrapper.js +80 -0
- data/webpack/test_setup.js +17 -0
- metadata +134 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateResourceQuotas < ActiveRecord::Migration[6.1]
|
4
|
+
# rubocop: disable Metrics/AbcSize
|
5
|
+
def change
|
6
|
+
create_table :resource_quotas do |t|
|
7
|
+
t.string :name, null: false
|
8
|
+
t.text :description
|
9
|
+
t.integer :cpu_cores, default: nil
|
10
|
+
t.integer :memory_mb, default: nil
|
11
|
+
t.integer :disk_gb, default: nil
|
12
|
+
|
13
|
+
t.timestamps
|
14
|
+
end
|
15
|
+
|
16
|
+
create_table :resource_quotas_usergroups do |t|
|
17
|
+
t.belongs_to :resource_quota
|
18
|
+
t.belongs_to :usergroup
|
19
|
+
t.timestamps
|
20
|
+
end
|
21
|
+
|
22
|
+
create_table :resource_quotas_users do |t|
|
23
|
+
t.belongs_to :resource_quota
|
24
|
+
t.belongs_to :user
|
25
|
+
t.timestamps
|
26
|
+
end
|
27
|
+
add_reference :hosts, :resource_quota, foreign_key: { to_table: :resource_quotas }
|
28
|
+
add_column :users, :resource_quota_is_optional, :boolean, default: false
|
29
|
+
end
|
30
|
+
# rubocop: enable Metrics/AbcSize
|
31
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ForemanResourceQuota
|
4
|
+
class Engine < ::Rails::Engine
|
5
|
+
engine_name 'foreman_resource_quota'
|
6
|
+
|
7
|
+
config.autoload_paths += Dir["#{config.root}/app/models/"]
|
8
|
+
config.autoload_paths += Dir["#{config.root}/app/controllers/"]
|
9
|
+
config.autoload_paths += Dir["#{config.root}/app/views/"]
|
10
|
+
config.autoload_paths += Dir["#{config.root}/app/services/foreman_resource_quota/"]
|
11
|
+
config.autoload_paths += Dir["#{config.root}/app/helpers/foreman_resource_quota/"]
|
12
|
+
config.autoload_paths += Dir["#{config.root}/lib/"]
|
13
|
+
|
14
|
+
# Add db migrations
|
15
|
+
initializer 'foreman_resource_quota.load_app_instance_data' do |app|
|
16
|
+
ForemanResourceQuota::Engine.paths['db/migrate'].existent.each do |path|
|
17
|
+
app.config.paths['db/migrate'] << path
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Apipie
|
22
|
+
initializer 'foreman_resource_quota.apipie' do
|
23
|
+
Apipie.configuration.checksum_path += ['/foreman_resource_quota/api/']
|
24
|
+
Rabl.configure do |config|
|
25
|
+
config.view_paths << ForemanResourceQuota::Engine.root.join('app', 'views', 'foreman_resource_quota')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Rake tasks
|
30
|
+
rake_tasks do
|
31
|
+
Rake::Task['db:seed'].enhance do
|
32
|
+
ForemanResourceQuota::Engine.load_seed
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Plugin extensions
|
37
|
+
initializer 'foreman_resource_quota.register_plugin', before: :finisher_hook do |_app|
|
38
|
+
require 'foreman_resource_quota/register'
|
39
|
+
end
|
40
|
+
|
41
|
+
# Include concerns in this config.to_prepare block
|
42
|
+
config.to_prepare do
|
43
|
+
::User.include ForemanResourceQuota::UserExtensions
|
44
|
+
::Usergroup.include ForemanResourceQuota::UsergroupExtensions
|
45
|
+
::Host::Managed.include ForemanResourceQuota::HostManagedExtensions
|
46
|
+
rescue StandardError => e
|
47
|
+
Rails.logger.warn "ForemanResourceQuota: skipping engine hook (#{e})"
|
48
|
+
end
|
49
|
+
|
50
|
+
initializer 'foreman_resource_quota.register_gettext', after: :load_config_initializers do |_app|
|
51
|
+
locale_dir = File.join(File.expand_path('../..', __dir__), 'locale')
|
52
|
+
locale_domain = 'foreman_resource_quota'
|
53
|
+
Foreman::Gettext::Support.add_text_domain locale_domain, locale_dir
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ForemanResourceQuota
|
4
|
+
module Exceptions
|
5
|
+
class ResourceQuotaException < Foreman::Exception; end
|
6
|
+
class HostResourceQuotaEmptyException < ResourceQuotaException; end
|
7
|
+
class ResourceLimitException < ResourceQuotaException; end
|
8
|
+
class HostResourcesException < ResourceQuotaException; end
|
9
|
+
class ResourceQuotaUtilizationException < ResourceQuotaException; end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop: disable Metrics/BlockLength
|
4
|
+
Foreman::Plugin.register :foreman_resource_quota do
|
5
|
+
requires_foreman '>= 3.5.0'
|
6
|
+
# Apipie
|
7
|
+
apipie_documented_controllers ["#{ForemanResourceQuota::Engine.root}" \
|
8
|
+
'/app/controllers/foreman_resource_quot/api/v2/*.rb']
|
9
|
+
|
10
|
+
# Add permissions
|
11
|
+
security_block :foreman_resource_quota do
|
12
|
+
permission 'view_foreman_resource_quota/resource_quotas',
|
13
|
+
{ 'foreman_resource_quota/resource_quotas': %i[index welcome auto_complete_search],
|
14
|
+
'foreman_resource_quota/api/v2/resource_quotas': %i[index show utilization hosts users usergroups
|
15
|
+
auto_complete_search],
|
16
|
+
'foreman_resource_quota/api/v2/resource_quotas/:resource_quota_id/': %i[utilization hosts users usergroups] },
|
17
|
+
resource_type: 'ForemanResourceQuota::ResourceQuota'
|
18
|
+
permission 'create_foreman_resource_quota/resource_quotas',
|
19
|
+
{ 'foreman_resource_quota/resource_quotas': %i[new create],
|
20
|
+
'foreman_resource_quota/api/v2/resource_quotas': %i[create] },
|
21
|
+
resource_type: 'ForemanResourceQuota::ResourceQuota'
|
22
|
+
permission 'edit_foreman_resource_quota/resource_quotas',
|
23
|
+
{ 'foreman_resource_quota/resource_quotas': %i[edit update],
|
24
|
+
'foreman_resource_quota/api/v2/resource_quotas': %i[update] },
|
25
|
+
resource_type: 'ForemanResourceQuota::ResourceQuota'
|
26
|
+
permission 'destroy_foreman_resource_quota/resource_quotas',
|
27
|
+
{ 'foreman_resource_quota/resource_quotas': %i[destroy],
|
28
|
+
'foreman_resource_quota/api/v2/resource_quotas': %i[destroy] },
|
29
|
+
resource_type: 'ForemanResourceQuota::ResourceQuota'
|
30
|
+
|
31
|
+
# TODO: Evaluate whether host/user/usergroup permission extensions are necessary
|
32
|
+
end
|
33
|
+
|
34
|
+
# Add a permissions to default roles (Viewer and Manager)
|
35
|
+
role 'Resource Quota Manager', ['view_foreman_resource_quota/resource_quotas',
|
36
|
+
'create_foreman_resource_quota/resource_quotas',
|
37
|
+
'edit_foreman_resource_quota/resource_quotas',
|
38
|
+
'destroy_foreman_resource_quota/resource_quotas',
|
39
|
+
'view_hosts',
|
40
|
+
'edit_hosts',
|
41
|
+
'view_users',
|
42
|
+
'edit_users']
|
43
|
+
role 'Resource Quota User', ['view_foreman_resource_quota/resource_quotas',
|
44
|
+
'view_hosts',
|
45
|
+
'view_users',
|
46
|
+
'view_usergroups']
|
47
|
+
add_all_permissions_to_default_roles
|
48
|
+
|
49
|
+
# add controller parameter extension
|
50
|
+
parameter_filter User, { resource_quotas: [], resource_quota_ids: [] }, :resource_quota_is_optional
|
51
|
+
parameter_filter Usergroup, { resource_quotas: [], resource_quota_ids: [] }
|
52
|
+
parameter_filter Host::Managed, :resource_quota_id
|
53
|
+
|
54
|
+
# add UI menu extension
|
55
|
+
add_menu_item :top_menu, :resource_quotas,
|
56
|
+
url_hash: { controller: 'foreman_resource_quota/resource_quotas', action: :index },
|
57
|
+
caption: N_('Resource Quotas'),
|
58
|
+
parent: :configure_menu,
|
59
|
+
after: :common_parameters
|
60
|
+
|
61
|
+
# add API extension
|
62
|
+
extend_rabl_template 'api/v2/hosts/main', 'foreman_resource_quota/api/v2/hosts/resource_quota'
|
63
|
+
extend_rabl_template 'api/v2/users/main', 'foreman_resource_quota/api/v2/users/resource_quota'
|
64
|
+
extend_rabl_template 'api/v2/usergroups/main', 'foreman_resource_quota/api/v2/usergroups/resource_quota'
|
65
|
+
|
66
|
+
# add UI user/usergroup/hosts extension
|
67
|
+
extend_page 'users/_form' do |cx|
|
68
|
+
cx.add_pagelet :main_tabs,
|
69
|
+
id: :quota_user_tab,
|
70
|
+
name: N_('Resource Quota'),
|
71
|
+
resource_type: :user,
|
72
|
+
partial: 'users/form_quota_tab'
|
73
|
+
end
|
74
|
+
extend_page 'usergroups/_form' do |cx|
|
75
|
+
cx.add_pagelet :main_tabs,
|
76
|
+
id: :quota_usergroup_tab,
|
77
|
+
name: N_('Resource Quota'),
|
78
|
+
resource_type: :usergroup,
|
79
|
+
partial: 'users/form_quota_tab'
|
80
|
+
end
|
81
|
+
extend_page 'hosts/_form' do |cx|
|
82
|
+
cx.add_pagelet :main_tab_fields,
|
83
|
+
id: :quota_hosts_tab_fields,
|
84
|
+
resource_type: :host,
|
85
|
+
partial: 'hosts/form_quota_fields'
|
86
|
+
end
|
87
|
+
|
88
|
+
# Add global Foreman settings
|
89
|
+
settings do
|
90
|
+
category :provisioning do
|
91
|
+
setting 'resource_quota_optional_assignment',
|
92
|
+
type: :boolean,
|
93
|
+
default: false,
|
94
|
+
full_name: N_('Resource Quota optional assignment'),
|
95
|
+
description: N_('Make the assignment of a Resource quota, during the host creation process, optional for
|
96
|
+
everyone. If this is true, user-specific "optional assignment" configurations are neglected.')
|
97
|
+
setting 'resource_quota_global_no_action',
|
98
|
+
type: :boolean,
|
99
|
+
default: true,
|
100
|
+
full_name: N_('Global Resource Quota no action'),
|
101
|
+
description: N_('Take no action when a resource quota is exceeded.')
|
102
|
+
# Future: Overwrite quota-specific "out of resource"-action and take no ..
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
# rubocop: enable Metrics/BlockLength
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
# Tasks
|
6
|
+
namespace :foreman_resource_quota do
|
7
|
+
namespace :example do
|
8
|
+
desc 'Example Task'
|
9
|
+
task task: :environment do
|
10
|
+
# Task goes here
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Tests
|
16
|
+
namespace :test do
|
17
|
+
desc 'Test ForemanResourceQuota'
|
18
|
+
Rake::TestTask.new(:foreman_resource_quota) do |t|
|
19
|
+
test_dir = File.expand_path('../../test', __dir__)
|
20
|
+
t.libs << 'test'
|
21
|
+
t.libs << test_dir
|
22
|
+
t.pattern = "#{test_dir}/**/*_test.rb"
|
23
|
+
t.verbose = true
|
24
|
+
t.warning = false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
namespace :foreman_resource_quota do
|
29
|
+
task rubocop: :environment do
|
30
|
+
begin
|
31
|
+
require 'rubocop/rake_task'
|
32
|
+
RuboCop::RakeTask.new(:rubocop_foreman_resource_quota) do |task|
|
33
|
+
task.patterns = ["#{ForemanResourceQuota::Engine.root}/app/**/*.rb",
|
34
|
+
"#{ForemanResourceQuota::Engine.root}/lib/**/*.rb",
|
35
|
+
"#{ForemanResourceQuota::Engine.root}/test/**/*.rb"]
|
36
|
+
end
|
37
|
+
rescue StandardError
|
38
|
+
puts 'Rubocop not loaded.'
|
39
|
+
end
|
40
|
+
|
41
|
+
Rake::Task['rubocop_foreman_resource_quota'].invoke
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
Rake::Task[:test].enhance ['test:foreman_resource_quota']
|
46
|
+
|
47
|
+
load 'tasks/jenkins.rake'
|
48
|
+
if Rake::Task.task_defined?(:'jenkins:unit')
|
49
|
+
Rake::Task['jenkins:unit'].enhance ['test:foreman_resource_quota', 'foreman_resource_quota:rubocop']
|
50
|
+
end
|
data/locale/Makefile
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
#
|
2
|
+
# Makefile for PO merging and MO generation. More info in the README.
|
3
|
+
#
|
4
|
+
# make all-mo (default) - generate MO files
|
5
|
+
# make check - check translations using translate-tool
|
6
|
+
# make tx-update - download and merge translations from Transifex
|
7
|
+
# make clean - clean everything
|
8
|
+
#
|
9
|
+
DOMAIN = foreman_resource_quota
|
10
|
+
VERSION = $(shell ruby -e 'require "rubygems";spec = Gem::Specification::load(Dir.glob("../*.gemspec")[0]);puts spec.version')
|
11
|
+
POTFILE = $(DOMAIN).pot
|
12
|
+
MOFILE = $(DOMAIN).mo
|
13
|
+
POFILES = $(shell find . -name '$(DOMAIN).po')
|
14
|
+
MOFILES = $(patsubst %.po,%.mo,$(POFILES))
|
15
|
+
POXFILES = $(patsubst %.po,%.pox,$(POFILES))
|
16
|
+
EDITFILES = $(patsubst %.po,%.edit.po,$(POFILES))
|
17
|
+
|
18
|
+
%.mo: %.po
|
19
|
+
mkdir -p $(shell dirname $@)/LC_MESSAGES
|
20
|
+
msgfmt -o $(shell dirname $@)/LC_MESSAGES/$(MOFILE) $<
|
21
|
+
|
22
|
+
# Generate MO files from PO files
|
23
|
+
all-mo: $(MOFILES)
|
24
|
+
|
25
|
+
# Check for malformed strings
|
26
|
+
%.pox: %.po
|
27
|
+
msgfmt -c $<
|
28
|
+
pofilter --nofuzzy -t variables -t blank -t urls -t emails -t long -t newlines \
|
29
|
+
-t endwhitespace -t endpunc -t puncspacing -t options -t printf -t validchars --gnome $< > $@
|
30
|
+
cat $@
|
31
|
+
! grep -q msgid $@
|
32
|
+
|
33
|
+
%.edit.po:
|
34
|
+
touch $@
|
35
|
+
|
36
|
+
check: $(POXFILES)
|
37
|
+
|
38
|
+
# Unify duplicate translations
|
39
|
+
uniq-po:
|
40
|
+
for f in $(shell find ./ -name "*.po") ; do \
|
41
|
+
msguniq $$f -o $$f ; \
|
42
|
+
done
|
43
|
+
|
44
|
+
tx-pull: $(EDITFILES)
|
45
|
+
tx pull -f
|
46
|
+
for f in $(EDITFILES) ; do \
|
47
|
+
sed -i 's/^\("Project-Id-Version: \).*$$/\1$(DOMAIN) $(VERSION)\\n"/' $$f; \
|
48
|
+
done
|
49
|
+
|
50
|
+
tx-update: tx-pull
|
51
|
+
@echo
|
52
|
+
@echo Run rake plugin:gettext[$(DOMAIN)] from the Foreman installation, then make -C locale mo-files to finish
|
53
|
+
@echo
|
54
|
+
|
55
|
+
mo-files: $(MOFILES)
|
56
|
+
git add $(POFILES) $(POTFILE) ../locale/*/LC_MESSAGES
|
57
|
+
git commit -m "i18n - pulling from tx"
|
58
|
+
@echo
|
59
|
+
@echo Changes commited!
|
60
|
+
@echo
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# foreman_resource_quota
|
2
|
+
#
|
3
|
+
# This file is distributed under the same license as foreman_resource_quota.
|
4
|
+
#
|
5
|
+
#, fuzzy
|
6
|
+
msgid ""
|
7
|
+
msgstr ""
|
8
|
+
"Project-Id-Version: version 0.0.1\n"
|
9
|
+
"Report-Msgid-Bugs-To: \n"
|
10
|
+
"POT-Creation-Date: 2014-08-20 08:46+0100\n"
|
11
|
+
"PO-Revision-Date: 2014-08-20 08:54+0100\n"
|
12
|
+
"Last-Translator: Foreman Team <foreman-dev@googlegroups.com>\n"
|
13
|
+
"Language-Team: Foreman Team <foreman-dev@googlegroups.com>\n"
|
14
|
+
"Language: \n"
|
15
|
+
"MIME-Version: 1.0\n"
|
16
|
+
"Content-Type: text/plain; charset=UTF-8\n"
|
17
|
+
"Content-Transfer-Encoding: 8bit\n"
|
18
|
+
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# foreman_resource_quota
|
2
|
+
#
|
3
|
+
# This file is distributed under the same license as foreman_resource_quota.
|
4
|
+
#
|
5
|
+
#, fuzzy
|
6
|
+
msgid ""
|
7
|
+
msgstr ""
|
8
|
+
"Project-Id-Version: version 0.0.1\n"
|
9
|
+
"Report-Msgid-Bugs-To: \n"
|
10
|
+
"POT-Creation-Date: 2014-08-20 08:46+0100\n"
|
11
|
+
"PO-Revision-Date: 2014-08-20 08:46+0100\n"
|
12
|
+
"Last-Translator: Foreman Team <foreman-dev@googlegroups.com>\n"
|
13
|
+
"Language-Team: Foreman Team <foreman-dev@googlegroups.com>\n"
|
14
|
+
"Language: \n"
|
15
|
+
"MIME-Version: 1.0\n"
|
16
|
+
"Content-Type: text/plain; charset=UTF-8\n"
|
17
|
+
"Content-Transfer-Encoding: 8bit\n"
|
18
|
+
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
|
19
|
+
|
data/locale/gemspec.rb
ADDED
data/package.json
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
{
|
2
|
+
"name": "foreman_resource_quota",
|
3
|
+
"version": "1.0.0",
|
4
|
+
"description": "DESCRIPTION",
|
5
|
+
"main": "index.js",
|
6
|
+
"scripts": {
|
7
|
+
"lint": "tfm-lint --plugin -d /webpack",
|
8
|
+
"test": "tfm-test --plugin --config jest.config.js",
|
9
|
+
"test:watch": "tfm-test --plugin --watchAll",
|
10
|
+
"test:current": "tfm-test --plugin --watch",
|
11
|
+
"publish-coverage": "tfm-publish-coverage",
|
12
|
+
"stories": "tfm-stories --plugin",
|
13
|
+
"stories:build": "tfm-build-stories --plugin",
|
14
|
+
"create-react-component": "yo react-domain"
|
15
|
+
},
|
16
|
+
"repository": {
|
17
|
+
"type": "git",
|
18
|
+
"url": "git+https://github.com/theforeman/foreman_resource_quota.git"
|
19
|
+
},
|
20
|
+
"bugs": {
|
21
|
+
"url": "http://projects.theforeman.org/projects/foreman_resource_quota/issues"
|
22
|
+
},
|
23
|
+
"peerDependencies": {
|
24
|
+
"@theforeman/vendor": ">= 6.0.0"
|
25
|
+
},
|
26
|
+
"dependencies": {},
|
27
|
+
"devDependencies": {
|
28
|
+
"@babel/core": "^7.24.3",
|
29
|
+
"@sheerun/mutationobserver-shim": "^0.3.3",
|
30
|
+
"@testing-library/react": "^10.4.9",
|
31
|
+
"@theforeman/builder": "^10.1.3",
|
32
|
+
"@theforeman/eslint-plugin-foreman": "13.0.0",
|
33
|
+
"@theforeman/find-foreman": "^13.0.0",
|
34
|
+
"@theforeman/stories": "^12.2.3",
|
35
|
+
"@theforeman/test": "^13.0.0",
|
36
|
+
"@theforeman/vendor-dev": "^13.0.0",
|
37
|
+
"babel-eslint": "^10.0.3",
|
38
|
+
"eslint": "^6.7.2",
|
39
|
+
"prettier": "^1.19.1",
|
40
|
+
"react-redux-test-utils": "^0.2.0",
|
41
|
+
"stylelint": "^16.3.1",
|
42
|
+
"stylelint-config-standard": "^36.0.0"
|
43
|
+
}
|
44
|
+
}
|
@@ -0,0 +1,113 @@
|
|
1
|
+
import { addToast } from 'foremanReact/components/ToastsList';
|
2
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
3
|
+
import { get, put, post } from 'foremanReact/redux/API';
|
4
|
+
|
5
|
+
/* API constants */
|
6
|
+
const RESOURCE_QUOTA_KEY = 'RESOURCE_QUOTAS';
|
7
|
+
|
8
|
+
export const resourceQuotaKey = quotaId => {
|
9
|
+
if (quotaId) return `${RESOURCE_QUOTA_KEY}_${quotaId}`;
|
10
|
+
return `${RESOURCE_QUOTA_KEY}`;
|
11
|
+
};
|
12
|
+
|
13
|
+
/* perform an API call to list all existing Resource Quotas */
|
14
|
+
const apiListResourceQuotas = (stateCallback, componentCallback) =>
|
15
|
+
get({
|
16
|
+
key: resourceQuotaKey(),
|
17
|
+
url: `/foreman_resource_quota/api/v2/resource_quotas`,
|
18
|
+
handleSuccess: response => stateCallback(true, response, componentCallback),
|
19
|
+
handleError: response => stateCallback(false, response, componentCallback),
|
20
|
+
});
|
21
|
+
|
22
|
+
/* perform an API call to get basic information on a Resource Quota */
|
23
|
+
const apiGetResourceQuota = (quotaId, stateCallback, componentCallback) =>
|
24
|
+
get({
|
25
|
+
key: resourceQuotaKey(),
|
26
|
+
url: `/foreman_resource_quota/api/v2/resource_quotas/${quotaId}`,
|
27
|
+
handleSuccess: response => stateCallback(true, response, componentCallback),
|
28
|
+
handleError: response => stateCallback(false, response, componentCallback),
|
29
|
+
});
|
30
|
+
|
31
|
+
/* perform an API call to determine information on a Resource Quota's utilization */
|
32
|
+
const apiGetResourceQuotaUtilization = (
|
33
|
+
quotaId,
|
34
|
+
stateCallback,
|
35
|
+
componentCallback
|
36
|
+
) =>
|
37
|
+
get({
|
38
|
+
key: resourceQuotaKey(),
|
39
|
+
url: `/foreman_resource_quota/api/v2/resource_quotas/${quotaId}/utilization`,
|
40
|
+
handleSuccess: response => stateCallback(true, response, componentCallback),
|
41
|
+
handleError: response => stateCallback(false, response, componentCallback),
|
42
|
+
});
|
43
|
+
|
44
|
+
/* perform an API call to create a new Resource Quota */
|
45
|
+
const apiCreateResourceQuota = (payload, stateCallback, componentCallback) =>
|
46
|
+
post({
|
47
|
+
key: resourceQuotaKey(),
|
48
|
+
url: `/foreman_resource_quota/api/v2/resource_quotas`,
|
49
|
+
params: { resource_quota: payload },
|
50
|
+
handleSuccess: response => stateCallback(true, response, componentCallback),
|
51
|
+
handleError: response => stateCallback(false, response, componentCallback),
|
52
|
+
});
|
53
|
+
|
54
|
+
/* perform an API call to update Resource Quota data */
|
55
|
+
const apiUpdateResourceQuota = (
|
56
|
+
quotaId,
|
57
|
+
payload,
|
58
|
+
stateCallback,
|
59
|
+
componentCallback
|
60
|
+
) =>
|
61
|
+
put({
|
62
|
+
key: resourceQuotaKey(quotaId),
|
63
|
+
url: `/foreman_resource_quota/api/v2/resource_quotas/${quotaId}`,
|
64
|
+
params: { resource_quota: payload },
|
65
|
+
handleSuccess: response => stateCallback(true, response, componentCallback),
|
66
|
+
handleError: response => stateCallback(false, response, componentCallback),
|
67
|
+
});
|
68
|
+
|
69
|
+
/**
|
70
|
+
* Handles the callback response from an asynchronous operation, displaying a toast message accordingly.
|
71
|
+
* @param {function} dispatcher - The dispatcher function to dispatch actions.
|
72
|
+
* @param {boolean} isSuccess - Indicates whether the operation was successful or not.
|
73
|
+
* @param {object} response - The response object returned from the operation.
|
74
|
+
* @param {string} successMessage - The success message to display in case of success.
|
75
|
+
* @param {string} errorMessage - The error message to display in case of failure.
|
76
|
+
*/
|
77
|
+
const dispatchAPICallbackToast = (
|
78
|
+
dispatch,
|
79
|
+
isSuccess,
|
80
|
+
response,
|
81
|
+
successMessage,
|
82
|
+
errorMessage
|
83
|
+
) => {
|
84
|
+
if (isSuccess) {
|
85
|
+
dispatch(
|
86
|
+
addToast({
|
87
|
+
type: 'success',
|
88
|
+
message: __(successMessage),
|
89
|
+
})
|
90
|
+
);
|
91
|
+
} else {
|
92
|
+
let printErrorMessage = __(errorMessage);
|
93
|
+
/* eslint-disable-next-line camelcase */
|
94
|
+
if (response?.response?.data?.error?.full_messages) {
|
95
|
+
printErrorMessage += __(` ${response.response.data.error.full_messages}`);
|
96
|
+
}
|
97
|
+
dispatch(
|
98
|
+
addToast({
|
99
|
+
type: 'warning',
|
100
|
+
message: printErrorMessage,
|
101
|
+
})
|
102
|
+
);
|
103
|
+
}
|
104
|
+
};
|
105
|
+
|
106
|
+
export {
|
107
|
+
apiListResourceQuotas,
|
108
|
+
apiGetResourceQuota,
|
109
|
+
apiGetResourceQuotaUtilization,
|
110
|
+
apiCreateResourceQuota,
|
111
|
+
apiUpdateResourceQuota,
|
112
|
+
dispatchAPICallbackToast,
|
113
|
+
};
|
@@ -0,0 +1,96 @@
|
|
1
|
+
import { dispatchAPICallbackToast } from './api_helper';
|
2
|
+
|
3
|
+
jest.mock('foremanReact/components/ToastsList', () => ({
|
4
|
+
addToast: jest.fn(param => param),
|
5
|
+
}));
|
6
|
+
|
7
|
+
jest.mock('foremanReact/common/I18n', () => ({
|
8
|
+
translate: jest.fn(param => param),
|
9
|
+
}));
|
10
|
+
|
11
|
+
const dispatch = jest.fn();
|
12
|
+
|
13
|
+
describe('dispatchAPICallbackToast', () => {
|
14
|
+
afterEach(() => {
|
15
|
+
jest.clearAllMocks(); // Reset mock calls after each test
|
16
|
+
});
|
17
|
+
|
18
|
+
it('should dispatch a success toast', () => {
|
19
|
+
const isSuccess = true;
|
20
|
+
const response = {};
|
21
|
+
const successMessage = 'Success message';
|
22
|
+
const errorMessage = 'Error message';
|
23
|
+
|
24
|
+
dispatchAPICallbackToast(
|
25
|
+
dispatch,
|
26
|
+
isSuccess,
|
27
|
+
response,
|
28
|
+
successMessage,
|
29
|
+
errorMessage
|
30
|
+
);
|
31
|
+
|
32
|
+
expect(dispatch).toHaveBeenCalledTimes(1);
|
33
|
+
expect(dispatch).toHaveBeenCalledWith({
|
34
|
+
type: 'success',
|
35
|
+
message: 'Success message',
|
36
|
+
});
|
37
|
+
});
|
38
|
+
|
39
|
+
it('should dispatch a warning toast with error', () => {
|
40
|
+
const isSuccess = false;
|
41
|
+
const response = {
|
42
|
+
response: {
|
43
|
+
data: {
|
44
|
+
error: {
|
45
|
+
full_messages: 'Some nice error',
|
46
|
+
},
|
47
|
+
},
|
48
|
+
},
|
49
|
+
};
|
50
|
+
const successMessage = 'Success message';
|
51
|
+
const errorMessage = 'Error message';
|
52
|
+
|
53
|
+
dispatchAPICallbackToast(
|
54
|
+
dispatch,
|
55
|
+
isSuccess,
|
56
|
+
response,
|
57
|
+
successMessage,
|
58
|
+
errorMessage
|
59
|
+
);
|
60
|
+
|
61
|
+
expect(dispatch).toHaveBeenCalledTimes(1);
|
62
|
+
expect(dispatch).toHaveBeenCalledWith({
|
63
|
+
type: 'warning',
|
64
|
+
message: 'Error message Some nice error',
|
65
|
+
});
|
66
|
+
});
|
67
|
+
|
68
|
+
it('should dispatch a warning toast without error', () => {
|
69
|
+
const isSuccess = false;
|
70
|
+
const response = {
|
71
|
+
response: {
|
72
|
+
data: {
|
73
|
+
notTheExpectedErrorFormat: {
|
74
|
+
full_messages: 'Some nice error',
|
75
|
+
},
|
76
|
+
},
|
77
|
+
},
|
78
|
+
};
|
79
|
+
const successMessage = 'Success message';
|
80
|
+
const errorMessage = 'Error message';
|
81
|
+
|
82
|
+
dispatchAPICallbackToast(
|
83
|
+
dispatch,
|
84
|
+
isSuccess,
|
85
|
+
response,
|
86
|
+
successMessage,
|
87
|
+
errorMessage
|
88
|
+
);
|
89
|
+
|
90
|
+
expect(dispatch).toHaveBeenCalledTimes(1);
|
91
|
+
expect(dispatch).toHaveBeenCalledWith({
|
92
|
+
type: 'warning',
|
93
|
+
message: 'Error message',
|
94
|
+
});
|
95
|
+
});
|
96
|
+
});
|
@@ -0,0 +1,46 @@
|
|
1
|
+
import React, { useState } from 'react';
|
2
|
+
import { Button, Modal, ModalVariant } from '@patternfly/react-core';
|
3
|
+
|
4
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
5
|
+
|
6
|
+
import ResourceQuotaForm from './ResourceQuotaForm';
|
7
|
+
import { MODAL_ID_CREATE_RESOURCE_QUOTA } from './ResourceQuotaForm/ResourceQuotaFormConstants';
|
8
|
+
|
9
|
+
const CreateResourceQuotaModal = () => {
|
10
|
+
const [isOpen, setIsOpen] = useState(false);
|
11
|
+
|
12
|
+
const onSubmitSuccessCallback = success => {
|
13
|
+
if (success) {
|
14
|
+
setIsOpen(false);
|
15
|
+
window.location.reload();
|
16
|
+
}
|
17
|
+
};
|
18
|
+
|
19
|
+
return (
|
20
|
+
<div>
|
21
|
+
<Button
|
22
|
+
id="foreman-resource-quota-create-modal-button"
|
23
|
+
variant="primary"
|
24
|
+
onClick={() => {
|
25
|
+
setIsOpen(true);
|
26
|
+
}}
|
27
|
+
>
|
28
|
+
{__('Create resource quota')}
|
29
|
+
</Button>{' '}
|
30
|
+
<Modal
|
31
|
+
ouiaId={MODAL_ID_CREATE_RESOURCE_QUOTA}
|
32
|
+
title={__('Create resource quota')}
|
33
|
+
variant={ModalVariant.small}
|
34
|
+
isOpen={isOpen}
|
35
|
+
onClose={() => {
|
36
|
+
setIsOpen(false);
|
37
|
+
}}
|
38
|
+
appendTo={document.body}
|
39
|
+
>
|
40
|
+
<ResourceQuotaForm isNewQuota onSubmit={onSubmitSuccessCallback} />
|
41
|
+
</Modal>
|
42
|
+
</div>
|
43
|
+
);
|
44
|
+
};
|
45
|
+
|
46
|
+
export default CreateResourceQuotaModal;
|