From 38d026d3e4778178dfa4f89651c17a8167cbd28d Mon Sep 17 00:00:00 2001 From: jrgriffiniii <1443986+jrgriffiniii@users.noreply.github.com> Date: Tue, 17 Dec 2024 11:37:08 -0500 Subject: [PATCH] Prototyping an initial implementation for the disk storage quota usage component in the Project Show View --- app/assets/stylesheets/_projects.scss | 159 +++++++++--------- app/assets/stylesheets/_variables.scss | 6 +- app/javascript/entrypoints/pulDataTables.js | 4 +- app/models/project.rb | 6 +- app/presenters/project_show_presenter.rb | 102 ++++++++++- .../_project_details_heading.html.erb | 106 +++++++----- spec/system/project_details_spec.rb | 9 + spec/system/project_spec.rb | 65 +++++-- 8 files changed, 326 insertions(+), 131 deletions(-) diff --git a/app/assets/stylesheets/_projects.scss b/app/assets/stylesheets/_projects.scss index cfca9070..373670d2 100644 --- a/app/assets/stylesheets/_projects.scss +++ b/app/assets/stylesheets/_projects.scss @@ -3,94 +3,103 @@ @import "bootstrap"; #project-details-heading { - margin-bottom: 1.5em; + margin-bottom: 1.5em; - .status { - float: right; - border-radius: 0.5em; - padding: 0.5em 0.75em 0.5em 0.5em; - text-transform: capitalize; - font-weight: bold; - } + .status { + float: right; + border-radius: 0.5em; + padding: 0.5em 0.75em 0.5em 0.5em; + text-transform: capitalize; + font-weight: bold; + } - .status::before { - content: ""; - width: 20px; - height: 20px; - } + .status::before { + content: ""; + width: 20px; + height: 20px; + } - .active { - background: url("status_active.svg") no-repeat; - background-color: $status-info; - background-position: left; - padding-left: 20px; - color: $blue-dark; - } + .active { + background: url("status_active.svg") no-repeat; + background-color: $status-info; + background-position: left; + padding-left: 20px; + color: $blue-dark; + } - .pending { - background: url("status_pending.svg") no-repeat; - background-color: $status-warning; - background-position: left; - padding-left: 20px; - color: $yellow-dark; + .pending { + background: url("status_pending.svg") no-repeat; + background-color: $status-warning; + background-position: left; + padding-left: 20px; + color: $yellow-dark; - } + } - .approved { - background: url("status_approved.svg") no-repeat; - background-color: $status-success; - background-position: left; - padding-left: 20px; - color: $green-dark; - } + .approved { + background: url("status_approved.svg") no-repeat; + background-color: $status-success; + background-position: left; + padding-left: 20px; + color: $green-dark; + } - .rejected { - background: url("status_rejected.svg") no-repeat; - background-color: $status-error; - background-position: left; - padding-left: 20px; - color: $red-darker; - } - - #project-description { - color: $black; - font-family: "Libre Franklin"; - font-size: 1em; - font-style: normal; - font-weight: 400; - line-height: 1.5em; - } + .rejected { + background: url("status_rejected.svg") no-repeat; + background-color: $status-error; + background-position: left; + padding-left: 20px; + color: $red-darker; + } + + #project-description { + color: $black; + font-family: "Libre Franklin"; + font-size: 1em; + font-style: normal; + font-weight: 400; + line-height: 1.5em; + } - .truncate { - overflow: hidden; - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 2; - } + .truncate { + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + } - a#show-more-less-link { - color: $gray-60; - } + a#show-more-less-link { + color: $gray-60; + } + + .label { + font-weight: bold; + } + + .date-and-data-info ul { + padding: 0; + } + + .date-and-data-info li { + float: left; + list-style-type: none; + line-height: 1em; + } + + .date-and-data-info li:first-child:after { + content: "|"; + padding: 0 .5em; + } - .label { + .storage-quota { + border-radius: 0.5rem; + &-total { font-weight: bold; - } - - .date-and-data-info ul { - padding: 0; } - - .date-and-data-info li { - float: left; - list-style-type: none; - line-height: 1em; + @include media-breakpoint-up(lg) { + max-width: 75%; } - - .date-and-data-info li:first-child:after { - content: "|"; - padding: 0 .5em; - } - + } } .latest-download-link { diff --git a/app/assets/stylesheets/_variables.scss b/app/assets/stylesheets/_variables.scss index d7ea178b..025f93eb 100644 --- a/app/assets/stylesheets/_variables.scss +++ b/app/assets/stylesheets/_variables.scss @@ -29,4 +29,8 @@ $status-error: #F3D9D9; $status-warning: #FFF6DF; $status-info: #E6EEF8; -$libre-franklin: "Libre Franklin", sans-serif; \ No newline at end of file +$libre-franklin: "Libre Franklin", sans-serif; + +$progress-bar-bg: $princeton-orange; +$progress-height: 2rem; + diff --git a/app/javascript/entrypoints/pulDataTables.js b/app/javascript/entrypoints/pulDataTables.js index 759e47d8..47b7a117 100644 --- a/app/javascript/entrypoints/pulDataTables.js +++ b/app/javascript/entrypoints/pulDataTables.js @@ -19,7 +19,9 @@ export function setupTable(tableId) { // If we have a table initialize it with DataTables if (table) { - table.dataTable(datasetOptions); + if (table.dataTable) { + table.dataTable(datasetOptions); + } } } diff --git a/app/models/project.rb b/app/models/project.rb index d56bb4b6..0da682e0 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -212,8 +212,12 @@ def asset_count(session_id:) values.fetch(:total_file_count, 0) end + def self.default_storage_unit + "KB" + end + def self.default_storage_usage - "0 KB" + "0 {default_storage_unit}" end def storage_usage(session_id:) diff --git a/app/presenters/project_show_presenter.rb b/app/presenters/project_show_presenter.rb index db4ce236..0f938bf0 100644 --- a/app/presenters/project_show_presenter.rb +++ b/app/presenters/project_show_presenter.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class ProjectShowPresenter delegate "id", "in_mediaflux?", "mediaflux_id", "pending?", "status", "title", to: :project - delegate "description", "project_id", "storage_capacity", "storage_performance_expectations", "project_purpose", to: :project_metadata + delegate "description", "project_id", "storage_performance_expectations", "project_purpose", to: :project_metadata attr_reader :project, :project_metadata @@ -30,4 +30,104 @@ def data_manager def project_directory project.project_directory.gsub(Mediaflux::Connection.hidden_root, "") end + + # This might not be needed + def storage_unit + return Project.default_storage_unit unless project.metadata.key?("storage_capacity") + + root = project.metadata["storage_capacity"] + return Project.default_storage_unit unless root.key?("unit") + + units = root["unit"] + return Project.default_storage_unit unless units.key?("approved") + + units["approved"] + end + + # This might not be needed + def storage_unit_tb? + storage_unit == "TB" + end + + # This might not be needed + def storage_unit_gb? + storage_unit == "GB" + end + + # This might not be needed + def storage_unit_mb? + storage_unit == "MB" + end + + # This might not be needed + def divisor + if storage_unit_tb? + 1024.0 + elsif storage_unit_gb? + 1.0 + elsif storage_unit_mb? + 1.0/(1024.0**1) + else + 1.0/(1024.0**2) + end + end + + # Usage is in MB + def default_usage_divisor + 1.0/(1024.0**1) + end + + # Capacity is in bytes + def default_capacity_divisor + 1.0/(1024.0**3) + end + + # This assumed that the storage usage is recorded in the same units as the units specified in the StorageCapacity metadata + def storage_usage(session_id:) + persisted = project.storage_usage_raw(session_id: session_id) + value = persisted.to_f + + value*default_usage_divisor + end + + def formatted_storage_usage(session_id:) + value = storage_usage(session_id:) + format("%.3f", value) + end + + def storage_capacity(session_id:) + persisted = project.storage_capacity_raw(session_id: session_id) + value = persisted.to_f + + value*default_capacity_divisor + end + + def formatted_storage_capacity(session_id:) + value = storage_capacity(session_id:) + format("%.3f", value) + end + + def storage_remaining(session_id:) + capacity = storage_capacity(session_id:) + return 0.0 if capacity.zero? + + usage = storage_usage(session_id:) + + capacity - usage + end + + def formatted_storage_remaining(session_id:) + value = storage_remaining(session_id:) + format("%.3f", value) + end + + def storage_usage_percent(session_id:) + capacity = storage_capacity(session_id: session_id) + return 0.0 if capacity.zero? + + usage = storage_usage(session_id: session_id) + + value = (usage/capacity)*100.0 + format("%.1f", value) + end end diff --git a/app/views/projects/_project_details_heading.html.erb b/app/views/projects/_project_details_heading.html.erb index 9df2bcf4..6221ea53 100644 --- a/app/views/projects/_project_details_heading.html.erb +++ b/app/views/projects/_project_details_heading.html.erb @@ -1,49 +1,79 @@
-
-

<%= @project.title %>

-
-
-
- <%= @project.status %> +
+

<%= @project.title %>

+
-
-
- - -
- -
-
- <%= @project.description %> +
+
+ <%= @project.status %> +
- more... -
+
-
-
-
-
    -
  • Date Created: <%= @project.created %>
  • -
  • Last updated: <%= @project.updated %>
  • -
-
-
-
+
+
+
+
+ <%= @project.description %> +
+ more... +
-
-
-
-
    -
  • Data Sponsor: <%= @project.data_sponsor %>
  • -
  • Data Manager: <%= @project.data_manager %>
  • -
-
-
-
-
+
+
+
+
    +
  • Date Created: <%= @project.created %>
  • +
  • Last updated: <%= @project.updated %>
  • +
+
+
+
+ +
+
+
+
    +
  • Data Sponsor: <%= @project.data_sponsor %>
  • +
  • Data Manager: <%= @project.data_manager %>
  • +
+
+
+
+
+ +
+
+
+
+
+ Storage (<%= @project.formatted_storage_capacity(session_id: current_user.mediaflux_session) %> GB) +
+
+ <%= link_to "Request More", "mailto:tigerdata@princeton.edu" %> +
+
+
+
+
+
+
+
+
+ <%= @project.formatted_storage_usage(session_id: current_user.mediaflux_session) %> KB Used +
+
+ <%= @project.formatted_storage_remaining(session_id: current_user.mediaflux_session) %> GB Free +
+
+
+
+
+
+