* Infolog: Push updates

This commit is contained in:
nathangray 2020-07-23 13:34:08 -06:00
parent efaf9771d0
commit 6d2af76576
8 changed files with 181 additions and 14 deletions

View File

@ -248,7 +248,7 @@ var AppJS = (function(){ "use strict"; return Class.extend(
* @param uid
* @param current_order
*/
nm_refresh_add: function(nm, uid, current_order)
nm_refresh_index: function(nm, uid, current_order)
{
// Do we have a modified field so we can check nm sort order?
if(this.modification_field_name)

View File

@ -193,7 +193,6 @@ var EgwApp = /** @class */ (function () {
*/
EgwApp.prototype.nm_refresh_index = function (nm, uid, current_order, update_type) {
var _a;
return false;
// Do we have a modified field so we can check nm sort order?
if (this.modification_field_name) {
var value = nm.getValue();

View File

@ -296,7 +296,6 @@ export abstract class EgwApp
*/
nm_refresh_index(nm: et2_nextmatch, uid: string, current_order: string[], update_type: string) : number|boolean
{
return false;
// Do we have a modified field so we can check nm sort order?
if(this.modification_field_name)
{

View File

@ -716,6 +716,8 @@ class infolog_bo
}
if ($info['info_status'] != 'deleted') // dont notify of final purge of already deleted items
{
Link::notify_update('infolog',$info_id,$info, 'delete');
// send email notifications and do the history logging
if(!$skip_notification)
{
@ -749,6 +751,7 @@ class infolog_bo
$skip_notification=false, $throw_exception=false, $purge_cfs=null, $ignore_acl=false)
{
$values = $values_in;
$change_type = 'update';
//echo "boinfolog::write()values="; _debug_array($values);
if (!$ignore_acl && (!$values['info_id'] && !$this->check_access(0, Acl::EDIT, $values['info_owner']) &&
!$this->check_access(0, Acl::ADD, $values['info_owner'])))
@ -760,6 +763,10 @@ class infolog_bo
{
$old = $this->read($values['info_id'], false, 'server', $ignore_acl);
}
else
{
$change_type = 'add';
}
if (($status_only = !$ignore_acl && $values['info_id'] && !$this->check_access($values,Acl::EDIT)))
{
@ -830,6 +837,7 @@ class infolog_bo
if ($forcestatus && !in_array($values['info_status'],array('done','billed','cancelled'))) $values['info_status'] = $status;
}
$check_defaults = false;
$change_type = 'update';
}
if ($check_defaults)
{
@ -1012,7 +1020,7 @@ class infolog_bo
}
// notify the link-class about the update, as other apps may be subscribt to it
Link::notify_update('infolog',$info_id,$values);
Link::notify_update('infolog',$info_id,$values, $change_type);
// pre-cache the new values
self::set_link_cache($values);

View File

@ -73,6 +73,7 @@ class infolog_hooks
'edit_id' => 'info_id',
'edit_popup' => '760x570',
'merge' => true,
'push_data' => ['info_type', 'info_owner','info_responsible', 'info_modified']
);
}

View File

@ -1826,7 +1826,7 @@ class infolog_ui
$GLOBALS['egw']->preferences->add('infolog','preferred_type',$content['info_type']);
$GLOBALS['egw']->preferences->save_repository(false,'user',false);
$content['msg'] = lang('InfoLog entry saved');
Framework::refresh_opener($content['msg'],'infolog',$info_id,$operation);
Framework::message($content['msg']);
}
$content['tabs'] = $active_tab;
@ -1881,12 +1881,12 @@ class infolog_ui
);
if (!($content['msg'] = $this->delete($info_id,$referer,'edit'))) return; // checks ACL first
Framework::refresh_opener($content['msg'],'infolog',$info_id,'delete');
Framework::message($content['msg']);
}
// called again after delete confirmation dialog
elseif ($button == 'deleted' && $content['msg'])
{
Framework::refresh_opener($content['msg'],'infolog',$info_id,'delete');
Framework::message($content['msg']);
}
if ($button == 'save' || $button == 'cancel' || $button == 'delete' || $button == 'deleted')
{

View File

@ -30,6 +30,9 @@ require("jqueryui");
require("../jsapi/egw_global");
require("../etemplate/et2_types");
var egw_app_1 = require("../../api/js/jsapi/egw_app");
var et2_widget_dialog_1 = require("../../api/js/etemplate/et2_widget_dialog");
var etemplate2_1 = require("../../api/js/etemplate/etemplate2");
var et2_extension_nextmatch_1 = require("../../api/js/etemplate/et2_extension_nextmatch");
/**
* UI for Infolog
*
@ -44,7 +47,7 @@ var InfologApp = /** @class */ (function (_super) {
*/
function InfologApp() {
// call parent
return _super.call(this, 'infolog') || this;
return _super.call(this, 'infolog', 'info_datemodified') || this;
}
/**
* Destructor
@ -143,6 +146,79 @@ var InfologApp = /** @class */ (function (_super) {
this.et2._inst.refresh(_msg, _app, _id, _type);
}
};
/**
* Handle a push notification about entry changes from the websocket
*
* @param pushData
* @param {string} pushData.app application name
* @param {(string|number)} pushData.id id of entry to refresh or null
* @param {string} pushData.type either 'update', 'edit', 'delete', 'add' or null
* - update: request just modified data from given rows. Sorting is not considered,
* so if the sort field is changed, the row will not be moved.
* - edit: rows changed, but sorting may be affected. Requires full reload.
* - delete: just delete the given rows clientside (no server interaction neccessary)
* - add: ask server for data, add in intelligently
* @param {object|null} pushData.acl Extra data for determining relevance. eg: owner or responsible to decide if update is necessary
* @param {number} pushData.account_id User that caused the notification
*/
InfologApp.prototype.push = function (pushData) {
if (pushData.app !== this.appname)
return;
// pushData does not contain everything, just the minimum.
var event = pushData.acl || {};
if (pushData.type === 'delete') {
return _super.prototype.push.call(this, pushData);
}
// check visibility - grants is ID => permission of people we're allowed to see
if (typeof this._grants === 'undefined') {
this._grants = egw.grants(this.appname);
}
if (this._grants && typeof this._grants[pushData.acl.info_owner] == "undefined") {
// No ACL access
return;
}
// If we know about it & it's a update, just update.
if (pushData.type == "update" && this.egw.dataHasUID(pushData.id) || pushData.type == "edit") {
return etemplate2_1.etemplate2.app_refresh("", pushData.app, pushData.id, pushData.type);
}
// Filter what's allowed down to those we care about
var filters = {
owner: { col: "info_owner", filter_values: [] },
responsible: { col: "info_responsible", filter_values: [] }
};
for (var _i = 0, _a = etemplate2_1.etemplate2.getByApplication(this.appname); _i < _a.length; _i++) {
var et = _a[_i];
et.widgetContainer.iterateOver(function (nm) {
var value = nm.getValue();
if (!value || !value.col_filter)
return;
for (var _i = 0, _a = Object.values(filters); _i < _a.length; _i++) {
var field_filter = _a[_i];
if (value.col_filter[field_filter.col]) {
field_filter.filter_values.push(value.col_filter[field_filter.col]);
}
}
}, this, et2_extension_nextmatch_1.et2_nextmatch);
}
var _loop_1 = function (field_filter) {
if (field_filter.filter_values.length == 0)
return "continue";
if (pushData.acl && typeof pushData.acl[field_filter.col] == "string" &&
field_filter.filter_values.indexOf(pushData.acl[field_filter.col]) <= 0) {
return { value: void 0 };
}
if (field_filter.filter_values.filter(function (account) { return pushData.acl[field_filter.col].indexOf(account) >= 0; }).length == 0)
return { value: void 0 };
};
for (var _b = 0, _c = Object.values(filters); _b < _c.length; _b++) {
var field_filter = _c[_b];
var state_1 = _loop_1(field_filter);
if (typeof state_1 === "object")
return state_1.value;
}
// Pass actual refresh on to etemplate to take care of
etemplate2_1.etemplate2.app_refresh("", pushData.app, pushData.id, pushData.type);
};
/**
* Retrieve the current state of the application for future restoration
*
@ -156,7 +232,7 @@ var InfologApp = /** @class */ (function (_super) {
var state = _super.prototype.getState.call(this);
var nm = {};
// Get index etemplate
var et2 = etemplate2.getById('infolog-index');
var et2 = etemplate2_1.etemplate2.getById('infolog-index');
if (et2) {
var content = et2.widgetContainer.getArrayMgr('content');
nm = content && content.data && content.data.nm ? content.data.nm : {};
@ -289,10 +365,10 @@ var InfologApp = /** @class */ (function (_super) {
child_button.style.display = children ? 'block' : 'none';
}
var callbackDeleteDialog = function (button_id) {
if (button_id == et2_dialog.YES_BUTTON) {
if (button_id == et2_widget_dialog_1.et2_dialog.YES_BUTTON) {
}
};
et2_dialog.show_dialog(callbackDeleteDialog, this.egw.lang("Do you really want to DELETE this Rule"), this.egw.lang("Delete"), {}, et2_dialog.BUTTONS_YES_NO_CANCEL, et2_dialog.WARNING_MESSAGE);
et2_widget_dialog_1.et2_dialog.show_dialog(callbackDeleteDialog, this.egw.lang("Do you really want to DELETE this Rule"), this.egw.lang("Delete"), {}, et2_widget_dialog_1.et2_dialog.BUTTONS_YES_NO_CANCEL, et2_widget_dialog_1.et2_dialog.WARNING_MESSAGE);
};
/**
* Confirm delete

View File

@ -18,6 +18,9 @@ import '../jsapi/egw_global';
import '../etemplate/et2_types';
import {EgwApp} from '../../api/js/jsapi/egw_app';
import {et2_dialog} from "../../api/js/etemplate/et2_widget_dialog";
import {etemplate2} from "../../api/js/etemplate/etemplate2";
import {et2_nextmatch} from "../../api/js/etemplate/et2_extension_nextmatch";
/**
* UI for Infolog
@ -27,6 +30,9 @@ import {EgwApp} from '../../api/js/jsapi/egw_app';
class InfologApp extends EgwApp
{
// Hold on to ACL grants
private _grants : any;
/**
* Constructor
*
@ -35,7 +41,7 @@ class InfologApp extends EgwApp
constructor()
{
// call parent
super('infolog');
super('infolog', 'info_datemodified');
}
/**
@ -150,6 +156,84 @@ class InfologApp extends EgwApp
this.et2._inst.refresh(_msg, _app, _id, _type);
}
}
/**
* Handle a push notification about entry changes from the websocket
*
* @param pushData
* @param {string} pushData.app application name
* @param {(string|number)} pushData.id id of entry to refresh or null
* @param {string} pushData.type either 'update', 'edit', 'delete', 'add' or null
* - update: request just modified data from given rows. Sorting is not considered,
* so if the sort field is changed, the row will not be moved.
* - edit: rows changed, but sorting may be affected. Requires full reload.
* - delete: just delete the given rows clientside (no server interaction neccessary)
* - add: ask server for data, add in intelligently
* @param {object|null} pushData.acl Extra data for determining relevance. eg: owner or responsible to decide if update is necessary
* @param {number} pushData.account_id User that caused the notification
*/
push(pushData)
{
if(pushData.app !== this.appname) return;
// pushData does not contain everything, just the minimum.
let event = pushData.acl || {};
if(pushData.type === 'delete')
{
return super.push(pushData);
}
// check visibility - grants is ID => permission of people we're allowed to see
if(typeof this._grants === 'undefined')
{
this._grants = egw.grants(this.appname);
}
if(this._grants && typeof this._grants[pushData.acl.info_owner] == "undefined")
{
// No ACL access
return;
}
// If we know about it & it's a update, just update.
if(pushData.type == "update" && this.egw.dataHasUID(pushData.id) || pushData.type == "edit")
{
return etemplate2.app_refresh("",pushData.app, pushData.id, pushData.type);
}
// Filter what's allowed down to those we care about
let filters = {
owner: {col: "info_owner", filter_values: []},
responsible: {col: "info_responsible", filter_values: []}
};
for(let et of etemplate2.getByApplication(this.appname))
{
et.widgetContainer.iterateOver( function(nm) {
let value = nm.getValue();
if(!value || !value.col_filter) return;
for(let field_filter of Object.values(filters))
{
if(value.col_filter[field_filter.col])
{
field_filter.filter_values.push(value.col_filter[field_filter.col]);
}
}
},this, et2_nextmatch);
}
for(let field_filter of Object.values(filters))
{
if(field_filter.filter_values.length == 0) continue;
if(pushData.acl && typeof pushData.acl[field_filter.col] == "string" &&
field_filter.filter_values.indexOf(pushData.acl[field_filter.col]) <=0)
{
return;
}
if(field_filter.filter_values.filter(account => pushData.acl[field_filter.col].indexOf(account) >=0).length == 0) return;
}
// Pass actual refresh on to etemplate to take care of
etemplate2.app_refresh("",pushData.app, pushData.id, pushData.type);
}
/**
* Retrieve the current state of the application for future restoration