diff --git a/apps/dashboard/app/controllers/concerns/pathable.rb b/apps/dashboard/app/controllers/concerns/directory_utils_concern.rb similarity index 59% rename from apps/dashboard/app/controllers/concerns/pathable.rb rename to apps/dashboard/app/controllers/concerns/directory_utils_concern.rb index 57947dcea..834d2bb8f 100644 --- a/apps/dashboard/app/controllers/concerns/pathable.rb +++ b/apps/dashboard/app/controllers/concerns/directory_utils_concern.rb @@ -1,4 +1,12 @@ -module Pathable +module DirectoryUtilsConcern + # Constants for sorting + ASCENDING = true + DESCENDING = false + # Constants for grouping + DIRECTORIES = true + FILES = false + DEFAULT_SORTING_PARAMS = { col: 'name', direction: ASCENDING, grouped?: true } + extend ActiveSupport::Concern def normalized_path(path) @@ -33,10 +41,41 @@ def validate_path! end end + def set_sorting_params(parameters) + @sorting_params = { + col: parameters[:col], + direction: parameters[:direction], + grouped?: parameters[:grouped?] + } + end + + def set_files + @files = @path.ls + @files = sort_by_column(@files, @sorting_params[:col], @sorting_params[:direction]) + @files = group_by_type(@files) if @sorting_params[:grouped?] + end + + def group_by_type(files) + directories = files.select { |file| file[:directory] } + files.select { |file| !file[:directory] } + end + + def sort_by_column(files, column, direction) + col = column.to_sym + sorted_files = files.sort_by do |file| + if col == :size + file[col].to_i + else + file[col].to_s.downcase + end + end + return sorted_files if direction == ASCENDING + return sorted_files.reverse + end + def posix_file? @path.is_a?(PosixFile) end - + def resolved_path raise NoMethodError, "Must implement resolved_path in #{self.class.to_s} to use Pathable concern" end diff --git a/apps/dashboard/app/controllers/files_controller.rb b/apps/dashboard/app/controllers/files_controller.rb index 502a9ed40..3edde290d 100644 --- a/apps/dashboard/app/controllers/files_controller.rb +++ b/apps/dashboard/app/controllers/files_controller.rb @@ -3,7 +3,7 @@ # The controller for all the files pages /dashboard/files class FilesController < ApplicationController include ActionController::Live - include Pathable + include DirectoryUtilsConcern before_action :strip_sendfile_headers, only: [:fs] diff --git a/apps/dashboard/app/controllers/projects_controller.rb b/apps/dashboard/app/controllers/projects_controller.rb index 958186913..5ae3ba77c 100644 --- a/apps/dashboard/app/controllers/projects_controller.rb +++ b/apps/dashboard/app/controllers/projects_controller.rb @@ -2,7 +2,7 @@ # The controller for project pages /dashboard/projects. class ProjectsController < ApplicationController - include Pathable + include DirectoryUtilsConcern # GET /projects/:id def show @@ -11,8 +11,9 @@ def show parse_path validate_path! - @files = @path.ls - + set_sorting_params(show_project_params[:sorting_params] || default_sorting_params) + set_files + if @project.nil? respond_to do |format| message = I18n.t('dashboard.jobs_project_not_found', project_id: project_id) @@ -34,20 +35,41 @@ def show end end end - + # GET /projects/:project_id/files/*filepath - def files - @project = Project.find(files_params[:project_id]) - parse_path(files_params[:filepath]) + def directory + @project = Project.find(directory_params[:project_id]) + parse_path("#{directory_params[:dir_path]}") validate_path! - Rails.logger.debug("\n\n\n==============================================================") - Rails.logger.debug("ProjectsController#files: request: #{request.methods.sort}") - Rails.logger.debug("==============================================================\n\n\n") - @files = @path.ls - - render(partial: 'projects/directory', locals: { project_id: @project.id, path: @path, files: @files }) + set_sorting_params(directory_params[:sorting_params] || DEFAULT_SORTING_PARAMS) + set_files + render( partial: 'projects/directory', + locals: { project: @project, + path: @path, + files: @files, + sorting_params: @sorting_params + } + ) end + def file + @project = Project.find(file_params[:project_id]) + parse_path(file_params[:path]) + validate_path! + @file = File.open(@path.to_s, "r") do |file| + file.read + end + + render( partial: 'projects/file', + locals: { + project: @project, + path: @path, + file: @file, + sorting_params: file_params[:sorting_params] + } + ) + end + # GET /projects def index @projects = Project.all @@ -192,6 +214,10 @@ def resolved_fs 'fs' end + def default_sorting_params + DEFAULT_SORTING_PARAMS + end + def templates Project.templates.map do |project| label = project.title @@ -209,8 +235,12 @@ def project_params .permit(:name, :directory, :description, :icon, :id, :template) end - def files_params - params.permit(:project_id, :filepath) + def directory_params + params.permit(:project_id, :format, :dir_path, sorting_params: [:col, :direction, :grouped?]) + end + + def file_params + params.permit(:project_id, :format, :path, :sorting_params) end def show_project_params diff --git a/apps/dashboard/app/helpers/projects_helper.rb b/apps/dashboard/app/helpers/projects_helper.rb index 87df4858d..7241a4f8f 100644 --- a/apps/dashboard/app/helpers/projects_helper.rb +++ b/apps/dashboard/app/helpers/projects_helper.rb @@ -31,4 +31,93 @@ def button_category(status) status end end + + def files_button + link_to( + ".../projects#{@path.to_s.split('projects')[1]}", + files_path(fs: 'fs', filepath: @path), + target: '_top', + class: 'link-light' + ).html_safe + end + + # + # + # <%= "Go To Files: .../projects#{@path.to_s.split('projects')[1]}" %> + # <%- if Configuration.project_size_enabled -%> + # + # <%- end -%> + # + + def project_size + + end + + # DRAFT: Remove if not needed + # def group_by_type_link + # group_link_text = "#{@sorting_params[:grouped?] ? 'Ungroup' : 'Group'}" + # group_link_title = @sorting_params[:grouped?] ? 'Ungroup results by type' : 'Group results by type' + # link_to( + # "Group", + # target_path(@sorting_params[:col], !@sorting_params[:grouped?]), + # title: "Group results by type", + # class: "btn btn-1 btn-primary btn-hover btn-sm align-self-end ml-auto", + # data: data_attributes + # ) + # end + + def column_head_link(column) + link_to( + link_text(column), + target_path(column), + title: tool_tip, + class: "text-dark", + data: data_attributes + ) + end + + def direction(column) + if column.to_s == @sorting_params[:col] + @sorting_params[:direction] == ascending ? descending : ascending + else + DirectoryUtilsConcern::ASCENDING + end + end + + def link_text(column) + col_title = t("dashboard.#{column.to_s}") + if column.to_s == @sorting_params[:col] + "#{col_title} #{fa_icon( direction(column) == ascending ? 'sort-up' : 'sort-down', classes: 'fa-md')}".html_safe + else + "#{col_title} #{fa_icon('sort', classes: 'fa-md')}".html_safe + end + end + + def target_path(column, grouped = @sorting_params[:grouped?]) + project_directory_path( + { project_id: @project.id, + dir_path: @path.to_s, + sorting_params: { col: column, + direction: direction(column), + grouped?: grouped + } + } + ) + end + + def tool_tip + "Show #{@path.basename} directory" + end + + def data_attributes + { turbo_frame: 'project_directory' } + end + + def ascending + DirectoryUtilsConcern::ASCENDING + end + + def descending + DirectoryUtilsConcern::DESCENDING + end end diff --git a/apps/dashboard/app/javascript/application.js b/apps/dashboard/app/javascript/application.js index 3b3fc068e..77caf0877 100644 --- a/apps/dashboard/app/javascript/application.js +++ b/apps/dashboard/app/javascript/application.js @@ -21,6 +21,8 @@ import 'datatables.net-bs4/js/dataTables.bootstrap4'; import 'datatables.net-select/js/dataTables.select'; import 'datatables.net-plugins/api/processing().mjs'; import "@hotwired/turbo-rails" +import { Turbo } from "@hotwired/turbo-rails" +Turbo.session.drive = false import Rails from '@rails/ujs'; diff --git a/apps/dashboard/app/views/projects/_directory.html.erb b/apps/dashboard/app/views/projects/_directory.html.erb index 6e719b1ae..7263a15e4 100644 --- a/apps/dashboard/app/views/projects/_directory.html.erb +++ b/apps/dashboard/app/views/projects/_directory.html.erb @@ -1,21 +1,27 @@ -<%= turbo_frame_tag "project_files" do %> - - - - - - - - - - - - - - - <%= render partial: "files", locals: { project_id: project.id, path: path, files: files } %> - -
- - TypeNameActionsSizeModified atOwnerMode
+<%= turbo_frame_tag "project_directory" do %> +
+
+ .../projects<%= @path.to_s.split('projects')[1] %> +
+ + + + + + + + + + + + + + <%= render partial: "files", locals: { project: project, path: path, files: files, sorting_params: sorting_params } %> + +
+
+  <%= files_button %> +
+
<%= t('dashboard.type') %><%= column_head_link(:name) %><%= column_head_link(:size) %><%= column_head_link(:date) %><%= column_head_link(:owner) %>Mode
+
<% end %> \ No newline at end of file diff --git a/apps/dashboard/app/views/projects/_file.html.erb b/apps/dashboard/app/views/projects/_file.html.erb new file mode 100644 index 000000000..939ab5f01 --- /dev/null +++ b/apps/dashboard/app/views/projects/_file.html.erb @@ -0,0 +1,26 @@ +<%= turbo_frame_tag "project_directory" do %> + +
+
+
+
+ <%= link_to("", + project_directory_path(project_id: @project.id, dir_path: "#{@path.parent}", sorting_params: @sorting_params), + class: 'fa fa-window-close align-self-start button buttom-sm text-danger', + data: { turbo_frame: "project_directory" } + ) + %>  + .../projects<%= @path.to_s.split('projects')[1] %> +
+
+
+
+
<%= @file %>
+
+
+
+  <%= files_button %> +
+
+
+<%- end -%> \ No newline at end of file diff --git a/apps/dashboard/app/views/projects/_files.html.erb b/apps/dashboard/app/views/projects/_files.html.erb index 14c39c432..e05f320e0 100644 --- a/apps/dashboard/app/views/projects/_files.html.erb +++ b/apps/dashboard/app/views/projects/_files.html.erb @@ -1,54 +1,73 @@ + +<%- unless path.to_s == project.directory.to_s -%> - + + + <%= link_to( + "..", + project_directory_path( + project_id: project.id, + dir_path: "#{path.parent}", + sorting_params: sorting_params + ), + title: 'Show parent directory', + data: { turbo_frame: "project_directory" } + ) + %> + - - <%= link_to("..", project_files_path(project_id: project_id, filepath: sanitize("#{path}/..")), data: { turbo_frame: "project_files" }) %> - - - <% files.each do |file| %> - - - - - - <%= file[:type] %> - - - <%= link_to(file[:name], project_files_path(project_id: project_id, filepath: sanitize("#{path}/#{file[:name]}")), data: { turbo_frame: "project_files" }) %> - - - Actions -
- - - -
- - - <%= file[:size] %> - - - <%= file[:modified_at] %> - - - <%= file[:owner] %> - - - <%= file[:mode] %> - - - <%- end -%> \ No newline at end of file +<%- end -%> +<% files.each do |file| %> + + + + + + <%- if file[:directory] -%> + <%= link_to( + file[:name], + project_directory_path( + project_id: project.id, + dir_path: "#{path}/#{file[:name]}", + sorting_params: sorting_params + ), + title: "Show #{file[:name]} directory", + data: { turbo_frame: "project_directory" } + ) + %> + <%- else -%> + <%= link_to( + file[:name], + project_file_path( + project_id: project.id, + path: "#{path}/#{file[:name]}", + sorting_params: sorting_params + ), + title: "Show #{file[:name]}", + data: { turbo_frame: "project_directory" } + ) + %> + <%- end -%> + + + <%= file[:size] %> + + + <%= DateTime.parse(Time.at(file[:date]).to_s).strftime("%F %r") %> + + + <%= file[:owner] %> + + + <%= file[:mode] %> + + +<%- end -%> \ No newline at end of file diff --git a/apps/dashboard/app/views/projects/_files_column_head.html.erb b/apps/dashboard/app/views/projects/_files_column_head.html.erb new file mode 100644 index 000000000..8b320d785 --- /dev/null +++ b/apps/dashboard/app/views/projects/_files_column_head.html.erb @@ -0,0 +1,14 @@ +<%= link_to( + "Name #{fa_icon( sorting_params["direction"] == controller.class::ASCENDING ? 'caret-up' : 'caret-down', classes: nil)}".html_safe, + project_directory_path( + project_id: project.id, + dir_path: path, + sorting_params: { col: 'name', + direction: sorting_params[:col] == 'name' ? sorting_params[:direction] : controller.class::ASCENDING, + grouped?: sorting_params[:grouped?] + } + ), + title: "Show #{path.basename} directory", + data: { turbo_frame: "project_directory" }, + class: "text-dark" +)%> \ No newline at end of file diff --git a/apps/dashboard/app/views/projects/show.html.erb b/apps/dashboard/app/views/projects/show.html.erb index c5f2380a7..f16de0bc1 100644 --- a/apps/dashboard/app/views/projects/show.html.erb +++ b/apps/dashboard/app/views/projects/show.html.erb @@ -20,16 +20,6 @@ - -
@@ -78,8 +68,8 @@
-

<%= "#{@project.name} (Project ID: #{@project.id})" %>

- <%= render partial: 'directory', locals: { project: @project, path: @path, files: @files } %> +

<%= "#{t('dashboard.project')} #{t('dashboard.directory')}" %>:  <%= @project.id %>

+ <%= render partial: 'directory', locals: { project: @project, path: @path, files: @files, sorting_params: @sorting_params } %>
diff --git a/apps/dashboard/config/locales/en.yml b/apps/dashboard/config/locales/en.yml index cbe6599f2..c1cd5f866 100644 --- a/apps/dashboard/config/locales/en.yml +++ b/apps/dashboard/config/locales/en.yml @@ -322,3 +322,9 @@ en: project: "Project" directory: "Directory" close: "Close" + type: "Type" + name: "Name" + size: "Size" + owner: "Owner" + date: "Date" + mode: "Mode" diff --git a/apps/dashboard/config/locales/ja_JP.yml b/apps/dashboard/config/locales/ja_JP.yml index e3b3282fd..09c1c8df5 100644 --- a/apps/dashboard/config/locales/ja_JP.yml +++ b/apps/dashboard/config/locales/ja_JP.yml @@ -10,6 +10,15 @@ ja_JP: edit: "編集する" show: "見せる" launch: "起動する" + type: 'タイプ' + name: '名前' + size: "サイズ" + owner: "所有者" + date: "日付" + mode: "モード" + project: "プロジェクト" + directory: "ディレクトリ" + # project: "Project" # directory: "Directory" auto_log_location_title: "ログの場所" \ No newline at end of file diff --git a/apps/dashboard/config/locales/zh-CN.yml b/apps/dashboard/config/locales/zh-CN.yml index bb3c798bd..48e5f99a4 100644 --- a/apps/dashboard/config/locales/zh-CN.yml +++ b/apps/dashboard/config/locales/zh-CN.yml @@ -151,4 +151,13 @@ zh-CN: edit: "编辑" show: "显示" launch: "启动" + type: "类型" + name: "名称" + size: "大小" + owner: "所有者" + date: "日期" + mode: "模式" + project: "项目" + directory: "目录" + # development_apps_caption: "Sandbox App" diff --git a/apps/dashboard/config/routes.rb b/apps/dashboard/config/routes.rb index d5e93352d..00c478ae9 100644 --- a/apps/dashboard/config/routes.rb +++ b/apps/dashboard/config/routes.rb @@ -16,7 +16,8 @@ end end if Configuration.can_access_files? - get 'projects/:project_id/files/*filepath' => 'projects#files', as: 'project_files' + get 'projects/:project_id/directory' => 'projects#directory', as: 'project_directory' + get 'projects/:project_id/file' => 'projects#file', as: 'project_file' end end