foreman-tasks 8.1.4 → 8.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/app/lib/actions/action_with_sub_plans.rb +2 -10
- data/app/lib/actions/bulk_action.rb +5 -5
- data/app/lib/actions/check_long_running_tasks.rb +6 -8
- data/app/lib/actions/deliver_long_running_tasks_notification.rb +0 -4
- data/app/models/foreman_tasks/concerns/user_extensions.rb +0 -19
- data/db/seeds.d/95-mail_notifications.rb +0 -14
- data/foreman-tasks.gemspec +1 -1
- data/lib/foreman_tasks/version.rb +1 -1
- data/package.json +6 -11
- data/test/unit/actions/action_with_sub_plans_test.rb +4 -0
- data/test/unit/task_groups_test.rb +4 -0
- metadata +4 -18
- data/.yo-rc.json +0 -5
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.stories.js +0 -9
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/PausedTasksCard.stories.js +0 -55
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/RunningTasksCard.stories.js +0 -56
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.stories.js +0 -33
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.stories.js +0 -72
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.stories.js +0 -51
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChart.stories.js +0 -26
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.stories.js +0 -55
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/TasksLabelsRow.stories.js +0 -21
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/TimeDropDown.stories.mdx +0 -57
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/TasksTimeRow.stories.js +0 -40
- data/webpack/stories/decorators/index.js +0 -1
- data/webpack/stories/decorators/withCardsDecorator.js +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b4f35490448b3b8f50b3632eae9f565b954642055c8d81726e0774cbf0d5fbc5
|
4
|
+
data.tar.gz: f837f11d4a5e7c1d5d4fcc831bd20139d822374cb0289e5d9990f64830eac2f9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 83be04fc0573f35f6caa81af65adb8a5e81dbde915fa6f7465837d580dce1abe5e92fad16a4d3970e16170a0c195e08067d1e6fc2af97719f4e51bd7364c09af
|
7
|
+
data.tar.gz: ac31f6183e48f5dd4040e4679c2dc394afdc624bee2d0bf2beab8c94ca7661f8e72f165b92177551f1bb097bfb676669e5fa4c248c856b1bea2bd6080d3d54aa
|
data/.gitignore
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Actions
|
2
2
|
class Actions::ActionWithSubPlans < Actions::EntryAction
|
3
|
-
include Dynflow::Action::WithSubPlans
|
3
|
+
include Dynflow::Action::V2::WithSubPlans
|
4
4
|
|
5
5
|
def plan(*_args)
|
6
6
|
raise NotImplementedError
|
@@ -9,17 +9,9 @@ module Actions
|
|
9
9
|
def humanized_output
|
10
10
|
return unless counts_set?
|
11
11
|
_('%{total} task(s), %{success} success, %{failed} fail') %
|
12
|
-
{ total:
|
12
|
+
{ total: total_count,
|
13
13
|
success: output[:success_count],
|
14
14
|
failed: output[:failed_count] }
|
15
15
|
end
|
16
|
-
|
17
|
-
def run_progress
|
18
|
-
if counts_set? && output[:total_count] > 0
|
19
|
-
(output[:success_count] + output[:failed_count]).to_f / output[:total_count]
|
20
|
-
else
|
21
|
-
0.1
|
22
|
-
end
|
23
|
-
end
|
24
16
|
end
|
25
17
|
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
module Actions
|
2
2
|
class BulkAction < Actions::ActionWithSubPlans
|
3
|
-
include Dynflow::Action::WithBulkSubPlans
|
4
|
-
|
5
3
|
# == Parameters:
|
6
4
|
# actions_class::
|
7
5
|
# Class of action to trigger on targets
|
@@ -9,12 +7,14 @@ module Actions
|
|
9
7
|
# Array of objects on which the action_class should be triggered
|
10
8
|
# *args::
|
11
9
|
# Arguments that all the targets share
|
12
|
-
def plan(action_class, targets, *args)
|
10
|
+
def plan(action_class, targets, *args, concurrency_limit: nil, **kwargs)
|
13
11
|
check_targets!(targets)
|
12
|
+
limit_concurrency_level!(concurrency_limit) if concurrency_limit
|
14
13
|
plan_self(:action_class => action_class.to_s,
|
15
14
|
:target_ids => targets.map(&:id),
|
16
15
|
:target_class => targets.first.class.to_s,
|
17
|
-
:args => args
|
16
|
+
:args => args,
|
17
|
+
:kwargs => kwargs)
|
18
18
|
end
|
19
19
|
|
20
20
|
def run(event = nil)
|
@@ -51,7 +51,7 @@ module Actions
|
|
51
51
|
missing = Array.new((current_batch - targets.map(&:id)).count) { nil }
|
52
52
|
|
53
53
|
(targets + missing).map do |target|
|
54
|
-
trigger(action_class, target, *input[:args])
|
54
|
+
trigger(action_class, target, *input[:args], **input[:kwargs])
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
@@ -8,10 +8,12 @@ module Actions
|
|
8
8
|
def plan
|
9
9
|
time = Time.now.utc
|
10
10
|
cutoff = time - INTERVAL
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
.where(
|
11
|
+
notification = ::ForemanTasks::TasksMailNotification.find_by(name: "long_running_tasks")
|
12
|
+
org_admin_role = Role.find_by(name: 'Organization admin')
|
13
|
+
users = User.left_joins(:roles)
|
14
|
+
.where(id: UserMailNotification.where(mail_notification_id: notification.id).select(:role_id))
|
15
|
+
.or(User.where(admin: true))
|
16
|
+
.or(User.where(id: UserRole.where(id: [org_admin_role.id] + org_admin_role.cloned_role_ids).select(:owner_id)))
|
15
17
|
|
16
18
|
query = "state ^ (#{STATES.join(', ')}) AND state_updated_at <= \"#{cutoff}\""
|
17
19
|
users.each do |user|
|
@@ -39,9 +41,5 @@ module Actions
|
|
39
41
|
def humanized_name
|
40
42
|
_('Check for long running tasks')
|
41
43
|
end
|
42
|
-
|
43
|
-
def rescue_strategy_for_self
|
44
|
-
Dynflow::Action::Rescue::Skip
|
45
|
-
end
|
46
44
|
end
|
47
45
|
end
|
@@ -8,25 +8,6 @@ module ForemanTasks
|
|
8
8
|
has_many :tasks, :dependent => :nullify,
|
9
9
|
:class_name => ::ForemanTasks::Task.name
|
10
10
|
# rubocop:enable Rails/ReflectionClassName
|
11
|
-
|
12
|
-
before_validation :attach_task_mail_notifications, on: :create
|
13
|
-
end
|
14
|
-
|
15
|
-
def attach_task_mail_notifications
|
16
|
-
return if ::ForemanSeeder.is_seeding
|
17
|
-
|
18
|
-
org_admin_role = Role.find_by(name: 'Organization admin')
|
19
|
-
admin_by_role = org_admin_role &&
|
20
|
-
(roles.map(&:id) & ([org_admin_role.id] + org_admin_role.cloned_role_ids)).any?
|
21
|
-
|
22
|
-
return unless admin || admin_by_role
|
23
|
-
|
24
|
-
notification = MailNotification.find_by(name: 'long_running_tasks')
|
25
|
-
return if notification.nil?
|
26
|
-
|
27
|
-
if user_mail_notifications.none? { |n| n.mail_notification_id == notification.id }
|
28
|
-
user_mail_notifications.build(mail_notification_id: notification.id, interval: 'Subscribe')
|
29
|
-
end
|
30
11
|
end
|
31
12
|
end
|
32
13
|
end
|
@@ -20,19 +20,5 @@ notifications.each do |notification|
|
|
20
20
|
raise ::Foreman::Exception.new(N_("Unable to create mail notification: %s"),
|
21
21
|
SeedHelper.format_errors(created_notification))
|
22
22
|
end
|
23
|
-
|
24
|
-
org_admin_role = Role.find_by(name: 'Organization admin')
|
25
|
-
|
26
|
-
users = User.left_joins(:roles)
|
27
|
-
.joins(:auth_source)
|
28
|
-
.where(admin: true)
|
29
|
-
.or(User.where(id: UserRole.where(id: [org_admin_role.id] + org_admin_role.cloned_role_ids).select(:owner_id)))
|
30
|
-
.where.not(auth_source: { name: 'Hidden' })
|
31
|
-
users.each do |user|
|
32
|
-
mail = UserMailNotification.create(mail_notification_id: created_notification.id, user_id: user.id, interval: 'Subscribe')
|
33
|
-
if mail.nil? || mail.errors.any?
|
34
|
-
raise ::Foreman::Exception.new(N_("Unable to enable mail notification to user '%s': %s"), user.login, SeedHelper.format_errors(mail))
|
35
|
-
end
|
36
|
-
end
|
37
23
|
end
|
38
24
|
end
|
data/foreman-tasks.gemspec
CHANGED
@@ -26,7 +26,7 @@ same resource. It also optionally provides Dynflow infrastructure for using it f
|
|
26
26
|
s.test_files = `git ls-files test`.split("\n")
|
27
27
|
s.extra_rdoc_files = Dir['README*', 'LICENSE']
|
28
28
|
|
29
|
-
s.add_dependency "dynflow", '>= 1.
|
29
|
+
s.add_dependency "dynflow", '>= 1.8.0'
|
30
30
|
s.add_dependency 'fugit', '~> 1.8'
|
31
31
|
s.add_dependency "get_process_mem" # for memory polling
|
32
32
|
s.add_dependency "sinatra" # for Dynflow web console
|
data/package.json
CHANGED
@@ -9,11 +9,7 @@
|
|
9
9
|
"test": "tfm-test --plugin",
|
10
10
|
"test:watch": "tfm-test --plugin --watchAll",
|
11
11
|
"test:current": "tfm-test --plugin --watch",
|
12
|
-
"publish-coverage": "tfm-publish-coverage"
|
13
|
-
"stories": "tfm-stories --plugin",
|
14
|
-
"stories:build": "tfm-build-stories --plugin",
|
15
|
-
"stories:deploy": "surge --project .storybook-dist",
|
16
|
-
"create-react-component": "yo react-domain"
|
12
|
+
"publish-coverage": "tfm-publish-coverage"
|
17
13
|
},
|
18
14
|
"repository": {
|
19
15
|
"type": "git",
|
@@ -23,18 +19,17 @@
|
|
23
19
|
"url": "http://projects.theforeman.org/projects/foreman-tasks/issues"
|
24
20
|
},
|
25
21
|
"peerDependencies": {
|
26
|
-
"@theforeman/vendor": ">=
|
22
|
+
"@theforeman/vendor": ">= 12.1.1"
|
27
23
|
},
|
28
24
|
"dependencies": {
|
29
25
|
"c3": "^0.4.11"
|
30
26
|
},
|
31
27
|
"devDependencies": {
|
32
28
|
"@babel/core": "^7.7.0",
|
33
|
-
"@theforeman/builder": ">=
|
34
|
-
"@theforeman/eslint-plugin-foreman": ">=
|
35
|
-
"@theforeman/
|
36
|
-
"@theforeman/
|
37
|
-
"@theforeman/vendor-dev": ">= 10.1.0",
|
29
|
+
"@theforeman/builder": ">= 12.1.1",
|
30
|
+
"@theforeman/eslint-plugin-foreman": ">= 12.1.1",
|
31
|
+
"@theforeman/test": ">= 12.1.1",
|
32
|
+
"@theforeman/vendor-dev": ">= 12.1.1",
|
38
33
|
"babel-eslint": "^10.0.3",
|
39
34
|
"eslint": "^6.7.2",
|
40
35
|
"jed": "^1.1.1",
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman-tasks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 8.
|
4
|
+
version: 8.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ivan Nečas
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dynflow
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.
|
19
|
+
version: 1.8.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.
|
26
|
+
version: 1.8.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: fugit
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -116,7 +116,6 @@ files:
|
|
116
116
|
- ".rubocop_todo.yml"
|
117
117
|
- ".stylelintrc"
|
118
118
|
- ".tx/config"
|
119
|
-
- ".yo-rc.json"
|
120
119
|
- Gemfile
|
121
120
|
- LICENSE
|
122
121
|
- README.md
|
@@ -413,7 +412,6 @@ files:
|
|
413
412
|
- webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskInfo.test.js.snap
|
414
413
|
- webpack/ForemanTasks/Components/TaskDetails/TaskDetails.js
|
415
414
|
- webpack/ForemanTasks/Components/TaskDetails/TaskDetails.scss
|
416
|
-
- webpack/ForemanTasks/Components/TaskDetails/TaskDetails.stories.js
|
417
415
|
- webpack/ForemanTasks/Components/TaskDetails/TaskDetailsActions.js
|
418
416
|
- webpack/ForemanTasks/Components/TaskDetails/TaskDetailsConstants.js
|
419
417
|
- webpack/ForemanTasks/Components/TaskDetails/TaskDetailsSelectors.js
|
@@ -425,23 +423,19 @@ files:
|
|
425
423
|
- webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetailsActions.test.js.snap
|
426
424
|
- webpack/ForemanTasks/Components/TaskDetails/index.js
|
427
425
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/PausedTasksCard.js
|
428
|
-
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/PausedTasksCard.stories.js
|
429
426
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/PausedTasksCard.test.js
|
430
427
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/__snapshots__/PausedTasksCard.test.js.snap
|
431
428
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/RunningTasksCard.js
|
432
|
-
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/RunningTasksCard.stories.js
|
433
429
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/RunningTasksCard.test.js
|
434
430
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/__snapshots__/RunningTasksCard.test.js.snap
|
435
431
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.js
|
436
432
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.scss
|
437
|
-
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.stories.js
|
438
433
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.test.js
|
439
434
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/__snapshots__/ScheduledTasksCard.test.js.snap
|
440
435
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/OtherInfo.js
|
441
436
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/OtherInfo.test.js
|
442
437
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.js
|
443
438
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.scss
|
444
|
-
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.stories.js
|
445
439
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.test.js
|
446
440
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCardTable.js
|
447
441
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCardTable.test.js
|
@@ -450,12 +444,10 @@ files:
|
|
450
444
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/StoppedTasksCardTable.test.js.snap
|
451
445
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.js
|
452
446
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.scss
|
453
|
-
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.stories.js
|
454
447
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.test.js
|
455
448
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/__snapshots__/TasksDonutCard.test.js.snap
|
456
449
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChart.js
|
457
450
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChart.scss
|
458
|
-
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChart.stories.js
|
459
451
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChart.test.js
|
460
452
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChartConstants.js
|
461
453
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChartHelper.js
|
@@ -464,21 +456,17 @@ files:
|
|
464
456
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/__snapshots__/TasksDonutChartHelper.test.js.snap
|
465
457
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.fixtures.js
|
466
458
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.js
|
467
|
-
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.stories.js
|
468
459
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.test.js
|
469
460
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/__snapshots__/TasksCardsGrid.test.js.snap
|
470
461
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/TasksLabelsRow.js
|
471
462
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/TasksLabelsRow.scss
|
472
|
-
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/TasksLabelsRow.stories.js
|
473
463
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/TasksLabelsRow.test.js
|
474
464
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/__snapshots__/TasksLabelsRow.test.js.snap
|
475
465
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/TimeDropDown.js
|
476
|
-
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/TimeDropDown.stories.mdx
|
477
466
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/TimeDropDown.test.js
|
478
467
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/__snapshots__/TimeDropDown.test.js.snap
|
479
468
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/TasksTimeRow.js
|
480
469
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/TasksTimeRow.scss
|
481
|
-
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/TasksTimeRow.stories.js
|
482
470
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/TasksTimeRow.test.js
|
483
471
|
- webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/__snapshots__/TasksTimeRow.test.js.snap
|
484
472
|
- webpack/ForemanTasks/Components/TasksDashboard/TasksDashboard.js
|
@@ -621,8 +609,6 @@ files:
|
|
621
609
|
- webpack/__mocks__/foremanReact/routes/common/PageLayout/PageLayout.js
|
622
610
|
- webpack/__mocks__/foremanReact/routes/common/PageLayout/components/ExportButton/ExportButton.js
|
623
611
|
- webpack/index.js
|
624
|
-
- webpack/stories/decorators/index.js
|
625
|
-
- webpack/stories/decorators/withCardsDecorator.js
|
626
612
|
homepage: https://github.com/theforeman/foreman-tasks
|
627
613
|
licenses:
|
628
614
|
- GPL-3.0
|
data/.yo-rc.json
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import { action, number, select } from '@theforeman/stories';
|
3
|
-
import { withCardsDecorator } from '../../../../../../../stories/decorators';
|
4
|
-
|
5
|
-
import {
|
6
|
-
TASKS_DASHBOARD_AVAILABLE_QUERY_MODES,
|
7
|
-
TASKS_DASHBOARD_AVAILABLE_TIMES,
|
8
|
-
TASKS_DASHBOARD_AVAILABLE_QUERY_STATES,
|
9
|
-
} from '../../../../TasksDashboardConstants';
|
10
|
-
import PausedTasksCard from './PausedTasksCard';
|
11
|
-
|
12
|
-
export default {
|
13
|
-
title: 'TasksDashboard/TasksCardsGrid/Cards/PausedTasksCard',
|
14
|
-
component: PausedTasksCard,
|
15
|
-
decorators: [withCardsDecorator],
|
16
|
-
parameters: {
|
17
|
-
centered: { disable: true },
|
18
|
-
},
|
19
|
-
};
|
20
|
-
|
21
|
-
export const Basic = () => {
|
22
|
-
const selectTime = select(
|
23
|
-
'time',
|
24
|
-
TASKS_DASHBOARD_AVAILABLE_TIMES,
|
25
|
-
PausedTasksCard.defaultProps.time
|
26
|
-
);
|
27
|
-
|
28
|
-
const selectMode = select(
|
29
|
-
'mode',
|
30
|
-
{ ...TASKS_DASHBOARD_AVAILABLE_QUERY_MODES, NONE: 'none', TOTAL: null },
|
31
|
-
'none'
|
32
|
-
);
|
33
|
-
return (
|
34
|
-
<PausedTasksCard
|
35
|
-
data={{
|
36
|
-
last: number('data.last', 3),
|
37
|
-
older: number('data.older', 5),
|
38
|
-
}}
|
39
|
-
time={selectTime}
|
40
|
-
query={{
|
41
|
-
state: select(
|
42
|
-
'query.state',
|
43
|
-
{
|
44
|
-
...TASKS_DASHBOARD_AVAILABLE_QUERY_STATES,
|
45
|
-
NONE: null,
|
46
|
-
},
|
47
|
-
TASKS_DASHBOARD_AVAILABLE_QUERY_STATES.PAUSED
|
48
|
-
),
|
49
|
-
mode: selectMode,
|
50
|
-
time: selectTime,
|
51
|
-
}}
|
52
|
-
updateQuery={action('updateQuery')}
|
53
|
-
/>
|
54
|
-
);
|
55
|
-
};
|
@@ -1,56 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import { number, select, action } from '@theforeman/stories';
|
3
|
-
|
4
|
-
import { withCardsDecorator } from '../../../../../../../stories/decorators';
|
5
|
-
|
6
|
-
import {
|
7
|
-
TASKS_DASHBOARD_AVAILABLE_QUERY_MODES,
|
8
|
-
TASKS_DASHBOARD_AVAILABLE_TIMES,
|
9
|
-
TASKS_DASHBOARD_AVAILABLE_QUERY_STATES,
|
10
|
-
} from '../../../../TasksDashboardConstants';
|
11
|
-
import RunningTasksCard from './RunningTasksCard';
|
12
|
-
|
13
|
-
export default {
|
14
|
-
title: 'TasksDashboard/TasksCardsGrid/Cards/RunningTasksCard',
|
15
|
-
component: RunningTasksCard,
|
16
|
-
decorators: [withCardsDecorator],
|
17
|
-
parameters: {
|
18
|
-
centered: { disable: true },
|
19
|
-
},
|
20
|
-
};
|
21
|
-
|
22
|
-
export const Basic = () => {
|
23
|
-
const selectTime = select(
|
24
|
-
'time',
|
25
|
-
TASKS_DASHBOARD_AVAILABLE_TIMES,
|
26
|
-
RunningTasksCard.defaultProps.time
|
27
|
-
);
|
28
|
-
|
29
|
-
const selectMode = select(
|
30
|
-
'mode',
|
31
|
-
{ ...TASKS_DASHBOARD_AVAILABLE_QUERY_MODES, NONE: 'none', TOTAL: null },
|
32
|
-
'none'
|
33
|
-
);
|
34
|
-
return (
|
35
|
-
<RunningTasksCard
|
36
|
-
data={{
|
37
|
-
last: number('data.last', 3),
|
38
|
-
older: number('data.older', 5),
|
39
|
-
}}
|
40
|
-
time={selectTime}
|
41
|
-
query={{
|
42
|
-
state: select(
|
43
|
-
'query.state',
|
44
|
-
{
|
45
|
-
...TASKS_DASHBOARD_AVAILABLE_QUERY_STATES,
|
46
|
-
NONE: null,
|
47
|
-
},
|
48
|
-
TASKS_DASHBOARD_AVAILABLE_QUERY_STATES.RUNNING
|
49
|
-
),
|
50
|
-
mode: selectMode,
|
51
|
-
time: selectTime,
|
52
|
-
}}
|
53
|
-
updateQuery={action('updateQuery')}
|
54
|
-
/>
|
55
|
-
);
|
56
|
-
};
|
@@ -1,33 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import { number, select, action } from '@theforeman/stories';
|
3
|
-
|
4
|
-
import { withCardsDecorator } from '../../../../../../../stories/decorators';
|
5
|
-
|
6
|
-
import { TASKS_DASHBOARD_AVAILABLE_QUERY_STATES } from '../../../../TasksDashboardConstants';
|
7
|
-
import ScheduledTasksCard from './ScheduledTasksCard';
|
8
|
-
|
9
|
-
export default {
|
10
|
-
title: 'TasksDashboard/TasksCardsGrid/Cards/ScheduledTasksCard',
|
11
|
-
component: ScheduledTasksCard,
|
12
|
-
decorators: [withCardsDecorator],
|
13
|
-
parameters: {
|
14
|
-
centered: { disable: true },
|
15
|
-
},
|
16
|
-
};
|
17
|
-
|
18
|
-
export const Basic = () => {
|
19
|
-
const selectState = select(
|
20
|
-
'query.state',
|
21
|
-
{ ...TASKS_DASHBOARD_AVAILABLE_QUERY_STATES, NONE: 'none' },
|
22
|
-
'none'
|
23
|
-
);
|
24
|
-
return (
|
25
|
-
<ScheduledTasksCard
|
26
|
-
data={number('data', 1)}
|
27
|
-
query={{
|
28
|
-
state: selectState,
|
29
|
-
}}
|
30
|
-
updateQuery={action('updateQuery')}
|
31
|
-
/>
|
32
|
-
);
|
33
|
-
};
|
@@ -1,72 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import { number, select, action } from '@theforeman/stories';
|
3
|
-
|
4
|
-
import { withCardsDecorator } from '../../../../../../../stories/decorators';
|
5
|
-
|
6
|
-
import {
|
7
|
-
TASKS_DASHBOARD_AVAILABLE_TIMES,
|
8
|
-
TASKS_DASHBOARD_AVAILABLE_QUERY_STATES,
|
9
|
-
TASKS_DASHBOARD_AVAILABLE_QUERY_RESULTS,
|
10
|
-
TASKS_DASHBOARD_AVAILABLE_QUERY_MODES,
|
11
|
-
} from '../../../../TasksDashboardConstants';
|
12
|
-
import StoppedTasksCard from './StoppedTasksCard';
|
13
|
-
|
14
|
-
export default {
|
15
|
-
title: 'TasksDashboard/TasksCardsGrid/Cards/StoppedTasksCard',
|
16
|
-
component: StoppedTasksCard,
|
17
|
-
decorators: [withCardsDecorator],
|
18
|
-
parameters: {
|
19
|
-
centered: { disable: true },
|
20
|
-
},
|
21
|
-
};
|
22
|
-
|
23
|
-
export const Basic = () => {
|
24
|
-
const selectTime = select(
|
25
|
-
'time',
|
26
|
-
TASKS_DASHBOARD_AVAILABLE_TIMES,
|
27
|
-
StoppedTasksCard.defaultProps.time
|
28
|
-
);
|
29
|
-
const selectState = select(
|
30
|
-
'query.state',
|
31
|
-
{ ...TASKS_DASHBOARD_AVAILABLE_QUERY_STATES, NONE: null },
|
32
|
-
TASKS_DASHBOARD_AVAILABLE_QUERY_STATES.STOPPED
|
33
|
-
);
|
34
|
-
const selectResult = select(
|
35
|
-
'query.result',
|
36
|
-
{ ...TASKS_DASHBOARD_AVAILABLE_QUERY_RESULTS, NONE: null },
|
37
|
-
null
|
38
|
-
);
|
39
|
-
const selectMode = select(
|
40
|
-
'query.mode',
|
41
|
-
{ ...TASKS_DASHBOARD_AVAILABLE_QUERY_MODES, NONE: null },
|
42
|
-
null
|
43
|
-
);
|
44
|
-
return (
|
45
|
-
<div>
|
46
|
-
<StoppedTasksCard
|
47
|
-
data={{
|
48
|
-
error: {
|
49
|
-
total: number('errorTotal', 8),
|
50
|
-
last: number('errorLast', 1),
|
51
|
-
},
|
52
|
-
warning: {
|
53
|
-
total: number('warningTotal', 20),
|
54
|
-
last: number('warningLast', 2),
|
55
|
-
},
|
56
|
-
success: {
|
57
|
-
total: number('successTotal', 25),
|
58
|
-
last: number('successLast', 3),
|
59
|
-
},
|
60
|
-
}}
|
61
|
-
time={selectTime}
|
62
|
-
query={{
|
63
|
-
state: selectState,
|
64
|
-
result: selectResult,
|
65
|
-
mode: selectMode,
|
66
|
-
time: selectTime,
|
67
|
-
}}
|
68
|
-
updateQuery={action('updateQuery')}
|
69
|
-
/>
|
70
|
-
</div>
|
71
|
-
);
|
72
|
-
};
|
@@ -1,51 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import { number, text, select, action } from '@theforeman/stories';
|
3
|
-
|
4
|
-
import { withCardsDecorator } from '../../../../../../../stories/decorators';
|
5
|
-
|
6
|
-
import {
|
7
|
-
TASKS_DASHBOARD_AVAILABLE_QUERY_MODES,
|
8
|
-
TASKS_DASHBOARD_AVAILABLE_TIMES,
|
9
|
-
} from '../../../../TasksDashboardConstants';
|
10
|
-
import TasksDonutCard from './TasksDonutCard';
|
11
|
-
|
12
|
-
export default {
|
13
|
-
title: 'TasksDashboard/TasksCardsGrid/Cards/TasksDonutCard',
|
14
|
-
component: TasksDonutCard,
|
15
|
-
decorators: [withCardsDecorator],
|
16
|
-
parameters: {
|
17
|
-
centered: { disable: true },
|
18
|
-
},
|
19
|
-
};
|
20
|
-
|
21
|
-
export const Basic = () => {
|
22
|
-
const selectTime = select(
|
23
|
-
'time',
|
24
|
-
TASKS_DASHBOARD_AVAILABLE_TIMES,
|
25
|
-
TasksDonutCard.defaultProps.time
|
26
|
-
);
|
27
|
-
|
28
|
-
const selectMode = select(
|
29
|
-
'mode',
|
30
|
-
{ ...TASKS_DASHBOARD_AVAILABLE_QUERY_MODES, NONE: 'none' },
|
31
|
-
'none'
|
32
|
-
);
|
33
|
-
|
34
|
-
return (
|
35
|
-
<TasksDonutCard
|
36
|
-
title={text('title', 'Some Title')}
|
37
|
-
data={{
|
38
|
-
last: number('data.last', 3),
|
39
|
-
older: number('data.older', 5),
|
40
|
-
}}
|
41
|
-
time={selectTime}
|
42
|
-
query={{
|
43
|
-
state: text('query.state', 'some-state'),
|
44
|
-
mode: selectMode,
|
45
|
-
time: selectTime,
|
46
|
-
}}
|
47
|
-
wantedQueryState={text('wantedQueryState', 'wanted-state')}
|
48
|
-
updateQuery={action('updateQuery')}
|
49
|
-
/>
|
50
|
-
);
|
51
|
-
};
|
@@ -1,26 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import { number, text, select, action } from '@theforeman/stories';
|
3
|
-
|
4
|
-
import { TASKS_DONUT_CHART_FOCUSED_ON_OPTIONS_ARRAY } from './TasksDonutChartConstants';
|
5
|
-
import TasksDonutChart from './TasksDonutChart';
|
6
|
-
|
7
|
-
export default {
|
8
|
-
title: 'TasksDashboard/TasksCardsGrid/Charts/TasksDonutChart',
|
9
|
-
component: TasksDonutChart,
|
10
|
-
};
|
11
|
-
|
12
|
-
export const Basic = () => (
|
13
|
-
<TasksDonutChart
|
14
|
-
last={number('last', 3)}
|
15
|
-
older={number('older', 5)}
|
16
|
-
time={text('time', '24h')}
|
17
|
-
focusedOn={select(
|
18
|
-
'focusedOn',
|
19
|
-
TASKS_DONUT_CHART_FOCUSED_ON_OPTIONS_ARRAY,
|
20
|
-
TasksDonutChart.defaultProps.focusedOn
|
21
|
-
)}
|
22
|
-
onTotalClick={action('onTotalClick')}
|
23
|
-
onLastClick={action('onLastClick')}
|
24
|
-
onOlderClick={action('onOlderClick')}
|
25
|
-
/>
|
26
|
-
);
|
@@ -1,55 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import { object, select, action } from '@theforeman/stories';
|
3
|
-
|
4
|
-
import {
|
5
|
-
TASKS_DASHBOARD_AVAILABLE_TIMES,
|
6
|
-
TASKS_DASHBOARD_AVAILABLE_QUERY_STATES,
|
7
|
-
TASKS_DASHBOARD_AVAILABLE_QUERY_RESULTS,
|
8
|
-
TASKS_DASHBOARD_AVAILABLE_QUERY_MODES,
|
9
|
-
} from '../../TasksDashboardConstants';
|
10
|
-
import { MOCKED_DATA } from './TasksCardsGrid.fixtures';
|
11
|
-
import TasksCardsGrid from './TasksCardsGrid';
|
12
|
-
|
13
|
-
export default {
|
14
|
-
title: 'TasksDashboard/TasksCardsGrid/TasksCardsGrid',
|
15
|
-
component: TasksCardsGrid,
|
16
|
-
};
|
17
|
-
|
18
|
-
const createSelect = (name, options) =>
|
19
|
-
select(name, { ...options, NONE: 'none' }, 'none');
|
20
|
-
|
21
|
-
export const Basic = () => {
|
22
|
-
const selectTime = select(
|
23
|
-
'time',
|
24
|
-
TASKS_DASHBOARD_AVAILABLE_TIMES,
|
25
|
-
TasksCardsGrid.defaultProps.time
|
26
|
-
);
|
27
|
-
const selectState = createSelect(
|
28
|
-
'query.state',
|
29
|
-
TASKS_DASHBOARD_AVAILABLE_QUERY_STATES
|
30
|
-
);
|
31
|
-
const selectResult = createSelect(
|
32
|
-
'query.result',
|
33
|
-
TASKS_DASHBOARD_AVAILABLE_QUERY_RESULTS
|
34
|
-
);
|
35
|
-
const selectMode = createSelect(
|
36
|
-
'query.mode',
|
37
|
-
TASKS_DASHBOARD_AVAILABLE_QUERY_MODES
|
38
|
-
);
|
39
|
-
|
40
|
-
return (
|
41
|
-
<div>
|
42
|
-
<TasksCardsGrid
|
43
|
-
time={selectTime}
|
44
|
-
query={{
|
45
|
-
state: selectState,
|
46
|
-
result: selectResult,
|
47
|
-
mode: selectMode,
|
48
|
-
time: selectTime,
|
49
|
-
}}
|
50
|
-
data={object('data', MOCKED_DATA)}
|
51
|
-
updateQuery={action('updateQuery')}
|
52
|
-
/>
|
53
|
-
</div>
|
54
|
-
);
|
55
|
-
};
|
@@ -1,21 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import { object, action } from '@theforeman/stories';
|
3
|
-
|
4
|
-
import { TASKS_DASHBOARD_AVAILABLE_TIMES } from '../../TasksDashboardConstants';
|
5
|
-
import TasksLabelsRow from './TasksLabelsRow';
|
6
|
-
|
7
|
-
export default {
|
8
|
-
title: 'TasksDashboard/TasksLabelsRow',
|
9
|
-
component: TasksLabelsRow,
|
10
|
-
};
|
11
|
-
|
12
|
-
export const Basic = () => (
|
13
|
-
<TasksLabelsRow
|
14
|
-
query={object('query', {
|
15
|
-
state: 'running',
|
16
|
-
mode: 'last',
|
17
|
-
time: TASKS_DASHBOARD_AVAILABLE_TIMES.H24,
|
18
|
-
})}
|
19
|
-
updateQuery={action('updateQuery')}
|
20
|
-
/>
|
21
|
-
);
|
@@ -1,57 +0,0 @@
|
|
1
|
-
import { Meta, Story, Preview, Props, action } from '@theforeman/stories';
|
2
|
-
|
3
|
-
import { TASKS_DASHBOARD_AVAILABLE_TIMES } from '../../../../TasksDashboardConstants';
|
4
|
-
import TimeDropDown from './TimeDropDown';
|
5
|
-
|
6
|
-
<Meta
|
7
|
-
title="TasksDashboard/TasksTimeRow/TimeDropDown"
|
8
|
-
component={TimeDropDown}
|
9
|
-
/>
|
10
|
-
|
11
|
-
# TimeDropDown
|
12
|
-
|
13
|
-
Render a dropdown with the available dashboard times to render.
|
14
|
-
|
15
|
-
<Props of={TimeDropDown} />
|
16
|
-
|
17
|
-
The available-times defined as a constant at `Components/TasksDashboard/TasksDashboardConstants.js`:
|
18
|
-
|
19
|
-
```js
|
20
|
-
import { TASKS_DASHBOARD_AVAILABLE_TIMES } from './Components/TasksDashboard/TasksDashboardConstants';
|
21
|
-
```
|
22
|
-
|
23
|
-
To set the current selected time, set the `selectedTime` prop to `TASKS_DASHBOARD_AVAILABLE_TIMES.H24`.
|
24
|
-
|
25
|
-
<Preview>
|
26
|
-
<Story name="24 hours">
|
27
|
-
<TimeDropDown
|
28
|
-
id="time-period-dropdown"
|
29
|
-
selectedTime={TASKS_DASHBOARD_AVAILABLE_TIMES.H24}
|
30
|
-
onChange={action('onChange')}
|
31
|
-
/>
|
32
|
-
</Story>
|
33
|
-
</Preview>
|
34
|
-
|
35
|
-
To set the current selected time, set the `selectedTime` prop to `TASKS_DASHBOARD_AVAILABLE_TIMES.H12`.
|
36
|
-
|
37
|
-
<Preview>
|
38
|
-
<Story name="12 hours">
|
39
|
-
<TimeDropDown
|
40
|
-
id="time-period-dropdown"
|
41
|
-
selectedTime={TASKS_DASHBOARD_AVAILABLE_TIMES.H12}
|
42
|
-
onChange={action('onChange')}
|
43
|
-
/>
|
44
|
-
</Story>
|
45
|
-
</Preview>
|
46
|
-
|
47
|
-
To set the current selected time, set the `selectedTime` prop to `TASKS_DASHBOARD_AVAILABLE_TIMES.WEEK`.
|
48
|
-
|
49
|
-
<Preview>
|
50
|
-
<Story name="week">
|
51
|
-
<TimeDropDown
|
52
|
-
id="time-period-dropdown"
|
53
|
-
selectedTime={TASKS_DASHBOARD_AVAILABLE_TIMES.WEEK}
|
54
|
-
onChange={action('onChange')}
|
55
|
-
/>
|
56
|
-
</Story>
|
57
|
-
</Preview>
|
data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/TasksTimeRow.stories.js
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
/* eslint-disable react-hooks/rules-of-hooks */
|
2
|
-
import React, { useState } from 'react';
|
3
|
-
import { select, action } from '@theforeman/stories';
|
4
|
-
|
5
|
-
import { TASKS_DASHBOARD_AVAILABLE_TIMES } from '../../TasksDashboardConstants';
|
6
|
-
import TasksTimeRow from './TasksTimeRow';
|
7
|
-
|
8
|
-
export default {
|
9
|
-
title: 'TasksDashboard/TasksTimeRow',
|
10
|
-
component: TasksTimeRow,
|
11
|
-
};
|
12
|
-
|
13
|
-
export const withState = () => {
|
14
|
-
const [time, updateTime] = useState(TASKS_DASHBOARD_AVAILABLE_TIMES.H24);
|
15
|
-
|
16
|
-
return <TasksTimeRow time={time} updateTime={updateTime} />;
|
17
|
-
};
|
18
|
-
|
19
|
-
export const withKnobs = () => (
|
20
|
-
<TasksTimeRow
|
21
|
-
time={select(
|
22
|
-
'time',
|
23
|
-
TASKS_DASHBOARD_AVAILABLE_TIMES,
|
24
|
-
TASKS_DASHBOARD_AVAILABLE_TIMES.H24
|
25
|
-
)}
|
26
|
-
updateTime={action('updateTime')}
|
27
|
-
/>
|
28
|
-
);
|
29
|
-
|
30
|
-
export const with24Hours = () => (
|
31
|
-
<TasksTimeRow time={TASKS_DASHBOARD_AVAILABLE_TIMES.H24} />
|
32
|
-
);
|
33
|
-
|
34
|
-
export const with12Hours = () => (
|
35
|
-
<TasksTimeRow time={TASKS_DASHBOARD_AVAILABLE_TIMES.H12} />
|
36
|
-
);
|
37
|
-
|
38
|
-
export const withWeek = () => (
|
39
|
-
<TasksTimeRow time={TASKS_DASHBOARD_AVAILABLE_TIMES.WEEK} />
|
40
|
-
);
|
@@ -1 +0,0 @@
|
|
1
|
-
export * from './withCardsDecorator';
|
@@ -1,14 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
|
3
|
-
export const withCardsDecorator = storyFn => (
|
4
|
-
<div
|
5
|
-
style={{
|
6
|
-
width: '100%',
|
7
|
-
height: '100vh',
|
8
|
-
backgroundColor: '#F5F5F5',
|
9
|
-
padding: '50px',
|
10
|
-
}}
|
11
|
-
>
|
12
|
-
<div style={{ width: '300px', margin: 'auto' }}>{storyFn()}</div>
|
13
|
-
</div>
|
14
|
-
);
|