diff --git a/app/assets/stylesheets/kpm/kpm.css b/app/assets/stylesheets/kpm/kpm.css index e8b0f4c..3377040 100644 --- a/app/assets/stylesheets/kpm/kpm.css +++ b/app/assets/stylesheets/kpm/kpm.css @@ -4,3 +4,592 @@ * the top of the compiled file, but it's generally better to create a new file per style scope. *= require_tree . */ + +/* app/views/kpm/nodes_info/_logs_table.html.erb */ + +.form-api-search input { + width: 20rem; + height: 2.2rem; + padding: 0.3rem 1rem; + border: 0.0625rem solid #e5e7eb; + border-radius: 0.375rem; + font-weight: 500; + font-size: 0.875rem; + line-height: 1.25rem; + color: #414651; + outline: none; +} + +#logs-table_filter input { + width: 20rem; + height: 2.2rem; + padding: 0.3rem 1rem; + border: 0.0625rem solid #e5e7eb; + border-radius: 0.375rem; + font-weight: 500; + font-size: 0.875rem; + line-height: 1.25rem; + color: #414651; + outline: none; +} + +#logs-table_filter input:focus { + border: 0.0625rem solid #1a73e8; + outline: none; + box-shadow: 0; +} + +/* app/views/kpm/nodes_info/_nodes_table.html.erb */ + +.nodes-info b { + font-weight: 600; + font-size: 0.875rem; + line-height: 1.25rem; + color: #414651; +} + +.nodes-info p, +.nodes-info p a { + font-weight: 400; + font-size: 0.875rem; + line-height: 1.25rem; + margin-bottom: 0; + color: #717680; + text-decoration: none; +} + +/* app/views/kpm/nodes_info/_official_plugins.html.erb */ + +.official-plugins-data .official-plugin { + padding: 1rem 0; + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 0.0625rem solid #e9eaeb; +} + +.official-plugins-data .official-plugin:last-child { + border-bottom: none; +} + +.official-plugins-data .official-plugin-icon { + width: 2.75rem; + height: 2.75rem; + border: 0.0625rem solid #e9eaeb; + border-radius: 0.375rem; + padding: 0.25rem; + margin-right: 1rem; +} + +.official-plugins-data .official-plugin h4 { + font-weight: 600; + font-size: 1rem; + line-height: 1.5rem; + margin-bottom: 0; + color: #414651; +} + +.official-plugins-data .official-plugin p { + font-weight: 400; + font-size: 0.875rem; + line-height: 1.25rem; + color: #535862; + margin: 0; +} + +.official-plugins-data .dots-menu { + padding: 0 !important; + width: 1.25rem; + height: 1.25rem; + background-color: transparent !important; + border: none !important; +} + +.official-plugins-data .dots-menu:hover { + background-color: transparent !important; +} + +.official-plugins-data .label-success { + display: inline-flex; + align-items: center; + gap: 0.125rem; + padding: 0.125rem 0.5rem; + border-radius: 3.90234375rem; + background-color: #ecfdf3; + border: 0.0625rem solid #dcfae6; + color: #067647 !important; + font-weight: 500; + font-size: 0.75rem; + line-height: 1.125rem; + margin: 0; +} + +.official-plugins-data .label-danger { + display: inline-flex; + align-items: center; + gap: 0.125rem; + padding: 0.125rem 0.5rem; + border-radius: 3.90234375rem; + background-color: #fef3f2; + border: 0.0625rem solid #fee4e2; + color: #b42318 !important; + font-weight: 500; + font-size: 0.75rem; + line-height: 1.125rem; + margin: 0; +} + +/* Toggle Switch */ +.official-plugins-data .switch { + position: relative; + display: inline-block; + width: 2.5rem; + height: 1.25rem; + margin-left: 0.75rem; +} + +.official-plugins-data .switch input { + opacity: 0; + width: 0; + height: 0; +} + +.official-plugins-data .slider { + position: absolute; + cursor: pointer; + background-color: #ccc; + transition: 0.4s; + top: 0; + left: 0; + right: 0; + bottom: 0; + border-radius: 1.25rem; +} + +.official-plugins-data .slider:before { + position: absolute; + content: ""; + height: 0.875rem; + width: 0.875rem; + left: 0.1875rem; + bottom: 0.1875rem; + background-color: white; + transition: 0.4s; + border-radius: 50%; +} + +.official-plugins-data input:checked + .slider { + background-color: #1a73e8; +} + +.official-plugins-data input:checked + .slider:before { + transform: translateX(1.25rem); +} + +.official-plugins-data .dropdown { + position: relative; + display: inline-block; + margin-left: 0.75rem; +} + +.official-plugins-data .dots-menu { + background: transparent; + border: none; + cursor: pointer; + font-size: 1.125rem; + color: #6b7280; +} + +.official-plugins-data .dropdown-content { + display: none; + position: absolute; + right: 0; + background-color: #fff; + min-width: 7.5rem; + box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.15); + border-radius: 0.375rem; + overflow: hidden; + padding: 0.25rem 0; + z-index: 1000; +} + +.official-plugins-data .dropdown-content a { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 0.625rem; + font-size: 0.875rem; + text-decoration: none; + font-weight: 500; + line-height: 1.25rem; + color: #414651; +} + +.official-plugins-data .dropdown-content a:hover { + background-color: #f2f2f2; +} + +.official-plugins-data .dropdown.show .dropdown-content { + display: block; +} + +.official-plugins-data .toggle-icon.playpause { + display: inline-block; + width: 2.5rem; + height: 1.25rem; + border-radius: 9999px; + position: relative; + margin-left: 0.75rem; + background-color: #f5f5f5; + transition: background-color 0.3s ease; +} + +.official-plugins-data .toggle-icon.playpause::before { + content: ""; + position: absolute; + top: 0.125rem; + left: 0.125rem; + width: 1rem; + height: 1rem; + background-color: #fff; + border-radius: 50%; + transition: transform 0.3s ease; +} + +.official-plugins-data .toggle-icon.playpause.running { + background-color: #1a73e8; +} + +.official-plugins-data .toggle-icon.playpause.running::before { + transform: translateX(1.25rem); +} + +.plugin-link.loading { + pointer-events: none; + opacity: 1; +} + +.plugin-link.toggle-icon.loading { + position: relative; +} + +.plugin-link.toggle-icon.loading::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 0.75rem; + height: 0.75rem; + margin: -0.375rem 0 0 -0.375rem; + border: 0.125rem solid #1a73e8; + border-top: 0.125rem solid transparent; + border-radius: 50%; + animation: spin 1s linear infinite; + z-index: 10; +} + +.plugin-link:not(.toggle-icon).loading i { + animation: spin 1s linear infinite; +} + +.official-plugin.loading { + position: relative; +} + +.official-plugin.loading::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(255, 255, 255, 0.8); + z-index: 5; +} + +.official-plugin.loading::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-size: 1.5rem; + z-index: 10; + animation: pulse 1.5s ease-in-out infinite; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +@keyframes pulse { + 0%, 100% { opacity: 0.7; } + 50% { opacity: 1; } +} + +/* app/views/kpm/plugins/index.html.erb */ + +.kpm-plugins-index .official-plugins .official-plugins-header { + display: flex; + align-items: start; + justify-content: space-between; + padding: 0; + border-bottom: 0.0625rem solid #e9eaeb; +} + +.kpm-plugins-index .official-plugins .official-plugins-header h2 { + font-weight: 600; + font-size: 1.125rem; + line-height: 1.75rem; + color: #414651; + margin-bottom: 1.25rem; +} + +.kpm-plugins-index .official-plugins #plugins-table tr td:last-child { + text-align: end; +} + +.kpm-plugins-index .official-plugins #plugins-table tr td:last-child a { + text-decoration: none; + color: #175cd3; +} + +.kpm-plugins-index .upload-plugin-title { + display: flex; + align-items: center; + gap: 1rem; + font-weight: 600; + font-size: 1.125rem; + line-height: 1.75rem; + letter-spacing: 0; + color: #1b1c1e; + padding: 1rem 0; + margin-bottom: 1.5rem; +} + +.kpm-plugins-index .icon-container { + display: inline-flex; + justify-content: center; + align-items: center; + border: 0.0625rem solid #d5d7da; + border-radius: 0.375rem; + width: 2.5rem; + height: 2.5rem; + padding: 0.25rem; +} + +.kpm-plugins-index .icon-container img { + width: 1rem; + height: 1rem; +} + +.kpm-plugins-index table { + overflow-x: auto; + min-width: 100%; +} + +.kpm-plugins-index table th { + padding: 0.375rem 0.75rem !important; + padding-right: 2rem !important; + font-weight: 500; + font-size: 0.875rem; + color: #717680; + text-transform: capitalize; + position: relative; +} + +.kpm-plugins-index table td { + font-weight: 500 !important; + font-size: 0.875rem !important; + padding: 1rem 0.5rem !important; + color: #535862 !important; + text-transform: capitalize !important; +} + +.kpm-plugins-index table thead tr th:not(:last-child)::after, +.kpm-plugins-index table thead tr th:not(:last-child)::before { + content: "" !important; + display: inline-block !important; + width: 0.75rem !important; + height: 0.75rem !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 0.75rem 0.75rem !important; + position: absolute !important; + left: 4rem !important; +} + +.kpm-plugins-index table thead tr th:not(:last-child)::after { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 5.5L6 2.5L9 5.5' stroke='%23A4A7AE' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); + top: 45% !important; + transform: translateY(-50%) !important; +} + +.kpm-plugins-index table thead tr th:not(:last-child)::before { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 6.5L6 9.5L9 6.5' stroke='%23A4A7AE' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); + bottom: 45% !important; + transform: translateY(50%) !important; +} + +/* app/views/kpm/nodes_info/index.html.erb */ + +.kpm-nodes-info-index .admin-tenant-details-header { + display: flex; + align-items: start; + justify-content: space-between; + padding: 0; + border-bottom: 0.0625rem solid #e9eaeb; +} + +.kpm-nodes-info-index .admin-tenant-details-header h2 { + font-weight: 600; + font-size: 1.125rem; + color: #414651; + margin-bottom: 1.25rem; +} + +.kpm-nodes-info-index .plugin-tabs { + background-color: #fafafa; + border: 0.0625rem solid #e9eaeb; + border-radius: 0.375rem; + display: flex; + align-items: center; + gap: 0.25rem; + margin-bottom: 1.5rem; + padding: 0.25rem; + width: fit-content; + height: 2.5rem; +} + +.kpm-nodes-info-index .plugin-tabs button { + background: transparent; + border: none; + font-weight: 500; + font-size: 0.875rem; + color: #717680; + padding: 0.375rem 0.75rem; + border-radius: 0.25rem; + cursor: pointer; + height: 2rem; + display: flex; + align-items: center; +} + +.kpm-nodes-info-index .plugin-tabs .activelink { + color: #414651; + background-color: #ffffff; + box-shadow: 0 0.0625rem 0.188rem rgba(10, 13, 18, 0.1); +} + +.kpm-nodes-info-index table { + overflow-x: auto; + min-width: 100%; +} + +.kpm-nodes-info-index table th { + padding: 0.375rem 0.75rem !important; + font-weight: 500; + font-size: 0.875rem; + color: #717680; + text-transform: capitalize; +} + +.kpm-nodes-info-index table td { + font-weight: 500 !important; + font-size: 0.875rem !important; + padding: 1rem 0.5rem !important; + color: #535862 !important; + text-transform: capitalize !important; +} + +/* app/views/kpm/plugins/_form.html.erb */ + +.upload-plugin-form .control-label { + font-size: 0.875rem !important; + font-weight: 500 !important; + line-height: 1.25rem !important; + color: #414651 !important; +} + +.upload-plugin-form .form-group.d-flex.pb-3 .form-control { + height: 2.5rem; + border-radius: 0.375rem; +} + +.upload-plugin-form .form-group.d-flex .form-control:focus { + outline: none; + box-shadow: none; +} + +.upload-plugin-form .toggle-segment { + display: flex; + align-items: center; + border: 0.0625rem solid #d5d7da; + width: fit-content; + border-radius: 0.375rem; + overflow: hidden; + font-size: 0.875rem; +} + +.upload-plugin-form .toggle-segment .radio label { + display: flex; + align-items: center; + padding: 0.625rem 1rem !important; + cursor: pointer; + color: #414651; + border-right: 0.0625rem solid #d5d7da; + font-weight: 500; + font-size: 0.875rem; + line-height: 1.25rem; + letter-spacing: 0; +} + +.upload-plugin-form .toggle-segment .radio:last-child label { + border-right: none; +} + +.upload-plugin-form .toggle-segment .radio label input[type="radio"] { + appearance: none; + -webkit-appearance: none; + -moz-appearance: none; + cursor: pointer; + position: relative; + outline: none; + border: 0; + background-color: transparent; + margin: 0; + padding: 0; +} + +.upload-plugin-form + .toggle-segment + .radio + label + input[type="radio"]:checked::before { + content: ""; + position: absolute; + top: 0.25rem; + left: 0; + width: 0.5rem; + height: 0.5rem; + background-color: #17b26a; + border-radius: 50%; +} + +.upload-plugin-form + .toggle-segment + .radio + label:has(input[type="radio"]:checked) { + background-color: #fafafa; + font-weight: 600; + color: #252b37; + gap: 1rem; +} + +.upload-plugin-form + .toggle-segment + .radio + label:not(:has(input[type="radio"]:checked)) { + gap: 0; +} diff --git a/app/views/kaui/components/breadcrumb/_breadcrumb.html.erb b/app/views/kaui/components/breadcrumb/_breadcrumb.html.erb new file mode 100644 index 0000000..094332f --- /dev/null +++ b/app/views/kaui/components/breadcrumb/_breadcrumb.html.erb @@ -0,0 +1,8 @@ +<%# + This is a placeholder breadcrumb component for standalone gem usage. + + This placeholder prevents "missing template" errors when running + the gem independently during development or testing. +%> + + diff --git a/app/views/kaui/components/button/_button.html.erb b/app/views/kaui/components/button/_button.html.erb new file mode 100644 index 0000000..46a1199 --- /dev/null +++ b/app/views/kaui/components/button/_button.html.erb @@ -0,0 +1,8 @@ +<%# + This is a placeholder button component for standalone gem usage. + + This placeholder prevents "missing template" errors when running + the gem independently during development or testing. +%> + + diff --git a/app/views/kaui/layouts/kaui_setting_sidebar.html.erb b/app/views/kaui/layouts/kaui_setting_sidebar.html.erb new file mode 100644 index 0000000..1d67998 --- /dev/null +++ b/app/views/kaui/layouts/kaui_setting_sidebar.html.erb @@ -0,0 +1,8 @@ +<%# + This is a placeholder sidebar component for standalone gem usage. + + This placeholder prevents "missing template" errors when running + the gem independently during development or testing. +%> + + diff --git a/app/views/kpm/nodes_info/_logs_table.html.erb b/app/views/kpm/nodes_info/_logs_table.html.erb index 8a59309..92da47c 100644 --- a/app/views/kpm/nodes_info/_logs_table.html.erb +++ b/app/views/kpm/nodes_info/_logs_table.html.erb @@ -1,4 +1,4 @@ - +
@@ -12,9 +12,17 @@ <%= form_tag url_for, :method => 'get', :format => :js, :id => 'kb_host-form', :class => 'form-horizontal', :style => 'display: none;' do %>
-
+
<% end %> diff --git a/app/views/kpm/nodes_info/_nodes_table.html.erb b/app/views/kpm/nodes_info/_nodes_table.html.erb index 638d9e8..f805f62 100644 --- a/app/views/kpm/nodes_info/_nodes_table.html.erb +++ b/app/views/kpm/nodes_info/_nodes_table.html.erb @@ -1,66 +1,32 @@ -
Time
- - - - - - - - - - - <%- has_kpm_plugin = kpm_plugin_installed?(nodes_info) %> - <% nodes_info.each do |node_info| %> - - - - - - - - <% end %> - -
NodeUptimeKill Bill versionDependenciesPlugins
<%= node_info.node_name %> - <% unless node_info.boot_time.blank? %> - <%= time_ago_in_words(DateTime.parse(node_info.boot_time)) %> - <% end %> - <%= node_info.kb_version %> -
    -
  • API: <%= node_info.api_version %>
  • -
  • Plugin API: <%= node_info.plugin_api_version %>
  • -
  • Platform: <%= node_info.platform_version %>
  • -
  • Commons: <%= node_info.common_version %>
  • -
-
- <% unless (node_info.plugins_info || []).empty? %> -
    - <% node_info.plugins_info.each do |plugin_info| %> -
  • - <%= plugin_info.plugin_name %> <%= plugin_info.version %> <%= plugin_info.state %> - <% if plugin_info.state == 'RUNNING' %> - <%-# If there is not plugin_key, this is most likely a pure OSGI bundle. In that case, we don't want to allow stopping it as we would lose track of it (once it's removed from the OSGI bundle registry, we don't know about it anymore) -%> - <% unless plugin_info.plugin_key.nil? %> - <%= link_to ''.html_safe, plugin_stop_path(:plugin_key => plugin_info.plugin_key, :plugin_name => plugin_info.plugin_name, :plugin_version => plugin_info.version), :method => :post, :title => 'Stop', :remote => true, :class => 'plugin-link' %> - <% end %> - <%= link_to ''.html_safe, plugin_restart_path(:plugin_key => plugin_info.plugin_key, :plugin_name => plugin_info.plugin_name, :plugin_version => plugin_info.version), :method => :post, :title => 'Restart', :remote => true, :class => 'plugin-link' %> - <% elsif plugin_info.state == 'INSTALLED' || plugin_info.state == 'STOPPED' %> - <%= link_to ''.html_safe, plugin_start_path(:plugin_key => plugin_info.plugin_key, :plugin_name => plugin_info.plugin_name, :plugin_version => plugin_info.version), :method => :post, :title => 'Start', :remote => true, :class => 'plugin-link' %> - <% end %> - <% if !plugin_info.version.nil? && has_kpm_plugin %> - <%= link_to ''.html_safe, plugin_uninstall_path(:plugin_key => plugin_info.plugin_key, :plugin_name => plugin_info.plugin_name, :plugin_version => plugin_info.version), :method => :post, :title => 'Uninstall', :remote => true, :class => 'plugin-link' %> - <% end %> -
  • - <% end %> -
- <% end %> -
- -<%= javascript_tag do %> - $(document).ready(function() { - $('#nodes-table').dataTable({ - "dom": "t", - "paging": false, - "ordering": false - }); - }); +<%- has_kpm_plugin = kpm_plugin_installed?(nodes_info) %> +<% nodes_info.each do |node_info| %> +
+
+
+ Node +

+ <%= node_info.node_name %> +

+
+
+ Kill Bill Version +

<%= node_info.kb_version %>

+
+
+
+ <% unless node_info.boot_time.blank? %> +
+ Uptime +

<%= time_ago_in_words(DateTime.parse(node_info.boot_time)) %>

+
+ <% end %> +
+ Dependencies +

API: <%= node_info.api_version %>

+

Plugin API: <%= node_info.plugin_api_version %>

+

Platform: <%= node_info.platform_version %>

+

Commons: <%= node_info.common_version %>

+
+
+
<% end %> diff --git a/app/views/kpm/nodes_info/_official_plugins.html.erb b/app/views/kpm/nodes_info/_official_plugins.html.erb new file mode 100644 index 0000000..0cd0379 --- /dev/null +++ b/app/views/kpm/nodes_info/_official_plugins.html.erb @@ -0,0 +1,75 @@ +
+ <%- has_kpm_plugin = kpm_plugin_installed?(nodes_info) %> + <% nodes_info.each do |node_info| %> + <% unless (node_info.plugins_info || []).empty? %> + <% node_info.plugins_info.each do |plugin_info| %> +
+
+
+
+

<%= plugin_info.plugin_name %>

+

<%= plugin_info.version %>

+
+
+
+ <%= plugin_info.state %> + <% if plugin_info.state == 'RUNNING' %> + <%= link_to '', plugin_stop_path(:plugin_key => plugin_info.plugin_key, :plugin_name => plugin_info.plugin_name, :plugin_version => plugin_info.version), :method => :post, :title => 'Stop', :remote => true, :class => 'plugin-link toggle-icon playpause running' %> + <% elsif plugin_info.state == 'INSTALLED' || plugin_info.state == 'STOPPED' %> + <%= link_to '', plugin_start_path(:plugin_key => plugin_info.plugin_key, :plugin_name => plugin_info.plugin_name, :plugin_version => plugin_info.version), :method => :post, :title => 'Start', :remote => true, :class => 'plugin-link toggle-icon playpause stopped' %> + <% end %> + <% if plugin_info.state == 'RUNNING' %> + + <% end %> +
+
+ <% end %> + <% end %> + <% end %> +
+ +<%= javascript_tag do %> + function toggleDropdown(button) { + const dropdown = button.closest(".dropdown"); + dropdown.classList.toggle("show"); + + // Close other dropdowns + document.querySelectorAll(".dropdown").forEach(d => { + if (d !== dropdown) d.classList.remove("show"); + }); + } + + document.addEventListener("click", function (e) { + if (!e.target.closest(".dropdown")) { + document.querySelectorAll(".dropdown").forEach(d => d.classList.remove("show")); + } + }); + +<% end %> \ No newline at end of file diff --git a/app/views/kpm/nodes_info/index.html.erb b/app/views/kpm/nodes_info/index.html.erb index a16de23..c63161c 100644 --- a/app/views/kpm/nodes_info/index.html.erb +++ b/app/views/kpm/nodes_info/index.html.erb @@ -1,68 +1,130 @@ -