Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

View filter changes #267

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions lib/GADS/API.pm
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,38 @@ post '/api/table_request' => require_login sub {
_post_table_request();
};

get '/api/:sheet/fields' => require_login sub {
my $user = logged_in_user;
my $sheetname = param 'sheet'
or panic __"No sheet name found";
my $layout = var('instances')->layout_by_shortname($sheetname)
or panic __x"Sheet {name} not found", name => $sheetname;
my $col_title = query_parameters->get('title')
or panic __"No column title found";
my $search = query_parameters->get('search');

my @columns = $layout->all(user_can_read => 1);
#Not sure if I should use the below in case it returns the column regardless of permissions?
#my $column = $layout->column_by_name($col_title);

my $items;
my $result=[];

foreach my $item (@columns) {
next if !$item || !($item->name) || $item->name !~ /$col_title/i;
last if $items;
$items = [$item->values_beginning_with($search)];
}

foreach my $item (@$items) {
if(ref($item) eq 'HASH') {
push @$result, $item->{'label'};
}
}

return encode_json($result);
};

# AJAX record browse
any ['get', 'post'] => '/api/:sheet/records' => require_login sub {
_get_records();
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
"handlebars": "^4.7.7",
"imports-loader": "^1.2.0",
"jquery": "^3.6.0",
"jquery-typeahead": "^2.11.1",
"jquery-ui-sortable-npm": "^1.0.0",
"jstree": "^3.3.12",
"keycharm": "^0.3.0",
Expand All @@ -43,6 +42,7 @@
"regenerator-runtime": "^0.13.11",
"summernote": "^0.8.20",
"tippy.js": "^6.3.7",
"typeahead.js": "^0.11.1",
"uuid": "^7.0.0",
"vis-data": "^6.3.0",
"vis-timeline": "7.4.3",
Expand All @@ -60,6 +60,7 @@
"@types/react": "^17.0.41",
"@types/react-dom": "^17.0.14",
"@types/react-grid-layout": "^1.3.2",
"@types/typeahead.js": "^0.11.5",
"@webpack-cli/serve": "^2.0.1",
"babel-jest": "^29.7.0",
"babel-loader": "^8.2.2",
Expand Down
2 changes: 1 addition & 1 deletion public/js/site.js

Large diffs are not rendered by default.

25 changes: 24 additions & 1 deletion src/frontend/components/data-table/lib/component.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
/* eslint-disable prefer-destructuring */
/* eslint-disable array-callback-return */
/* eslint-disable no-unneeded-ternary */
/* eslint-disable no-unreachable */
/* eslint-disable no-else-return */
/* eslint-disable no-useless-return */
/* eslint-disable prefer-const,no-duplicate-imports*/
import { Component } from 'component'
import 'datatables.net'
import 'datatables.net-buttons'
Expand All @@ -10,6 +17,7 @@ import { initializeRegisteredComponents, initializeComponent } from 'component'
import RecordPopupComponent from '../../record-popup/lib/component'
import MoreLessComponent from '../../more-less/lib/component'
import { moreLess } from '../../more-less/lib/more-less'
import 'jquery-typeahead';

const MORE_LESS_TRESHOLD = 50

Expand Down Expand Up @@ -263,8 +271,18 @@ class DataTableComponent extends Component {

this.toggleFilter(column)

$.typeahead({
input: $('input', $header),
minLength: 0,
seachOnFocus: true,
source: {
url: this.getApiEndpoint(title.replace(/Sort/g, '').trim()),
},
debug: true
});

// Apply the search
$('input', $header).on('change', function () {
$('input', $header).on('change', () => {
if (column.search() !== this.value) {
column
.search(this.value)
Expand Down Expand Up @@ -308,6 +326,11 @@ class DataTableComponent extends Component {
})
}

getApiEndpoint(title) {
const table = window.location.pathname.substring(1).split('/')[0];
return `/api/${table}/fields?title=${title}`;
}

encodeHTMLEntities(text) {
return $("<textarea/>").text(text).html();
}
Expand Down
2 changes: 2 additions & 0 deletions src/frontend/components/form-group/_form-group.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@import 'display-conditions/display-conditions';

.form-inline .form-group {
margin-right: $padding-base-horizontal;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.items {
max-height: 7.4em;
overflow: auto;
border : solid 1px #ccc;
border-top: solid 1px #FFF;
border-radius: 3px;
padding-top: 2px;
margin-top: -4px;

.item {
margin: 5px;
}

.item:hover {
background-color: #f5f5f5;
cursor: pointer;
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,85 @@
import { Component } from 'component'
import queryBuilder from '@lol768/jquery-querybuilder-no-eval/dist/js/query-builder.standalone.min'
import { Component } from 'component';
import '@lol768/jquery-querybuilder-no-eval/dist/js/query-builder.standalone.min';
import 'jquery-typeahead';

class DisplayConditionsComponent extends Component {
constructor(element) {
constructor(element) {
super(element)
this.el = $(this.element)
this.data = [];
this.initDisplayConditions()
}

initDisplayConditions() {
const builderData = this.el.data()
const filters = JSON.parse(Buffer.from(builderData.filters, 'base64'))
if (!filters.length) return
this.buildConditions(this.el);
}

createTypeaheadDivStructure() {
const div = document.createElement("div");
div.className = "typeahead__container";
const field = document.createElement("div");
field.className = "typeahead__field";
const query = document.createElement("div");
query.className = "typeahead__query";
const input = document.createElement("input");
input.type = "text";
input.className = "js-typeahead";
input.autocomplete = "on";
input.name = "js-typeahead";
query.append(input);
field.append(query);
div.append(field);
this.setupTypeahead(input);
return div;
}

setupSelects(el) {
const selects = el.find("select");
const select = $(selects[selects.length - 1]);
const self = this;
select.hide();
select
.find("option")
.each(function () {
if (this.text === "------") return;
self.addData(this.text, this.value);
});
const div = this.createTypeaheadDivStructure();
select.closest(".rule-filter-container").append(div);
}

setupTypeahead(input) {
const items = this.getItems();
typeof $.typeahead === "function" && $.typeahead({
input: input,
minLength: 1,
maxItem: 15,
autocomplete: true,
order: "asc",
source: {
data: items,
},
callback: {
onClickAfter: (node, a, item, event) => {
event.preventDefault();
const select = $(node).closest(".rule-filter-container").find("select");
select.val(this.getValue(item.display));
select.trigger("change");
},
},
});
}

buildConditions(el) {
const self = this;

el.on("afterCreateRuleFilters.queryBuilder", (event, filters) => {
self.setupSelects($(event.target));
});

const builderData = el.data();
const filters = JSON.parse(Buffer.from(builderData.filters, "base64"));
if (!filters.length) return;

this.el.queryBuilder({
filters: filters,
Expand All @@ -29,6 +97,25 @@ class DisplayConditionsComponent extends Component {
this.el.queryBuilder('setRules', JSON.parse(data))
}
}

addData(text, value) {
if (this.checkData(text)) return;
this.data.push({ text, value });
}

checkData(text) {
return this.data.find((item) => item.text === text);
}

getItems() {
return this.data.map((item) => {
return item.text;
});
}

getValue(item) {
return this.data.filter((data) => data.text === item)[0].value;
}
}

export default DisplayConditionsComponent
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import DisplayConditionsComponent from "./component";

global.$ = require("jquery");

describe("tests for component replacement", () => {
const getDiv = () => {
const div = document.createElement("div");
div.classList.add("rule-filter-container");
div.id = "displayConditionsBuilder";
$(div).data(
"filters",
"W3siaWQiOiI4IiwidHlwZSI6InN0cmluZyIsImxhYmVsIjoiVGVzdCJ9LHsidHlwZSI6InN0cmluZyIsImxhYmVsIjoiVGVzdCBPdGhlciBWYWx1ZSIsImlkIjoiMTEifSx7ImlkIjoiMTIiLCJ0eXBlIjoic3RyaW5nIiwibGFiZWwiOiJUZXN0IFJBRyJ9LHsiaWQiOiIxMyIsInR5cGUiOiJzdHJpbmciLCJsYWJlbCI6IlBlcnNvbiBUZXN0In1d"
);
return div;
};

it("should replace selects with inputs", () => {
const div = getDiv();
new DisplayConditionsComponent(div);
expect($(div).find('[type="text"]').length).toBe(1);
expect($(div).find("select").length).toBe(1);
});

it("should have list of options in data", () => {
const div = getDiv();
const conditions = new DisplayConditionsComponent(div);
expect(conditions.data.length).toBe(4);
});

it("should have all values from the select options in it's data", () => {
const div = getDiv();
const component = new DisplayConditionsComponent(div);
const select = $(div).find("select");
const options = $(select).find("option");
const items = component.data;
expect(options.length).toBe(items.length + 1);
});
});
Loading
Loading