json-object-editor
Version:
JOE the Json Object Editor | Platform Edition
790 lines (738 loc) • 34.3 kB
JavaScript
var task = function(){return{
title : '${name}',
info:"Create a new task and assign it to a team member in the project panel.",
ai_instructions:"",
listWindowTitle: 'Tasks',
gridView:{
cols:[
{name:'priority 1',filter:{priority:1}},
{name:'priority 2',filter:{priority:2}},
{name:'priority 3',filter:{priority:3}},
{name:'unprioritized',filter:{priority:1000}}
]
},
tableView:{
},
columns:3,
// shortTemplate:function(currentitem,asset){
// var asset = asset || currentitem || {};
// var imageURL = (asset.tcin && parseInt(asset.tcin) && 'https://target.scene7.com/is/image/Target/'+asset.tcin)||
// asset.thumbnail_url;
// var t = '<img class="asset-icon" src='+imageURL+' />'
// +'<joe-subtitle>${name}</joe-subtitle>'
// +'${if (${tcin})}<joe-subtext>tcin <b>${tcin}</b></joe-subtext>${end if}'
// +'<joe-subtext>#${asset_id}</joe-subtext>'
// +'<joe-subtext>${asset_type_name}</joe-subtext>'
// ;
// return t;
// },
menuicon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="-10 -10 120 120"><path d="M71.51,28.79a30,30,0,1,0,0,42.43A29.9,29.9,0,0,0,71.51,28.79ZM68.19,67.9a25.31,25.31,0,1,1,0-35.8A25.15,25.15,0,0,1,68.19,67.9Z"/><polygon points="47.65 50.21 39.03 40.84 29.5 50.37 29.5 50.37 47.46 68.33 83.8 34.99 82.87 24.94 47.65 50.21"/></svg>',
listTitle:function(item){
var project ={},phase = '',phasename='';
if(item.project){
project = _joe.getDataItem(item.project,"project");
if(item.project_phase){
phase = project.phases.where({id:item.project_phase})[0]||{name:''};
phasename = (phase.name)?' > '+phase.name:'';
}
}
return'<joe-full-right>'
+'<joe-subtitle>'+((item.points && item.points+' pts' )||'')+'</joe-subtitle>'
+'<joe-title>${RUN[_joe.SERVER.User.Render.cubes;${members};]}</joe-title></joe-full-right>'
//+'<joe-subtext>${RUN[_joe.getDataItemProp;${project};"project"]} </joe-subtext>'
+'<joe-subtext>'+(project.name||'')+phasename+' </joe-subtext>'
+`<joe-title>${item.name}</joe-title><joe-subtitle>${item.info}</joe-subtitle>
${item.due_date && `<joe-subtext>due ${item.due_date}</joe-subtext>`||''}`
},
searchables:['name','info','description','_id'],
sorter:[
'priority','project','status',
{field:'!due_date',display:'due'},
'name',
{field:'!joeUpdated',display:'updated'},
{field:'!points',display:'points'},
{field:'project_phase',display:'phase'},
],
// Curated summary for agents (normalized, stable)
summary:{
description:'Work item tracked against projects and users; used for planning and execution.',
purpose:'Tasks track units of work for users and projects. A task belongs to a single project (optional), has a single status, may have a single parent task, and can be associated to many users (members) and many tags. Use the task schema to manage actionable items, planning, and execution state; resolve related names via project/status/user/tag when presenting to users.',
labelField:'name',
defaultSort:{ field:'joeUpdated', dir:'desc' },
searchableFields:['name','info','description','_id'],
allowedSorts:['priority','project','status','due_date','name','joeUpdated','points','project_phase','created'],
relationships:{
outbound:[
{ field:'status', targetSchema:'status', cardinality:'one' },
{ field:'project', targetSchema:'project', cardinality:'one' },
{ field:'parent_task', targetSchema:'task', cardinality:'one' },
{ field:'members', targetSchema:'user', cardinality:'many' },
{ field:'tags', targetSchema:'tag', cardinality:'many' }
],
inbound:{ graphRef:'server/relationships.graph.json' }
},
joeManagedFields:['created','joeUpdated'],
fields:[
{ name:'_id', type:'string', required:true },
{ name:'itemtype', type:'string', required:true, const:'task' },
{ name:'name', type:'string', required:true },
{ name:'info', type:'string' },
{ name:'description', type:'string' },
{ name:'task_type', type:'string', enumValues:['task','chore','epic'] },
{ name:'status', type:'string', isReference:true, targetSchema:'status', required:true },
{ name:'project', type:'string', isReference:true, targetSchema:'project' },
{ name:'parent_task', type:'string', isReference:true, targetSchema:'task' },
{ name:'project_phase', type:'string' },
{ name:'priority', type:'number', enumValues:[1,2,3,1000] },
{ name:'due_date', type:'string', format:'date-time' },
{ name:'complete', type:'boolean' },
{ name:'members', type:'string', isArray:true, isReference:true, targetSchema:'user' },
{ name:'tags', type:'string', isArray:true, isReference:true, targetSchema:'tag' },
{ name:'points', type:'number' },
{ name:'time_estimate', type:'number' },
{ name:'joeUpdated', type:'string', format:'date-time', required:true },
{ name:'created', type:'string', format:'date-time', required:true }
]
},
task_types:['task','chore','epic'],
methods:{
addUser:function(userid,goto){
var current = _jco(true);
if(current.members.indexOf(userid) == -1){
current.members.push(userid);
_joe.Fields.rerender('members',{members:current.members});
}
if(goto){
_joe.gotoSection('manage');
}
},
doToday:function(){
var current = _jco(true);
var todaystr = $c.format(new Date(),'m/d/Y');
var overwrites = {due_date:todaystr};
var active_status = _joe.Data.status.where({
datasets:{$in:[current.itemtype]},
active:true,
}).sortBy('index')[0] || false;
if(active_status){
overwrites.status = active_status._id;
}
_joe.Fields.rerender('due_date,status',overwrites);
},
assigned:function(task,userid){
var userid = userid ||_joe.User._id;
if((task.members||[]).indexOf(userid) != -1){
return true;
}
var subs = (task.subtasks ||[]).where({assigned:userid});
if(subs.length){
return true;
}
return false;
},
setType:function(type){
if(type == "chore"){
_joe.Sections.unFocusAll();
_joe.gotoSection('tags',{focus:'tags',activate:'true'})
_joe.gotoSection('overview',{focus:'overview',activate:'true'})
_joe.gotoSection('glance',{focus:'glance',activate:'true'})
_joe.gotoSection('estimates',{focus:'estimates',activate:'true'})
_joe.gotoSection('subtasks',{focus:'subtasks',activate:'true'})
_joe.Sections.setTabbedMode(true);
_joe.Sections.toggleSome(['overview','glance','estimates'],true);
var wkflw = _joe.getData({query:{workflow_id:'chore'}})[0]||false;
if(wkflw && wkflw.statuses && wkflw.statuses[0]){
_joe.Fields.set('status',wkflw.statuses[0]);
}
}else{
_joe.Sections.unFocusAll();
_joe.Sections.setTabbedMode(false);
}
},
// (Deprecated) task-specific Thought trigger kept for backward compatibility if needed
},
onPanelShow:function(state){
},
menu:function(){
if(__jsu && ['super','admin','editor'].indexOf(__jsu.role) != -1 || $c.isEmpty(self.Data.user)){
return [
__exportBtn__,
_joe.SERVER.History.button,
{name:'assingme',title:'assign task to me', label:_joe.schemas.user.menuicon+'<button-text>Assign Me</button-text>', action:'_joe.schemas.task.methods.addUser(_joe.User._id,true)', css:'joe-left-button joe-orange-button joe-svg-button'},
{name:'dotoday',title:'today', label:_joe.schemas.event.menuicon+'<button-text>Today</button-text>', action:'_joe.schemas.task.methods.doToday()', css:'joe-left-button joe-orange-button joe-svg-button'},
__quicksaveBtn__,
__deleteBtn__
];
}
return [];
},
fields:function(){
var fields = [
{sidebar_start:'left'},
{section_start:'JAI',display:'JOE Ai'},
"objectChat",
"listConversations",
'proposeThought',
'ai_responses',
{section_end:'JAI'},
{sidebar_end:'left'},
{section_start:'overview'},
'name',
'info',
{extend:'description',specs:{
ai:{prompt:'Summarize the task in a few sentences. Take into account the project the task is associated with if there is one.'}}
},
{section_end:'overview'},
{section_start:'subtasks'},
{name:'subtasks',type:'objectList',label:false,
template:function(obj,subobj){
var done = (subobj.sub_complete)?'joe-strike':'';
return '<joe-full-right>'+(subobj.assigned && _renderUserCubes(_joe.getDataItem(subobj.assigned,'user'))||'')+'</joe-full-right>'
+'<joe-subtext>${sub_duedate}</joe-subtext>'
+'<joe-title class="'+done+'">${info}</joe-title>'
},
properties:[
{name:'info'},
{name:'sub_duedate', display:'due', type:'date',width:'50px'},
{name:'assigned',display:'asgt',type:'select',width:'50px',
onchange:'_joe.schemas.task.methods.addUser(this.value);',
values:function(item){
var opts = [];
var item = _jco(true);
if(item.members && item.members.length){
opts = opts.concat(item.members);
}
if(item.project){
var proj = _joe.getDataItem(item.project,'project');
if(proj.members && proj.members.length){
opts = opts.concat(proj.members);
}
}
//opts = $.unique(opts);
//opts(new Set(opts));
Array.from(new Set(opts));
if(!opts || !opts.length){
return [];
}
var users = _joe.Data.user.where({_id:{$in:opts}});
return users;
},blank:true,
idprop:'_id',template:function(t,u){
if(_joe.sizeClass == "large-size"){
return u.name;
}
var name = (u.first_name && u.first_name+' '+u.last_name) ||u.fullname || u.name;
if(!name){
return '';
}
var initials = name[0]+ (((name.indexOf(' ') > 0) && name[name.indexOf(' ')+1])||'');
return initials;
}
},
{name:'sub_complete',display:'done',type:'boolean',width:'50px'}
]
},
{section_end:'subtasks'},
{section_start:'acceptance',collapsed:function(item){
return !(item.scceptance_criteria && item.scceptance_criteria.length);
}},
{name:'scceptance_criteria',display:'acceptance criteria',type:'objectList',label:false,
template:function(obj,subobj){
var done = (subobj.sub_complete)?'joe-strike':'';
return '<joe-title class="'+done+'">${criteria}</joe-title>' ;
},
properties:[
{name:'criteria'},
{name:'sub_complete',display:'done',type:'boolean',width:'50px'}
]
},
{section_end:'acceptance'},
{section_start:'related',collapsed:function(item){
return !(item.files && item.files.length);
}},
{name:'files',type:'uploader',allowmultiple:true, height:'300px',comment:'drag files here to upload', onConfirm:_joe.SERVER.Plugins.awsFileUpload},
'references',
{section_end:'related'},
{sidebar_start:'right',collapsed:function(item){
if(_joe.sizeClass == "large-size"){
return false;
}
return (item.priority && item.project && item.status && item.due_date);
}},
{section_start:'glance'},
{name:'task_type',type:'select',display:'task type',
values:function(){
return (['']).concat(_joe.schemas.task.task_types);
},
onchange:'_joe.schemas.task.methods.setType(this.value);',
onPanelShow:function(cur){
console.log('CURRENT',cur);
if(cur.task_type){
_joe.schemas.task.methods.setType(cur.task_type);
}
}
},
'status',
{name:'due_date',type:'date',display:'due'},
{name:'complete',type:'boolean',display:'complete task',label:'click to hide from list'},
{section_end:'glance'},
{section_start:'organize'},
{name:'project',type:'select',values:'project',goto:'project',idprop:'_id',width:'50%',blank:true,rerender:'project_phase,subtasks,parent_task',icon:_joe.schemas.project.menuicon},
{name:'parent_task', width:'50%',
hidden:function(item){
return !item.project;
},goto:'task',
type:'select',values:function(item){
var query = {project:item.project};
if(item.project_phase){
query.project_phase = item.project_phase;
}
var tasks = _joe.Data.task.where(query).sortBy('project_phase,priority');
return tasks;
},icon:'task',
schema:'task',blank:true
},
{name:'project_phase',
type:'select',
blank:true,
rerender:'parent_task',
values:function(item){
if(!item.project){
return [];
}
var proj = _joe.getDataItem(item.project,'project');
if(!proj || !proj.phases || !proj.phases.length){
return [];
}
var vals = [];
proj.phases.map(function(phase){
vals.push({name:phase.name+' '+(phase.end_date && ' - '+phase.end_date ||''),value:phase.id||phase.name})
})
return vals;
},
display:'phase',width:'50%',hidden:function(item){
if(!item.project){
return true;
}
var proj = _joe.getDataItem(item.project,'project');
if(!proj || !proj.phases || !proj.phases.length){
return true;
}
return false;
}},
'priority',
{section_end:'organize'},
{section_start:'estimates'},
{name:'points',comment:'fte, scrum, etc',type:'number',display:'story points'},
{name:'time_estimate',comment:'minutes',type:'number',display:'time estimate'},
{section_end:'estimates'},
{section_start:'manage', collapsed:function(item){
return false;
return (item.members && item.members.length);
}},
{extend:'members',specs:{rerender:'subtasks'}},
{label:'comments'},
'user_comments',
{section_end:'manage'},
{section_start:'reports',collapsed:true},
'reports',
{section_end:'reports'},
{section_start:'tags',collapsed:true},
'tags',
{section_end:'tags'},
{section_start:'access'},
'_protected',
{section_end:'access'},
{sidebar_end:'right'},
{section_start:'system',collapsed:true},
'_id','created','itemtype',
{section_end:'system'}
];
return fields;
},
instance:{
checkbox:function(instance){
return {prop:'approved'}
},
fields:function(){
return [
{name:'approved',type:'boolean',display:'APPROVED','label':'click when task is approved',width:'50%'},
{name:'date',type:'date',width:'50%',native:true},
//'members',
{name:'members',type:'group',label:'completed by -',
values:function(){
return _joe.Data.user.where({custom_roles:{$in:['chore_assignee']}});
}
},
{name:'points',type:'number'},
{name:'files',type:'uploader',allowmultiple:true, height:'300px',comment:'drag files here to upload', onConfirm:_joe.SERVER.Plugins.awsFileUpload},
];
}
},
filters:function(){
if(!_joe.Cache.static.weekstart){
var curr = new Date;
var startD,endD;
startD = new Date(curr.setDate(curr.getDate() - curr.getDay() +1));
startD.setHours(0,0,0);
_joe.Cache.static.weekstart = _joe.Utils.toDateString(startD,{fullyear:true})
endD = new Date(curr.setDate(curr.getDate() - curr.getDay() +8))
endD.setHours(0,0,0);
_joe.Cache.static.weekend = _joe.Utils.toDateString(endD,{fullyear:true})
}
var filters = [];
var others =[
{group_start:'priorities',collapsed:true/*,name:'prioritized',
filter:{$and:[{priority:{$nin:[null,'']}},{priority:{$exists:true}}]}*/
},
{name:'priority 1',filter:{priority:1},
stripecolor:_joe.Colors.priority[1]},
{name:'priority 2',filter:{priority:2},stripecolor:
_joe.Colors.priority[2]},
{name:'priority 3',filter:{priority:3},
stripecolor:_joe.Colors.priority[3]},
{name:'unprioritized',filter:{priority:1000}},
{group_end:'priorities'},
{name:'My Tasks',filter:{members:{$in:[_joe.User._id]}}},
{name:'unassigned',filter:{complete:{$nin:['true',true]},$or:[{members:{$lte:0}},{members:{$exists:false}}]}},
{name:'this week',filter:{due_date:{$gte:_joe.Cache.static.weekstart,$lte:_joe.Cache.static.weekend}}}
];
var stats = _joe.Filter.Options.status({
schema:'task',
group:'status',
collapsed:true,
none:true
});
filters = filters.concat(stats,
_joe.Filter.Options.tags({
schema:'task',
group:'tags',
collapsed:true
}),
_joe.Filter.Options.datasetProperty('user','members',{
group:'members',
collapsed:true
}),
others
);
/*_joe.Data.status.sortBy('index')
.where({datasets:{$in:['task']}}).map(function(status){
stats.push({name:status.name,filter:{status:status._id},bgcolor:status.color})
})*/
return filters;
},
stripeColor:function(item){
if(item.priority && item.priority < 100){
return {
title:`P${item.priority}`,
color:_joe.Colors.priority[item.priority]
};
}
},
bgColor:function(item){
if(!item.status){
return '';
}
var status = _joe.getDataItem(item.status,'status');
/* var color = _joe.getDataItemProp(item.status,'status','color');*/
return {color:status.color,title:status.name};
},
/* stripeColor:[
{color:'#000',filter:{priority:1}},
{color:'#999',filter:{priority:2}}
],*/
checkbox:{prop:'complete',percentage:function(item){
if(!item.subtasks || !item.subtasks.length){
return false;
}
var subs = item.subtasks;
return (subs.filter(function(sub){return sub.sub_complete;}).length/subs.length);
}},
subsets:function(){
if(!_joe.Cache.static.weekstart){
var curr = new Date;
var startD,endD;
startD = new Date(curr.setDate(curr.getDate() - curr.getDay() +1));
startD.setHours(0,0,0);
_joe.Cache.static.weekstart = _joe.Utils.toDateString(startD,{fullyear:true})
endD = new Date(curr.setDate(curr.getDate() - curr.getDay() +8))
endD.setHours(0,0,0);
_joe.Cache.static.weekend = _joe.Utils.toDateString(endD,{fullyear:true})
}
var sets = [
{name:'ACTIVE',default:true,filter:
function(){
if(this.task_type == "chore"){
return false;
}
if(this.complete){
return false;
}
if(!this.status){
return false;
}
else{
//var s = _joe.Cache.get(this.status);
var s = $.get(this.status);
if(s.inactive || s.terminal || s.default){
return false;
}
}
return true;
}
},
{name:'Incomplete',filter:
function(){
if(this.complete){
return false;
}
if(this.status){
if(_joe.Cache.get(this.status).inactive){
return false;
}
}
return true;
}
},
{name:'inactive',filter:
function(){
if(this.complete){
return false;
}
if(this.status){
if(_joe.Cache.get(this.status).inactive){
return true;
}
}
return false;
}
},
//{name:'My Tasks',default:true,filter:{complete:{$nin:['true',true]},members:{$in:[_joe.User._id]}}},
{name:'My Tasks',filter:function(ind,item){
if(parseBoolean(this.complete)){
return false;
}
if((this.members||[]).indexOf(_joe.User._id) != -1){
return true;
}
var subs = (this.subtasks ||[]).where({assigned:_joe.User._id});
if(subs.length){
return true;
}
}},
// {complete:{$nin:['true',true]},members:{$in:[_joe.User._id]}}
{name:'this week',filter:{due_date:{$gte:_joe.Cache.static.weekstart,$lte:_joe.Cache.static.weekend}}},
];
sets.push({group_start:'projects',collapsed:true, name:'projects',filter:{project:{$in:[null,'']}}})
var projs = [];
_joe.Data.project.map(function(p){
if(p.complete != true){
projs.push({name: p.name,filter:{project: p._id,complete:{$nin:['true',true]}}});
}
});
sets = sets.concat(projs.sortBy('name'));
sets.push({group_end:'projects'})
var tts = [];
sets.push({group_start:'task_type',collapsed:false, name:'task type',filter:{project:{$in:[null,'']}}})
_joe.schemas.task.task_types.map(function(tt){
tts.push({name: tt,filter:{task_type: tt}});
});
sets = sets.concat(tts);
sets.push({group_end:'task_type'})
sets.push({name:'completed',sorter:['!joeUpdated'],filter:{complete:{$in:['true',true]}}});
return sets;
},
idprop : "_id",
onDemandExpander:true,
itemExpander:function(task){
if(task.subtasks && task.subtasks.length){
var subtask_html = '<joe-card><joe-title>Subtasks</joe-title>';
task.subtasks.map(function(st){
subtask_html +='<div class="joe-subtitle '+(st.assigned && "lh-30"||"")+' clear '
+(st.sub_complete && 'joe-strike' || '')+'">'
+((st.assigned && _renderUserCubes(_joe.getDataItem(st.assigned,'user')))||'')
+st.info
+((st.sub_duedate && ' - '+st.sub_duedate)||'')
+'</div>';
})
subtask_html+='</joe-card>';
//+fillTemplate('<div class="joe-subtitle">${info}</div>',task.subtasks);
return subtask_html;
}else{
return '';
}
},
new:function(){
var payload = {
itemtype:'task',
created:(new Date).toISOString(),
_id:cuid()
};
if(_joe.current.subset){
payload.project = (_joe.Data.project.where({name:_joe.current.subset.name})[0]||{_id:null})._id;
}
return payload;
},
report:{
name:'standard report',
info:'the report that comes with joe',
template:function(task,templateData){
var content = ``;
if(task.project){
var projectSchema = JOE.Schemas.schema.project;
var project = JOE.Cache.findByID("project",task.project);
content+=`
<report-section class="marginless">
<a class="report-content-item" target="_blank" href="/API/plugin/reportbuilder/standard/?itemid=${task.project}">
<report-icon>${projectSchema.menuicon}</report-icon>
<joe-subtitle>Project</joe-subtitle><joe-title>${project.name}</joe-title>
</a>
<div style="clear:both;"></div>
</report-section>
`;
}
if(task.description){
content+=`<report-section>
<report-section-label>Description</report-section-label>
${task.description}
</report-section>`;
}
if(task.subtasks && task.subtasks.length){
content+=`<report-section>
<report-section-label>Subtasks</report-section-label>
${task.subtasks.map(t=>{
return `<report-subtask class="complete-${t.sub_complete}">${t.info}</report-subtask>`;
}).join('')}
</report-section>`;
}
return content;
}
},
reports:{
chore_cards:{
name:'Chore Cards',
template_type:'module',
template:function(data){
var schema = JOE.Schemas.raw_schemas.task;
var icon = schema.menuicon;
//var icon = JOE.SC
var start=0,count=10,tasks;
if(data.request.query && data.request.query.where){
tasks = JOE.Data.task.where(eval('('+data.request.query.where+')'));
}else{
tasks = JOE.Data.task;
}
tasks = tasks.slice(start,count);
logit(tasks);
function renderCard(task){
return `<task-card><card-front>
<card-icon>${icon}</card-icon>
<joe-title>${task.name}</joe-title>
<card-points>${(task.points && `<pts-number>${task.points}</pts-number> pts`)||''}</card-points>
</card-front>
</task-card>`;
}
var template =`
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<link rel="stylesheet" href="/JsonObjectEditor/css/joe.css">
<link rel="stylesheet" href="/JsonObjectEditor/css/report-styles.css">
<link rel="icon" href="/chore_favicon.ico?v=2" type="image/x-icon" />
<link rel="icon" sizes="192x192" href="/chore-192x192.png">
<meta name="mobile-web-app-capable" content="yes">
<title>Chore Cards</title>
<style>
html,body{
background:#fff;
}
*{ padding:0; margin:0; position:relative;}
task-card{
width:calc(50% - 12px);
margin:4px;
height:198px;
border:2px solid #999;
display:block;
float:left;
}
card-front{
display:block;
text-align:center;
padding-top:20px;
}
card-icon {
position: absolute;
top: -10px;
left: -10px;
width: 80px;
opacity:.8;
}
card-points{
font-weight:bold;
color:#999;
font-size:24px;
}
card-front joe-title {
font-size: 24px;
margin: 30px 20px 10px 20px;
}
</style>
</head>
<body>
${tasks.map(renderCard).join('')}
</body>
</html>
`;
return template;
}
}
},
events:{
create:function(item,specs){
var members = item.members;
var member;
var status = JOE.Cache.findByID('status',item.status)||{};
var project = JOE.Cache.findByID('project',item.project)||{};
members.map(function(mem){
member = JOE.Cache.findByID('user',mem);
if(member){
logit('sending assignment email to: '+member.email);
/*cd75a051-dcec-4306-8894-e1dc64853306*/
JOE.Apps.plugins.notifier.sendNotification('TASK_ASSIGNED',{
ASSIGNED:member,
TASK:item,
PROJECT:project,
STATUS:status
})
}
})
},
save:function(item,specs){
$c.DEBUG_MODE =false;
if(specs.cached && specs.historical_info.changes && specs.historical_info.changes.members){
var cached_members = specs.cached.members;
var members = item.members;
var member;
var status = JOE.Cache.findByID('status',item.status)||{};
var project = JOE.Cache.findByID('project',item.project)||{};
members.map(function(mem){
if(cached_members.indexOf(mem) == -1){
member = JOE.Cache.findByID('user',mem);
if(member){
logit('sending assignment email to: '+member.email);
/*cd75a051-dcec-4306-8894-e1dc64853306*/
JOE.Apps.plugins.notifier.sendNotification('TASK_ASSIGNED',{
ASSIGNED:member,
TASK:item,
PROJECT:project,
STATUS:status
})
}
}
})
}
}
}
}
};
module.exports = task();