Skip to content

Commit

Permalink
feature: implement file manager, part 2
Browse files Browse the repository at this point in the history
  • Loading branch information
mutantsan committed Jan 29, 2024
1 parent 10a67d2 commit 7786655
Show file tree
Hide file tree
Showing 11 changed files with 151 additions and 49 deletions.
59 changes: 59 additions & 0 deletions ckanext/file_manager/assets/js/fm-htmx.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
ckan.module("fm-htmx", function ($) {
return {
options: {
formId: null,
},
initialize: function () {
$.proxyAll(this, /_on/);

document.addEventListener('htmx:beforeRequest', this._onHTMXbeforeRequest);
document.addEventListener('htmx:afterSettle', this._onHTMXafterSettle);
document.addEventListener('htmx:confirm', this._onHTMXconfirm);
document.addEventListener('htmx:afterRequest', this._onAfterRequest)
},

_onHTMXbeforeRequest: function (e) {
$(e.detail.target).find("[data-module]").unbind()

for (const [key, _] of Object.entries(ckan.module.instances)) {
ckan.module.instances[key] = null;
}
},

_onHTMXafterSettle: function (e) {
const doNotInitialize = ["ap-hyperscript"]

$(e.detail.target).find("[data-module]").each(function (_, element) {
const moduleName = $(element).attr("data-module");

if (!doNotInitialize.includes(moduleName)) {
ckan.module.initializeElement(element);
}
})
},

_onHTMXconfirm: function (evt) {
if (evt.detail.path.includes("/file_manager/delete")) {
evt.preventDefault();

swal({
text: this._("Are you sure you wish to delete a file?"),
icon: "warning",
buttons: true,
dangerMode: true,
}).then((confirmed) => {
if (confirmed) {
evt.detail.issueRequest();
this.sandbox.publish("ap:notify", this._("A file has been removed"));
}
});
}
},

_onAfterRequest: function (evt) {
if (evt.detail.pathInfo.requestPath.includes("/file_manager/delete/")) {
htmx.trigger(`#${this.options.formId}`, "change");
}
}
};
});
9 changes: 9 additions & 0 deletions ckanext/file_manager/assets/webassets.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
file-manager-js:
filter: rjsmin
output: ckanext-admin_panel/%(version)s-file-manager.js
contents:
- js/fm-htmx.js
extra:
preload:
- base/main
- base/ckan
29 changes: 29 additions & 0 deletions ckanext/file_manager/col_renderers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from __future__ import annotations

from datetime import datetime

import ckan.plugins.toolkit as tk

from ckanext.toolbelt.decorators import Collector

import ckanext.ap_main.types as ap_types

renderer, get_renderers = Collector("fm").split()


@renderer
def last_access(
rows: ap_types.ItemList,
row: ap_types.Item,
value: ap_types.ItemValue,
**kwargs,
) -> int:
if not value:
return tk._("Never")

datetime_obj = datetime.fromisoformat(value)
current_date = datetime.now()

days_passed = (current_date - datetime_obj).days

return days_passed
50 changes: 27 additions & 23 deletions ckanext/file_manager/collection.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from __future__ import annotations

from typing import Any
from ckanext.collection.utils.data.model import ModelData

from dominate import tags

import ckan.plugins.toolkit as tk
import sqlalchemy as sa

from ckanext.collection.types import InputFilter, LinkFilter
from ckanext.collection.utils import Filters, StatementSaData
from ckanext.collection.types import InputFilter, LinkFilter, ButtonFilter
from ckanext.collection.utils import Filters

from ckanext.ap_main.collection.base import (
ApCollection,
Expand All @@ -21,9 +21,17 @@
from ckanext.files.model import File


def file_row_dictizer(serializer: ApHtmxTableSerializer, row: File):
data = row.dictize({})
data["bulk-action"] = data["id"]

return data


class FileManagerCollection(ApCollection[Any]):
SerializerFactory = ApHtmxTableSerializer.with_attributes(
record_template="file_manager/record.html"
record_template="file_manager/record.html",
row_dictizer=file_row_dictizer,
)

ColumnsFactory = ApColumns.with_attributes(
Expand All @@ -33,10 +41,11 @@ class FileManagerCollection(ApCollection[Any]):
"path",
"kind",
"uploaded_at",
"last_access",
"extras",
"row_actions",
],
sortable={"name", "kind", "uploaded_at"},
sortable={"name", "kind", "uploaded_at", "last_access"},
searchable={"name"},
labels={
"bulk-action": tk.literal(
Expand All @@ -45,36 +54,30 @@ class FileManagerCollection(ApCollection[Any]):
name="bulk_check",
id="bulk_check",
data_module="ap-bulk-check",
data_module_selector='input[name="id"]',
data_module_selector='input[name="entity_id"]',
)
),
"name": "Name",
"path": "Path",
"kind": "Type",
"uploaded_at": "Uploaded At",
"last_access": "Last Access",
"extras": "Extras",
"row_actions": "Actions",
},
width={"name": "20%", "path": "20%"},
serializers={
"uploaded_at": [("date", {})],
"extras": [("json_display", {})],
"last_access": [("day_passed", {})],
},
)

DataFactory = StatementSaData.with_attributes(
DataFactory = ModelData.with_attributes(
model=File,
use_naive_filters=True,
is_scalar=True,
use_naive_search=True,
statement=sa.select(
File.id.label("bulk-action"),
File.id.label("id"),
File.name.label("name"),
File.path.label("path"),
File.kind.label("kind"),
File.uploaded_at.label("uploaded_at"),
File.extras.label("extras"),
),
use_naive_filters=True,
)

FiltersFactory = Filters.with_attributes(
Expand All @@ -98,7 +101,6 @@ class FileManagerCollection(ApCollection[Any]):
"icon": "fa fa-pencil",
"params": {
"data-module-path": "$id",
"entity_type": "$type",
"view": "edit",
},
},
Expand Down Expand Up @@ -126,13 +128,15 @@ class FileManagerCollection(ApCollection[Any]):
"placeholder": "Search",
},
),
LinkFilter(
name="clear",
type="link",
ButtonFilter(
name="type",
type="button",
options={
"label": "Clear",
"endpoint": "file_manager.list",
"kwargs": {},
"type": "button",
"attrs": {
"onclick": "$(this).closest('form').find('input,select').val('').prevObject[0].requestSubmit()"
},
},
),
],
Expand Down
5 changes: 5 additions & 0 deletions ckanext/file_manager/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@

import ckanext.ap_main.types as ap_types
from ckanext.ap_main.interfaces import IAdminPanel
from ckanext.ap_main.types import ColRenderer

from ckanext.collection.interfaces import ICollection, CollectionFactory

from ckanext.file_manager.collection import FileManagerCollection
from ckanext.file_manager.col_renderers import get_renderers


@tk.blanket.blueprints
Expand Down Expand Up @@ -43,6 +45,9 @@ def register_config_sections(
)
return config_list

def get_col_renderers(self) -> dict[str, ColRenderer]:
return get_renderers()

# ICollection

def get_collection_factories(self) -> dict[str, CollectionFactory]:
Expand Down
14 changes: 8 additions & 6 deletions ckanext/file_manager/templates/file_manager/list.html
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
{% extends 'admin_panel/base.html' %}

{% import 'macros/autoform.html' as autoform %}
{% import 'macros/form.html' as form %}
{% import 'admin_panel/macros/form.html' as ap_form %}

{% block ap_main_class %} ap-log-list {% endblock %}
{% block ap_main_class %} file-manager-list {% endblock %}

{% block breadcrumb_content %}
<li>{% link_for _("File manager"), request.endpoint %}</li>
{% endblock breadcrumb_content %}

{% block ap_content %}
<div class="file-manager--manage mb-2">
<div class="file-manager--manage mb-2" data-module="fm-htmx" data-module-form-id="{{ collection.serializer.form_id }}">
<button
type="button"
class="btn btn-success"
Expand All @@ -36,3 +32,9 @@
{% endif %}
</div> <!-- row -->
{% endblock ap_content %}


{% block scripts %}
{% asset 'file_manager/file-manager-js' %}
{{ super() }}
{% endblock %}
8 changes: 5 additions & 3 deletions ckanext/file_manager/templates/file_manager/record.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@
{% block value %}
{% if column == "row_actions" %}
<a
data-module="ap-tooltip fm-copy-url"
data-module="ap-tooltip ap-copy-to-clipboard"
data-module-content="{{ data.url }}"
title="{{ _('Copy file URL')}}"
class="btn btn-black">
<i class="fas fa-copy"></i>
</a>

<a
data-module="ap-tooltip fm-copy-url"
href="{{ data.url }}"
download
data-module="ap-tooltip"
title="{{ _('Download file')}}"
class="btn btn-primary">
<i class="fas fa-download"></i>
</a>


<a
data-module="ap-tooltip" title="{{ _('Remove a file') }}"
class="btn btn-danger"
Expand Down
14 changes: 2 additions & 12 deletions ckanext/file_manager/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import logging
from typing import Union, Callable

from flask import Blueprint, Response, jsonify
from flask import Blueprint, Response
from flask.views import MethodView

import ckan.plugins.toolkit as tk
Expand All @@ -22,16 +22,6 @@
file_manager.before_request(ap_before_request)


# file_manager.add_url_rule(
# "/file_manager",
# view_func=ApConfigurationPageView.as_view(
# "list",
# "file_manager_config",
# page_title=tk._("File manager"),
# ),
# )


class FileManagerView(MethodView):
def get(self) -> Union[str, Response]:
return tk.render(
Expand All @@ -45,7 +35,7 @@ def get(self) -> Union[str, Response]:

def post(self) -> Response:
bulk_action = tk.request.form.get("bulk-action")
file_ids = tk.request.form.getlist("file_id")
file_ids = tk.request.form.getlist("entity_id")

action_func = (
self._get_bulk_action(bulk_action) if bulk_action else None
Expand Down
5 changes: 5 additions & 0 deletions ckanext/files/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import ckanext.files.config as files_conf


def files_get_unused_threshold() -> int:
return files_conf.get_unused_threshold()
6 changes: 1 addition & 5 deletions ckanext/files/model/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,5 @@ class File(Base):

def dictize(self, context):
result = table_dictize(self, context)
result["url"] = tk.h.url_for("files.get_file", file_id=self.id)
result["url"] = tk.h.url_for("files.get_file", file_id=self.id, qualified=True)
return result

@property
def url(self):
return tk.h.url_for_static(self.path, qualified=True)
1 change: 1 addition & 0 deletions ckanext/files/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
@tk.blanket.blueprints
@tk.blanket.config_declarations
@tk.blanket.cli
@tk.blanket.helpers
class FilesPlugin(p.SingletonPlugin):
p.implements(p.IActions)
p.implements(p.IAuthFunctions)
Expand Down

0 comments on commit 7786655

Please sign in to comment.