Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
mutantsan committed Jul 25, 2024
1 parent ff651f3 commit f4b7024
Show file tree
Hide file tree
Showing 41 changed files with 1,024 additions and 2,004 deletions.
1,185 changes: 1 addition & 1,184 deletions README.md

Large diffs are not rendered by default.

114 changes: 104 additions & 10 deletions ckanext/bulk/assets/scripts/bulk-manager-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,22 @@ ckan.module("bulk-manager-form", function () {
actionSelect: ".bulk-select-action select",
entitySelect: ".bulk-select-entity select",
submitBtn: ".bulk-submit-form-btn",
globalOperator: "#global_operator",
infoBlock: ".bulk-info",
},
options: {},

initialize() {
$.proxyAll(this, /_/);

this.managerForm = this.el.find("form");
this.updateToBlock = $(this.const.updateToBlock);
this.filterBlock = $(this.const.filterBlock);
this.updateToBlock = $(this.const.updateToBlock);
this.actionSelect = $(this.const.actionSelect);
this.entitySelect = $(this.const.entitySelect);
this.submitBtn = $(this.const.submitBtn);
this.globalOperator = $(this.const.globalOperator);
this.infoBlock = $(this.const.infoBlock);

this.actionSelect.on("change", this._onActionSelectChange);
this.entitySelect.on("change", this._onEntitySelectChange);
Expand All @@ -29,8 +33,25 @@ ckan.module("bulk-manager-form", function () {
// Add event listeners on dynamic elements
$('body').on('click', '.btn-item-remove', this._onFilterItemRemove);

// initialize CKAN modules for HTMX loaded pages
htmx.on("htmx:afterSettle", this._HTMXAfterSettle);

// ON INIT
this._onActionSelectChange();

this._initFieldSelectors(this.filterBlock.find(".bulk-field-select select"));
this._initFieldSelectors(this.updateToBlock.find("select"));
this._toggleRemoveBtns();
},

_HTMXAfterSettle(event) {
if (event.detail.pathInfo.requestPath == "/bulk/create_filter_item") {
this._initFieldSelectors(this.filterBlock.find(".bulk-field-select select"));
} else if (event.detail.pathInfo.requestPath == "/bulk/create_update_item") {
this._initFieldSelectors(this.updateToBlock.find("select"));
}

this._toggleRemoveBtns();
},

/**
Expand All @@ -42,22 +63,32 @@ ckan.module("bulk-manager-form", function () {
this.updateToBlock.toggle(this.actionSelect.val() === "update");
},

_onEntitySelectChange() {
_onEntitySelectChange(e) {
if (!this._getFilters().length) {
return;
}

this._reinitFieldSelectors(this.filterBlock.find(".bulk-field-select select"));
this._reinitFieldSelectors(this.updateToBlock.find("select"));

// HACK: select an input because swal will focus the last focused element
// and we don't want it to be an entity selector
$("#value").get(0).focus()

Swal.fire({
title: "Do you want to save the changes?",
title: "Do you want to clear the filters?",
showDenyButton: true,
confirmButtonText: "Yes",
denyButtonText: "No"
}).then((result) => {
if (result.isConfirmed) {
this._clearFilters();
} else if (result.isDenied) {
}
});
},

_clearFilters() {
this.filterBlock.find("select").prop("selectedIndex", 0);
this.filterBlock.find("select").get(0).tomselect.clear();
this.filterBlock.find("input").val("");
this.filterBlock.find(".filter-item:not(:first)").remove();
this.filterBlock.find(".filter-item .btn").prop("disabled", "disabled");
Expand All @@ -72,6 +103,24 @@ ckan.module("bulk-manager-form", function () {

_onFilterItemRemove(e) {
$(e.target).closest(".bulk-fieldset-item").remove();

this.managerForm.trigger("change");

this._toggleRemoveBtns();
},

_toggleRemoveBtns() {
if (this.filterBlock.find(".bulk-fieldset-item").length == 1) {
this.filterBlock.find(".filter-item .btn").prop("disabled", "disabled");
} else {
this.filterBlock.find(".filter-item .btn").prop("disabled", false);
}

if (this.updateToBlock.find(".update-field-item").length == 1) {
this.updateToBlock.find(".update-field-item .btn").prop("disabled", "disabled");
} else {
this.updateToBlock.find(".update-field-item .btn").prop("disabled", false);
}
},

_onSubmitBtnClick(e) {
Expand Down Expand Up @@ -103,9 +152,9 @@ ckan.module("bulk-manager-form", function () {
this.filterBlock.find(".filter-item").each((_, el) => {
const field = $(el).find(".bulk-field-select select").val();
const operator = $(el).find(".bulk-operator-select select").val();
const value = $(el).find(".bulk-value-input input").val();
const value = $(el).find(".bulk-value-input input").val() || "";

if (field && operator && value) {
if (field && operator) {
filters.push({ field, operator, value });
}
});
Expand All @@ -130,16 +179,20 @@ ckan.module("bulk-manager-form", function () {

_onFormChange() {
console.log("Form changed");
console.log(this.globalOperator);

const data = {
entity_type: this.entitySelect.val(),
action: this.actionSelect.val(),
filters: this._getFilters(),
global_operator: this.globalOperator.is(":checked") ? "AND" : "OR",
}

this._toggleLoadSpinner(true);

if (!data.filters.length) {
console.log("No filters");
return;
this.infoBlock.find(".counter").html("There will be information about how many entities will be changed.");
return this._toggleLoadSpinner(false);
}

this.sandbox.client.call(
Expand All @@ -148,12 +201,53 @@ ckan.module("bulk-manager-form", function () {
data,
(data) => {
console.log(data);
$(".bulk-info").html("Found " + data.result.count + " entities");
this.infoBlock.find(".counter").html("Found " + data.result.length + " entities");
this._toggleLoadSpinner(false);
},
(resp) => {
iziToast.error({ message: resp });
this._toggleLoadSpinner(false);
}
);
},

_initFieldSelectors: function (selectItems, reinit = false) {
selectItems.each((_, el) => {
if (el.tomselect !== undefined) {
if (reinit) {
el.tomselect.destroy();
} else {
return;
}
}

console.log(el);

const self = this;

new TomSelect(el, {
valueField: "value",
labelField: "text",
plugins: ['dropdown_input'],
placeholder: "Search for field name",
create: true,
preload: true,
load: function (query, callback) {
var url = `/api/action/bulk_search_fields?query=${encodeURIComponent(query)}&entity_type=${self.entitySelect.val()}`;
fetch(url)
.then(response => response.json())
.then(json => {
callback(json.result);
}).catch(() => {
callback();
});
},
});
});
},

_toggleLoadSpinner: function (show) {
this.infoBlock.find(".spinner").toggle(show);
}
}
})
25 changes: 2 additions & 23 deletions ckanext/bulk/assets/scripts/bulk-tom-select.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,11 @@
/**
* TomSelect adapter.
* https://tom-select.js.org/
*/
ckan.module("tom-select", function () {

return {
// any attribute with `data-module-` prefix transforms into camelized
// option. `data-module-hello-world="1"` becomes `helloWorld: 1`. Case
// transformation happens only after hyphen. This is used to pass nested
// options. For example, `data-module-hello-world_bye-world` becomes
// `helloWorld_byeWorld`. Then options are processed by
// `this.sandbox.bulk.nestedOptions` and we receive
// `{helloWorld: {byeWorld: ...}}`.
options: {
valueField: 'value',
labelField: 'text',
valueField: "value",
labelField: "text",
plugins: ['dropdown_input'],
customRender: false,
load: function (query, callback) {
var url = '/api/action/bulk_search_fields?query=' + encodeURIComponent(query) + "&entity_type=dataset";
fetch(url)
.then(response => response.json())
.then(json => {
callback(json.result);
}).catch(() => {
callback();
});
},
render: {},
},

Expand Down
72 changes: 36 additions & 36 deletions ckanext/bulk/assets/scripts/bulk.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,46 @@
* Avoid using this function and try extracting logic into CKAN JS modules.
*/
jQuery(function () {
// register plugin helpers inside Sandbox object, available as `this.sandbox`
// inside every module instance.
ckan.sandbox.extend({
"bulk": {
/**
* Transform `{hello_world_prop: 1}` into `{hello:{world:{prop: 1}}}`
*/
nestedOptions(options) {
const nested = {};
// register plugin helpers inside Sandbox object, available as `this.sandbox`
// inside every module instance.
ckan.sandbox.extend({
"bulk": {
/**
* Transform `{hello_world_prop: 1}` into `{hello:{world:{prop: 1}}}`
*/
nestedOptions(options) {
const nested = {};

for (let name in options) {
if (typeof name !== "string") continue;
for (let name in options) {
if (typeof name !== "string") continue;

const path = name.split("_");
const prop = path.pop();
const target = path.reduce((container, part) => {
container[part] = container[part] || {};
return container[part];
}, nested);
target[prop] = options[name];
}
const path = name.split("_");
const prop = path.pop();
const target = path.reduce((container, part) => {
container[part] = container[part] || {};
return container[part];
}, nested);
target[prop] = options[name];
}

return nested;
},
},
});
return nested;
},
},
});

// initialize CKAN modules inside fragments loaded by HTMX
if (typeof htmx !== "undefined") {
htmx.on("htmx:afterSettle", function (event) {
var elements = event.target.querySelectorAll("[data-module]");
// initialize CKAN modules inside fragments loaded by HTMX
if (typeof htmx !== "undefined") {
htmx.on("htmx:afterSettle", function (event) {
var elements = event.target.querySelectorAll("[data-module]");

for (let node of elements) {
if (node.getAttribute("dm-initialized")) {
continue;
}
for (let node of elements) {
if (node.getAttribute("dm-initialized")) {
continue;
}

ckan.module.initializeElement(node);
node.setAttribute("dm-initialized", true)
}
});
}
ckan.module.initializeElement(node);
node.setAttribute("dm-initialized", true)
}
});
}
});
20 changes: 14 additions & 6 deletions ckanext/bulk/assets/scss/_global.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,30 @@
.bulk-manager {

// mask default select to look like tomselect and avoid flashing on init
select {
width: 100%;
height: 36px;
border-color: #d0d0d0;
border-radius: 3px;
padding: 8px;
select, input.form-control {
font-size: 13px;
line-height: 18px;
color: #303030;
border-radius: 3px;
border-color: #d0d0d0;
height: 36px;
padding: 8px;
box-shadow: unset;
}

select {
width: 100%;

-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}

.ts-wrapper {
box-shadow: unset;
border: unset;
padding: 0;

.ts-control {
min-height: 36px;
}
Expand Down
4 changes: 2 additions & 2 deletions ckanext/bulk/assets/scss/bulk.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
@use "fonts";
@use "cssvars";

@use "global";

@use "elements/buttons";
@use "elements/forms";

@use "global";
Loading

0 comments on commit f4b7024

Please sign in to comment.