add filter function for Tags, refactoring and restyling, add phrases and dbupdate

This commit is contained in:
ma0068
2025-11-13 09:19:35 +01:00
parent df63b8c1b7
commit a26bdfe385
10 changed files with 616 additions and 318 deletions
@@ -33,6 +33,10 @@ class Bookmark extends FHCAPI_Controller
'update' => self::PERM_LOGGED,
'changeOrder' => self::PERM_LOGGED,
'getAllBookmarkTags' => self::PERM_LOGGED,
'getTagFilter' => self::PERM_LOGGED,
'addAndUpdateTagFilter' => self::PERM_LOGGED,
'isInOverride' => self::PERM_LOGGED,
'addWidgetToOverride' => self::PERM_LOGGED,
]);
$this->load->model('dashboard/Bookmark_model', 'BookmarkModel');
@@ -184,5 +188,140 @@ class Bookmark extends FHCAPI_Controller
$this->terminateWithSuccess(current($bookmarks));
}
/**
* get all tagFilter of a certain bookmark widget
* @access public
* @return void
*/
public function getTagFilter($widgetId, $sectionName)
{
$result = $this->BookmarkModel->getTagFilter($widgetId, $this->uid, $sectionName);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess(current($data));
}
/**
* get all tagFilter of a certain bookmark widget
* @access public
* @return void
*/
public function addAndUpdateTagFilter($widgetId, $sectionName)
{
$tags = $this->input->post('tags',true);
if (is_array($tags))
{
$tags = json_encode($tags);
}
$result = $this->BookmarkModel->addAndUpdateTagFilter($widgetId, $this->uid, $sectionName, $tags);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
/**
* checks if a widget has already an entry in the benutzeroverride
* @access public
* @return void
*/
public function isInOverride($widgetId, $sectionName)
{
$result = $this->BookmarkModel->checkOrAddToOverride($widgetId, $this->uid, $sectionName);
$data = getData($result);
if(!$data)
$this->terminateWithSuccess([false, 0]);
$id = current($data)->widgetid;
$id = trim($id, '"');
if ($id != $widgetId)
$this->terminateWithSuccess([false, 1]);
else
$this->terminateWithSuccess([true, null]);
}
/**
* adds widget benutzeroverride
* @access public
* @return void
*/
public function addWidgetToOverride($widgetId, $sectionName, $mode, $x, $y, $h, $w)
{
$this->load->library('dashboard/DashboardLib', null, 'DashboardLib');
$dashboard_kurzbz = "CIS";
$structure = [
"custom" => [
"widgets" => []
],
"general" => [
"widgets" => [
$widgetId => [
"widget" => 3,
"config" => new stdClass(),
"place" => [
"3" => [
"x" => $x,
"y" => $y,
"w" => $w,
"h" => $h
]
],
"widgetid" => $widgetId,
"custom" => 1,
"id" => "insertByBookmarkwidget"
]
]
]
];
$jsonOverrideNew = json_encode($structure, JSON_UNESCAPED_UNICODE);
//no existing benutzeroverride
if($mode == 0)
{
$override = $this->DashboardLib->getOverrideOrCreateEmptyOverride($dashboard_kurzbz, $this->uid);
$override->override = $jsonOverrideNew;
$result = $this->DashboardLib->insertOrUpdateOverride($override);
$this->terminateWithSuccess($result);
}
//benutzeroverride existing, but widget not included
elseif($mode == 1)
{
$overrideExisting = $this->DashboardLib->getOverrideOrCreateEmptyOverride($dashboard_kurzbz, $this->uid);
$override = json_decode($overrideExisting->override, true); // decode as Array
$newWidget = [
"widget" => 3,
"config" => new stdClass(),
"place" => [
"3" => [
"x" => $x,
"y" => $y,
"w" => $w,
"h" => $h
]
],
"widgetid" => $widgetId,
"custom" => 1,
"id" => "insertByBookmarkwidget"
];
$override['general']['widgets'][$widgetId] = $newWidget;
$jsonOverrideUpdated = json_encode($override, JSON_UNESCAPED_UNICODE);
$overrideExisting->override = $jsonOverrideUpdated;
$result = $this->DashboardLib->insertOrUpdateOverride($overrideExisting);
$this->terminateWithSuccess($result);
}
else
$this->terminateWithError("Error: no known mode");
}
}
@@ -215,47 +215,4 @@ class Config extends Auth_Controller
return $this->outputJsonSuccess($result);
}
//TODO(Manu) move to Bookmark controller
public function insertAndUpdateTagsForBookmarksUser()
{
$widgetId = $this->input->get('widget_id');
$funktion_kurzbz = $this->input->get('funktion_kurzbz');
$uid = $this->AuthLib->getAuthObj()->username;
$tags = $this->input->get('tags');
$this->load->model('dashboard/Dashboard_Override_model', 'Dashboard_OverrideModel');
$result = $this->Dashboard_OverrideModel->addTagFilter($widgetId, $uid, $funktion_kurzbz, $tags);
$this->outputJsonSuccess($result ?: []);
}
//TODO(Manu) move to Bookmark controller
public function getTagFilter()
{
$widgetId = $this->input->get('widget_id');
$funktion_kurzbz = $this->input->get('funktion_kurzbz');
$uid = $this->AuthLib->getAuthObj()->username;
//$dashboard_kurzbz = 1;
$this->load->model('dashboard/Dashboard_Override_model', 'Dashboard_OverrideModel');
/* $override = $this->DashboardLib->getOverride($dashboard_kurzbz, $uid);
if (empty($override)) {
http_response_code(404);
$this->terminateWithJsonError('userconfig for dashboard ' . $dashboard_kurzbz . ' not found.');
}
$override_decoded = json_decode($override->override, true);
return $this->outputJsonSuccess($override_decoded ?: []);*/
$result = $this->Dashboard_OverrideModel->getTagFilter($widgetId, $uid, $funktion_kurzbz);
$this->outputJsonSuccess($result ?: []);
}
}
@@ -28,4 +28,67 @@ class Bookmark_model extends DB_Model
return $this->execQuery($qry, array('uid' => $uid));
}
/**
* Get Overrides of given uid and funktion_kurzbz and widget_id
* @param integer $widget_id
* @param string $uid
* @param string $funktion_kurzbz
* @return array
*/
public function getTagFilter($widgetId, $uid, $funktion_kurzbz)
{
$qry = " SELECT override -> '" . $funktion_kurzbz . "'-> 'widgets'-> '" . $widgetId . "'-> 'config' -> 'tags' AS tags FROM dashboard.tbl_dashboard_benutzer_override WHERE uid = '" . $uid . "';";
return $this->execQuery($qry);
}
/*
* updates Tagfilter
* checks and changes type of config
* if config == array -> change to object
*/
public function addAndUpdateTagFilter($widgetId, $uid, $funktion_kurzbz, $tags)
{
$params = [
$funktion_kurzbz, $widgetId,
$funktion_kurzbz, $widgetId,
$funktion_kurzbz, $widgetId,
$funktion_kurzbz, $widgetId,
$tags,
$uid
];
$qry = "
UPDATE dashboard.tbl_dashboard_benutzer_override
SET override = jsonb_set(
-- check if config is object
jsonb_set(
COALESCE(override, '{}'::jsonb),
format('{%s,widgets,%s,config}', ?, ?)::text[],
CASE
WHEN jsonb_typeof(override #> format('{%s,widgets,%s,config}', ?, ?)::text[]) = 'array'
THEN '{}'::jsonb
ELSE COALESCE((override #> format('{%s,widgets,%s,config}', ?, ?)::text[])::jsonb, '{}'::jsonb)
END,
true
),
-- insert tags
format('{%s,widgets,%s,config,tags}', ?, ?)::text[],
?::jsonb,
true
)
WHERE uid = ?
";
return $this->execQuery($qry, $params);
}
public function checkOrAddToOverride($widgetId, $uid, $funktion_kurzbz)
{
$params = [$funktion_kurzbz, $widgetId, $uid];
$qry = " SELECT override -> '" . $funktion_kurzbz . "'-> 'widgets'-> '" . $widgetId . "'-> 'widgetid' as widgetid FROM dashboard.tbl_dashboard_benutzer_override WHERE uid = '" . $uid . "';";
return $this->execQuery($qry, $params);
}
}
@@ -23,58 +23,4 @@ class Dashboard_Override_model extends DB_Model
{
return $this->loadWhere(array('dashboard_id' => $dashboard_id, 'uid'=> $uid));
}
/**
* Get Overrides of given uid and funktion_kurzbz and widget_id
* @param integer dashboard_id
* @param string $uid
* @return array
*/
//TODO(MANU) move to bookmark model
public function getTagFilter($widgetId, $uid, $funktion_kurzbz)
{
// $qry = "SELECT override -> ? -> 'widgets' -> ? -> 'tags' AS tags FROM dashboard.tbl_dashboard_benutzer_override WHERE uid = ?";
// $qry = " SELECT override -> '" . $funktion_kurzbz . "'-> 'widgets'-> '" . $widgetId . "'-> 'tags' AS tags FROM dashboard.tbl_dashboard_benutzer_override WHERE uid = '" . $uid . "';";
//unter config
$qry = " SELECT override -> '" . $funktion_kurzbz . "'-> 'widgets'-> '" . $widgetId . "'-> 'config' -> 'tags' AS tags FROM dashboard.tbl_dashboard_benutzer_override WHERE uid = '" . $uid . "';";
/* $qry = <<<SQL
SELECT
override -> ?
-> 'widgets'
-> ?
-> 'tags' AS tags
FROM dashboard.tbl_dashboard_benutzer_override
WHERE uid = ?
SQL;*/
//return $qry;
return $this->execQuery($qry);
// return $this->execQuery($qry, array($funktion_kurzbz, $widgetId, $uid));
}
//TODO(MANU) move to bookmark model
public function addTagFilter($widgetId, $uid, $funktion_kurzbz, $tags)
{
if (is_array($tags)) {
$tags = json_encode($tags); // convert PHP array to JSON string
}
$params = [$funktion_kurzbz, $widgetId, $tags, $uid];
$qry = "
UPDATE dashboard.tbl_dashboard_benutzer_override
SET override = jsonb_set(
COALESCE(override, '{}'::jsonb),
format('{%s,widgets,%s,config,tags}',? , ?)::text[],
?::jsonb,
true
)
WHERE uid = ?
";
// return $qry;
return $this->execQuery($qry, $params);
}
}
+25 -7
View File
@@ -17,6 +17,7 @@
export default {
getBookmarks() {
return {
method: 'get',
url: '/api/frontend/v1/Bookmark/getBookmarks'
@@ -54,12 +55,29 @@ export default {
url: '/api/frontend/v1/Bookmark/getAllBookmarkTags'
};
},
//TODO(Manu) getTagFilter and addTagFilter
//in bookmark_model
/* updateBenutzeroverride() {
return{
getTagFilter(widgetId, sectionName){
return {
method: 'get',
url: `/api/frontend/v1/Bookmark/getTagFilter/${widgetId}/${sectionName}`
};
},
addTagFilter(widgetId, sectionName, tags){
return {
method: 'post',
url: `/api/frontend/v1/Bookmark/update/${bookmark_id}`,
params: {url, title, tag}
}*/
url: `/api/frontend/v1/Bookmark/addAndUpdateTagFilter/${widgetId}/${sectionName}`,
params: { tags }
};
},
isInOverride(widgetId, sectionName){
return {
method: 'post',
url: `/api/frontend/v1/Bookmark/isInOverride/${widgetId}/${sectionName}`
};
},
addWidgetToOverride(widgetId, sectionName, mode, x, y, h, w){
return {
method: 'post',
url: `/api/frontend/v1/Bookmark/addWidgetToOverride/${widgetId}/${sectionName}/${mode}/${x}/${y}/${h}/${w}`,
};
}
};
+1 -1
View File
@@ -191,7 +191,7 @@ export default {
</div>
<!-- TODO Manu rename/remove-->
<div v-if="ready" class="card-body overflow-hidden p-0">
<component :is="component" v-model:shared-data="sharedData" :config="arguments" :width="width" :height="height" :widget-id="widgetID" :manu2="widgetID" :widgetConfig="config" @setConfig="setConfig" @change="changeConfigManually"></component>
<component :is="component" v-model:shared-data="sharedData" :config="arguments" :width="width" :height="height" :widget-id="widgetID" :item_data="item_data" @setConfig="setConfig" @change="changeConfigManually"></component>
</div>
<div v-else class="card-body overflow-hidden text-center d-flex flex-column justify-content-center"><i class="fa-solid fa-spinner fa-pulse fa-3x"></i></div>
<bs-modal v-if="hasConfig" ref="config" @hideBsModal="handleHideBsModal" @showBsModal="handleShowBsModal">
@@ -6,9 +6,8 @@ export default {
"configMode",
"sharedData",
"widgetInfo",
"widgetId", //check
"manu2", //TODO(Manu) check/remove
"widgetConfig"
"widgetId",
"item_data"
],
emits: [
"setConfig",
+177 -200
View File
@@ -4,7 +4,6 @@ import BsModal from "../Bootstrap/Modal.js";
import AbstractWidget from './Abstract.js';
import ApiBookmark from '../../api/factory/widget/bookmark.js';
import ApiDashboard from '../../api/factory/cis/dashboard.js'; //nutzt aber nicht viel
export default {
name: "WidgetsUrl",
@@ -36,17 +35,14 @@ export default {
invalidURL: false,
invalidTitel: false,
},
tagsArray: [],
tagsArrayMS: [],
tagsArrayAC: [],
selectedTags: [],
newTag: null,
selectedFilters: [], //die aber im benutzer_override speichern
items:[],
value: '',
//viewData: []
ArrayAC: [],
selectedTagsAC: [],
tagsInput2: [],
filteredArrayAC: [],
selectedFilters: [],
filter: [],
filteredArray: [],
sharedFiltered: {},
}),
computed: {
tagName() {
@@ -71,16 +67,13 @@ export default {
if(this.shared.length == 0)
return 0;
else
return Math.max(...this.shared.map(b => b.sort));
return Math.max(...this.sharedFiltered.map(b => b.sort));
},
minSort(){
if(this.shared.length == 0)
return 0;
else
return Math.min(...this.shared.map(b => b.sort));
},
tagsInput(){
return this.selectedTags.map(item => item.tag);
return Math.min(...this.sharedFiltered.map(b => b.sort));
},
filterInput(){
return this.selectedFilters.map(item => item.tag);
@@ -102,9 +95,7 @@ export default {
this.title_input = bookmark.title;
this.url_input = bookmark.url;
this.bookmark_id = bookmark.bookmark_id;
//but the JSON string to array
this.selectedTagsAC = JSON.parse(bookmark.tag);
// this.selectedTags = this.prepareTag(bookmark.tag);
this.selectedTags = JSON.parse(bookmark.tag);
this.$refs.editModal.show();
},
@@ -117,15 +108,14 @@ export default {
bookmark_id: this.bookmark_id,
title: this.title_input,
url: this.url_input,
tag: this.selectedTagsAC,
//tag: this.tagsInput, //old version
tag: this.selectedTags,
}))
.then((res) => res.data)
.then((result) => {
this.$fhcAlert.alertInfo(this.$p.t("bookmark", "bookmarkUpdated"));
// refetch the bookmarks to see the updates
this.fetchBookmarks();
this.getAllBookmarkTags();
this.fetchBookmarks();
// reset the values for the title and url inputs
this.clearInputs();
this.$refs.editModal.hide();
@@ -150,9 +140,7 @@ export default {
this.$api
.call(ApiBookmark.insert({
//tag: this.config.tag,
//tag: this.tagsInput, //old version
tag: this.selectedTagsAC,
tag: this.selectedTags,
title: this.title_input,
url: this.url_input,
sort: this.sort
@@ -161,15 +149,14 @@ export default {
.then((result) => {
this.$fhcAlert.alertInfo(this.$p.t("bookmark", "bookmarkAdded"));
// refetch the bookmarks to see the updates
this.fetchBookmarks();
this.getAllBookmarkTags();
this.fetchBookmarks();
this.$refs.createModal.hide();
// reset the values for the title and url inputs
this.clearInputs();
})
.catch(this.$fhcAlert.handleSystemError);
},
isValidationSuccessfull() {
// validate the input fields
if (this.title_input.length === 0) {
@@ -189,6 +176,10 @@ export default {
.then((res) => res.data)
.then((result) => {
this.shared = result;
this.$nextTick(() => {
this.sharedFiltered = this.filterBookmarksByTags(this.shared);
});
})
.catch(this.$fhcAlert.handleSystemError);
},
@@ -209,10 +200,19 @@ export default {
})
.catch(this.$fhcAlert.handleSystemError);
},
sortDown(bookmark_id){
const current = this.shared.find(b => b.bookmark_id === bookmark_id);
filterBookmarksByTags(bookmarks) {
const filter = this.filter;
if (!filter || filter.length === 0 || filter == "[]") return bookmarks;
const next = this.shared
return bookmarks.filter(b => {
const tags = JSON.parse(b.tag || "[]");
return tags.some(tag => filter.includes(tag));
});
},
sortDown(bookmark_id){
const current = this.sharedFiltered.find(b => b.bookmark_id === bookmark_id);
const next = this.sharedFiltered
.filter(b => b.sort > current.sort)
.sort((a, b) => a.sort - b.sort)[0];
@@ -223,9 +223,9 @@ export default {
this.changeOrder(current.bookmark_id, next.bookmark_id);
},
sortUp(bookmark_id){
const current = this.shared.find(b => b.bookmark_id === bookmark_id);
const current = this.sharedFiltered.find(b => b.bookmark_id === bookmark_id);
const next = this.shared
const next = this.sharedFiltered
.filter(b => b.sort < current.sort)
.sort((a, b) => a.sort + b.sort)[0];
@@ -237,12 +237,12 @@ export default {
},
addNewTag(){
if(this.newTag != null && this.newTag.length) {
this.tagsArray.push({tag: this.newTag, code: this.newTag});
this.tagsArrayMS.push({tag: this.newTag, code: this.newTag});
this.selectedTags.push({tag: this.newTag, code: this.newTag});
this.newTag = null;
}
else
this.$fhcAlert.alertError("Eingabe eines Zeichens erforderlich!");
this.$fhcAlert.alertError(this.$p.t("bookmark", "errorInputNecessary"));
},
changeOrder(bookmark_id_1, bookmark_id_2){
this.$api
@@ -265,10 +265,11 @@ export default {
return false;
}
}
return Array.isArray(tags) && tags.length > 0;
if (Array.isArray(tags) && tags.length > 0) {
return tags.join(' ');
}
},
prepareTag(bookmarkArr){
// parse if string
const parsedArr = Array.isArray(bookmarkArr)
? bookmarkArr
: JSON.parse(bookmarkArr);
@@ -285,200 +286,141 @@ export default {
.call(ApiBookmark.getAllBookmarkTags())
.then((res) => res.data)
.then((result) => {
//Variante Chips
this.tagsArray = this.prepareTag(result.data);
//Version Chips
this.tagsArrayMS = this.prepareTag(result.data);
//Variante Autocomplete
/*
this.ArrayAC = result.data;
console.log("type of " + typeof this.ArrayAC);
console.log(Array.isArray(this.ArrayAC));*/
// this.ArrayAC = Object.values(result.data);
// this.ArrayAC = Object.keys(result.data);
this.ArrayAC = result.data; //in object umwandeln
/* this.ArrayAC = {...this.ArrayAC};
console.log("type of " + typeof this.ArrayAC);
console.log(Array.isArray(this.ArrayAC)); // true*/
/* Array.isArray(result.data)
? result.data
: JSON.parse(result.data); */
//Version Autocomplete
this.tagsArrayAC = result.data;
})
.catch(this.$fhcAlert.handleSystemError);
},
addBookmarkFilter(){
console.log("in addFilterLogic: save in benutzeroverride " + this.selectedFilters.map(tag => tag.tag).join(", "));
openFilterModal(){
this.$refs.filterModal.show();
},
async handleAddingTagFilter(widgetId){
console.log("widget_id " + this.manu2);
console.log("tags " + this.filterInput);
const result = await this.isInOverride(widgetId);
console.log(`${this.apiurl}/dashboard/Config/insertAndUpdateTagsForBookmarksUser`, {
db: "CIS",
funktion_kurzbz: this.sectionName,
widget_id: this.manu2,
tags: this.filterInput
});
if (!result) {
return;
}
const [status, reason] = result;
axios.post(this.apiurl + '/dashboard/Config/insertAndUpdateTagsForBookmarksUser', {
db: "CIS",
funktion_kurzbz: this.sectionName,
widget_id: this.manu2,
tags: this.filterInput
})
.then(res => {
console.log("API Response:", res.data);
if (status) {
this.addTagFilter(widgetId);
} else {
this.addWidgetToOverride(widgetId, reason);
}
},
addTagFilter(widgetId){
this.$api
.call(ApiBookmark.addTagFilter(widgetId, this.sectionName, this.filterInput))
.then((res) => res.data)
.then((result) => {
this.$fhcAlert.alertInfo(this.$p.t("bookmark", "filterUpdated"));
this.$refs.filterModal.hide();
this.getTagFilter(this.widgetId);
this.$nextTick(() => {
this.getAllBookmarkTags();
});
this.fetchBookmarks();
})
.catch(err => {
console.error("ERROR:", err);
});
.catch(this.$fhcAlert.handleSystemError);
},
async isInOverride(widgetId) {
try {
const res = await this.$api.call(ApiBookmark.isInOverride(widgetId, this.sectionName));
const result = res.data;
return result;
} catch (err) {
this.$fhcAlert.handleSystemError(err);
return null;
}
},
addWidgetToOverride(widgetId, reason){
this.$api
.call(ApiBookmark.addWidgetToOverride(
widgetId,
this.sectionName,
reason,
this.item_data.x,
this.item_data.y,
this.item_data.h,
this.item_data.w
))
.then((res) => res.data)
.then((result) => {
this.addTagFilter(widgetId);
})
.catch(this.$fhcAlert.handleSystemError);
},
getTagFilter(widget_id){
/* console.log(`${this.apiurl}/dashboard/Config/getTagFilter`, {
db: "CIS",
funktion_kurzbz: this.sectionName,
widget_id: widget_id
});*/
axios.get(this.apiurl + '/dashboard/Config/getTagFilter', {
params: {
db: "CIS",
funktion_kurzbz: this.sectionName,
widget_id: widget_id
}
})
.then(res => {
// console.log("API Response:", res.data);
//old version
/* const raw = res.data?.retval?.retval?.[0]?.tags;
const filterArray = raw ? JSON.parse(raw) : [];
this.selectedFilters = this.prepareTag(filterArray);*/
//unter config
const rawTags = res.data.retval.retval[0].tags; // string
const filterArray = JSON.parse(rawTags);
//this.selectedFilters = res.data.retval;
this.selectedFilters = this.prepareTag(filterArray);
this.$api
.call(ApiBookmark.getTagFilter(widget_id, this.sectionName))
.then((res) => res.data)
.then((result) => {
const rawTags = result.tags; // string
this.filter = rawTags;
if(rawTags != null) {
this.rawTagsParsed = JSON.parse(rawTags);
this.selectedFilters = this.prepareTag(this.rawTagsParsed);
}
this.fetchBookmarks();
})
.catch(err =>
console.error('ERROR: ', err));
.catch(this.$fhcAlert.handleSystemError);
},
//Variante mit AutocompleteFeld
/* search(event) {
this.ArrayAC = this.ArrayAC.map((item) => item) || event;
},*/
search(event) {
const query = event.query ?? ""; // PrimeVue liefert query
const query = event.query ?? "";
// Filter ArrayAC nach eingegebenem Text
this.filteredArrayAC = this.ArrayAC.filter(item =>
// Filter for text
this.filteredArray = this.tagsArrayAC.filter(item =>
item.toLowerCase().includes(query.toLowerCase())
);
// Wenn kein Treffer → manuellen Text erlauben
if (this.filteredArrayAC.length === 0 && query) {
this.filteredArrayAC = [query];
// input if search not successful
if (this.filteredArray.length === 0 && query) {
this.filteredArray = [query];
}
console.log("Filtered suggestions:", this.filteredArrayAC);
},
/* addCustomTag(event) {
const value = event.value; // das ist der vom User eingegebene Text
console.log("Custom Tag:", value);
// Füge den neuen Tag zu selectedTags hinzu
// this.selectedTags = [...this.selectedTags, value];
const newTag = { tag: value };
// Optional: Füge den Tag auch in ArrayAC hinzu, damit er zukünftig auswählbar ist
if (!this.tagsArray.includes(value)) {
this.tagsArray.push(value);
}
}*/
},
async mounted() {
if(this.widgetId) {
this.getTagFilter(this.widgetId);
}
await this.fetchBookmarks();
this.getAllBookmarkTags();
if(this.manu2) {
this.getTagFilter(this.manu2);
}
/* console.log("config " + this.config);
console.log("widgetID " + this.widgetId);*/
// console.log("apiurl " + this.apiurl );
/* console.log("widgetinfo " + this.widgetInfo);
console.log("config " + this.config);
console.log(JSON.stringify(this.config));
console.log("width " + this.width);
console.log("height " + this.height);
console.log("configMode " + this.configMode);
console.log("sharedData " + this.sharedData);
console.log(JSON.stringify(this.sharedData));*/
//console.log( this.config.map(tag => tag.tag).join(", "));
/* console.log("manu " + this.manu);
console.log("manu2 " + this.manu2);
console.log("widgetID " + this.widgetID);*/
},
created() {
//
// this.$emit('setConfig', true); // -> use this to enable widget config mode if needed
/*
widgetId: {{widgetId}}
{{manu2}} {{sectionName}}
*/
},
template: /*html*/ `
<div class="widgets-url w-100 h-100 overflow-auto" style="padding: 1rem 1rem;">
<div class="d-flex flex-column justify-content-between">
<!--TODO Manu eigener button mit modal für Filter, Autocomplete Variante !-->
<!-- div class="mt-2 row">
<div class="col-10">
<PvMultiSelect
v-model="selectedFilters"
id="tagFilterUrl"
:options="tagsArray"
optionLabel="tag"
display="chip"
placeholder="Show only tags"
:maxSelectedLabels="3"
class="p-inputtext-sm w-100 me-2"
/>
</div>
<div class="col-1">
<button
class="btn btn-secondary"
@click="addBookmarkFilter"
title="nach Tags filtern"
>
<i class="fa-solid fa-filter"></i>
</button>
</div>
</div -->
<div class="d-flex mt-2">
<button class="btn btn-outline-secondary btn-sm flex-grow-1 me-2" @click="openCreateModal">
{{$p.t('bookmark','newLink')}}
</button>
<button v-if="selectedFilters.length" class="btn btn-secondary btn-sm" :title="this.$p.t('bookmark/editFilter')" @click="openFilterModal">
<i class="fa-solid fa-filter-circle-xmark"></i>
</button>
<button v-else class="btn btn-outline-secondary btn-sm" :title="this.$p.t('bookmark/filterByTags')" @click="openFilterModal">
<i class="fa-solid fa-filter"></i>
</button>
</div>
<button class="btn btn-outline-secondary btn-sm w-100 mt-2 card" @click="openCreateModal" type="button">{{$p.t('bookmark','newLink')}}</button>
<template v-if="shared">
<template v-if="sharedFiltered">
<template v-if="!emptyBookmarks">
<div v-for="link in shared" :key="link.id" class="d-flex mt-2">
<div v-for="link in sharedFiltered" :key="link.id" class="d-flex mt-2">
<a target="_blank" :href="link.url" class="me-1">
<i class="fa fa-solid fa-arrow-up-right-from-square me-1"></i>{{ link.title }}
</a>
<span
v-if="hasTags(link)"
:title="link.tag"
:title="hasTags(link)"
style="color: silver;"
>
<i class="fa fa-solid fa-tag text-gray-500" aria-hidden="true"></i>
@@ -486,32 +428,32 @@ export default {
<div class="ms-auto">
<!--EDIT BOOKMARK-->
<a type="button" href="#" @click.prevent="openEditModal(link)" aria-label="edit bookmark" v-tooltip="{showDelay:1000,value:'edit bookmark'}">
<a type="button" href="#" @click.prevent="openEditModal(link)" aria-label="edit bookmark" :title="this.$p.t('bookmark/editBookmark')">
<i class="fa fa-edit me-1" aria-hidden="true"></i>
</a>
<!--DELETE BOOKMARK-->
<a type="button" id="deleteBookmark" href="#" aria-label="delete bookmark" v-tooltip="{showDelay:1000,value:'delete bookmark'}" @click.prevent="removeLink(link.bookmark_id)">
<a type="button" id="deleteBookmark" href="#" aria-label="delete bookmark" :title="this.$p.t('bookmark/deleteBookmark')" @click.prevent="removeLink(link.bookmark_id)">
<i class="fa fa-regular fa-trash-can" aria-hidden="true"></i>
</a>
<!--SORT BOOKMARKS-->
<a
v-if="shared.length > 1"
v-if="sharedFiltered.length > 1"
type="button"
id="downsortBookmark"
href="#"
aria-label="sortdown bookmark"
v-tooltip="{showDelay:1000,value:'sort down bookmark'}"
:title="this.$p.t('bookmark/sortDownwards')"
@click.prevent="sortDown(link.bookmark_id)"
>
<i :class="[ 'fa', 'fa-arrow-down', 'me-1', link.sort === maxSort ? 'text-light pointer-events-none' : '' ]"></i>
</a>
<a
v-if="shared.length > 1"
v-if="sharedFiltered.length > 1"
type="button"
id="upsortBookmark"
href="#"
aria-label="sortup bookmark"
v-tooltip="{showDelay:1000,value:'sort up bookmark'}"
:title="this.$p.t('bookmark/sortToTop')"
@click.prevent="sortUp(link.bookmark_id)"
>
<i :class="[ 'fa', 'fa-arrow-up', 'me-1', link.sort === minSort ? 'text-light pointer-events-none' : '' ]"></i>
@@ -541,16 +483,16 @@ export default {
</template>
<template #default>
<form-input :label="$p.t('profil','Titel')" :title="$p.t('profil','Titel')" id="editTitle" v-model="title_input" name="title" class="mb-2"></form-input>
<form-input :label="$p.t('profil','Titel')" :title="$p.t('profil','Titel')" id="editTitle" v-model="title_input" name="title" class="mb-2"></form-input>
<form-input label="Url" title="Url" id="editUrl" v-model="url_input" name="url"></form-input>
<label class="mt-2">Tags</label>
<div class="mt-2">
<PvAutoComplete
v-model="selectedTagsAC"
v-model="selectedTags"
multiple
dropdown
:suggestions="filteredArrayAC"
:suggestions="filteredArray"
@complete="search"
/>
</div>
@@ -574,10 +516,10 @@ export default {
<label class="mt-2">Tags</label>
<div class="mt-2">
<PvAutoComplete
v-model="selectedTagsAC"
v-model="selectedTags"
multiple
dropdown
:suggestions="filteredArrayAC"
:suggestions="filteredArray"
@complete="search"
/>
</div>
@@ -588,6 +530,41 @@ export default {
</template>
</bs-modal>
</teleport>
<!--FILTER MODAL-->
<teleport to="body">
<bs-modal @[\`hide.bs.modal\`]="clearInputs();" ref="filterModal">
<template #title>
<h2>{{$p.t('bookmark','headerFilterBookmark')}}</h2>
</template>
<template #default>
<div class="mt-2 row">
<div class="col-10">
<PvMultiSelect
v-model="selectedFilters"
id="tagFilterUrl"
:options="tagsArrayMS"
optionLabel="tag"
display="chip"
:placeholder="$p.t('bookmark','noFilter')"
:maxSelectedLabels="3"
class="p-inputtext-sm w-100 me-2"
/>
</div>
</div>
</template>
<template #footer>
<button
class="btn btn-secondary"
@click="handleAddingTagFilter(widgetId)"
:title="$p.t('bookmark','filterByTags')"
>
OK
</button>
</template>
</bs-modal>
</teleport>
`,
};
@@ -12,12 +12,9 @@ if(!@$db->db_query("SELECT sort FROM dashboard.tbl_bookmark LIMIT 1")) {
else
echo '<br>Spalte sort zu Tabelle dashboard.tbl_bookmark hinzugefügt';
}
//add preliminary Sort for all bookmarks if NULL
//TODO(manu) verfeinern, falls einzelne Werte NULL
if(@$db->db_query("SELECT sort FROM dashboard.tbl_bookmark LIMIT 1")) {
$qry = "WITH ranked AS (
//add preliminary Sort for all bookmarks if NULL
if(@$db->db_query("SELECT sort FROM dashboard.tbl_bookmark LIMIT 1")) {
$qry = "WITH ranked AS (
SELECT
t1.bookmark_id,
(
@@ -34,10 +31,11 @@ if(@$db->db_query("SELECT sort FROM dashboard.tbl_bookmark LIMIT 1")) {
WHERE t.bookmark_id = ranked.bookmark_id
AND t.sort IS NULL;";
if (!$db->db_query($qry))
echo '<strong>dashboard.tbl_bookmark ' . $db->db_last_error() . '</strong><br>';
else
echo '<br>Tabelle dashboard.tbl_bookmark: Spalte sort mit vorläufiger Sortierung befüllt';
if (!$db->db_query($qry))
echo '<strong>dashboard.tbl_bookmark ' . $db->db_last_error() . '</strong><br>';
else
echo '<br>Tabelle dashboard.tbl_bookmark: Spalte sort mit vorläufiger Sortierung befüllt';
}
}
//set column tag to type JSONB
+201
View File
@@ -34514,6 +34514,207 @@ array(
)
)
),
array(
'app' => 'core',
'category' => 'bookmark',
'phrase' => 'editFilter',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Filter bearbeiten',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'edit Filter',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'bookmark',
'phrase' => 'filterByTags',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Nach Tags Filtern',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'filter by Tags',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'bookmark',
'phrase' => 'sortDownwards',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Nach unten verschieben',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'sort downwards',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'bookmark',
'phrase' => 'sortToTop',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Nach oben verschieben',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'sort to top',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'bookmark',
'phrase' => 'deleteBookmark',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Lesezeichen löschen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'delete Bookmark',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'bookmark',
'phrase' => 'editBookmark',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Lesezeichen bearbeiten',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'edit Bookmark',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'bookmark',
'phrase' => 'filterUpdated',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Filteraktion erfolgreich durchgeführt',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'filter updated successfully',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'bookmark',
'phrase' => 'errorInputNecessary',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Eingabe eines Zeichens erforderlich',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'One character must be entered',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'bookmark',
'phrase' => 'noFilter',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Kein Filter für Lesezeichen ausgewählt',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'No bookmark filter entered',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'bookmark',
'phrase' => 'headerFilterBookmark',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Lesezeichen filtern',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Filter Bookmarks',
'description' => '',
'insertvon' => 'system'
)
)
),
// BOOKMARK PHRASEN END ----------------------------------------------------------------------
array(
'app' => 'core',
'category' => 'global',