def get_task_status_select_wdg(task_sobject): """ Given a sthpw/task sobject, return a SelectWdg with all its potential status options. This is done by looking up what those options are through the parent Pipeline. :param task_sobject: sthpw/task sobject :return: SelectWdg """ task_status_select = SelectWdg('task_status_select') task_status_select.set_id('task_status_select') task_status_select.add_style('width: 165px;') task_status_select.add_empty_option() task_pipe_code = task_sobject.get_value('pipeline_code') # if the current task has no pipeline, then search for # any task pipeline if not task_pipe_code: # just use the default task_pipe_code = 'task' pipeline = Pipeline.get_by_code(task_pipe_code) if not pipeline: pipeline = Pipeline.get_by_code('task') for status in pipeline.get_process_names(): task_status_select.append_option(status, status) if task_sobject.get('status'): task_status_select.set_value(task_sobject.get('status')) return task_status_select
def execute(my): key = "enable_workflow_engine" from prod_setting import ProdSetting setting = ProdSetting.get_value_by_key(key) if setting not in [True, 'true']: return # find the node in the pipeline task = my.get_caller() sobject = task.get_parent() if not sobject: return pipeline = None process_code = task.get_value("process_code", no_exception=True) if process_code: process_sobj = Search.get_by_code("config/process", process_code) if process_sobj: pipeline_code = process_sobj.get_value("pipeline_code") pipeline = Pipeline.get_by_code("sthpw/pipeline", pipeline_code) if not pipeline: pipeline = Pipeline.get_by_sobject(sobject) if not pipeline: return process_name = task.get_value("process") status = task.get_value("status") process = pipeline.get_process(process_name) if not process: # we don't have enough info here return node_type = process.get_type() process_name = process.get_name() event = "process|%s" % status.lower() output = { 'sobject': sobject, 'pipeline': pipeline, 'process': process_name, } Trigger.call(task, event, output=output)
def handle_td(my, td): sobject = my.get_current_sobject() # find the pipeline code of the task pipeline_code = sobject.get_value('pipeline_code', no_exception=True) parent_pipeline_code = '' if my.parent: parent_pipeline_code = my.parent.get_value('pipeline_code', no_exception=True) # if not find the pipeline of the parent and match the process if not pipeline_code: task_process = sobject.get_value("process") if task_process: parent = my.parent if parent: parent_pipeline_code = parent.get_value('pipeline_code', no_exception=True) pipeline = Pipeline.get_by_code(parent_pipeline_code) if pipeline: attributes = pipeline.get_process_attrs(task_process) pipeline_code = attributes.get('task_pipeline') value = my.get_value() color = Task.get_default_color(value) # If task status pipeline is chosen, # use color attribute from status (process) if pipeline_code: td.set_attr("spt_pipeline_code", pipeline_code) pipeline = Pipeline.get_by_code(pipeline_code) if pipeline: #attributes = pipeline.get_process_attrs(value) #color = attributes.get("color") process = pipeline.get_process(value) if process: color = process.get_color() if not color: process_sobject = pipeline.get_process_sobject(value) if process_sobject: color = process_sobject.get_value("color") if color: td.add_style("background-color: %s" % color) if parent_pipeline_code: td.set_attr("spt_parent_pipeline_code", parent_pipeline_code) super(TaskStatusElementWdg, my).handle_td(td)
def __init__(self, name='task_status', task_pipeline=None): '''by default, it should grab all sthpw/task pipelines''' if not task_pipeline: project_code = Project.get_project_code() task_pipeline = Pipeline.get_by_search_type('sthpw/task', project_code) if isinstance(task_pipeline, list): self.task_pipelines = task_pipeline else: self.task_pipelines = [Pipeline.get_by_code(task_pipeline)] self.process_names = [] self.checkbox_control = None super(TaskStatusFilterWdg,self).__init__(name) self.label = "Task Status Filter: " self.set_persistence()
def notify_listeners(my): '''The command must have operated on an sobject with a pipeline and the operation must have been done on a process in that pipeline''' # find the sobject that this command operated on sobjects = my.get_sobjects() if not sobjects: return sobject = sobjects[0] if not sobject.has_value("pipeline_code"): return # we have sufficient information current_pipeline_code = my.get_pipeline_code() if not current_pipeline_code: current_pipeline_code = sobject.get_value("pipeline_code") current_process = my.get_process() event = my.get_event_name() if not current_pipeline_code or not current_process: return # get the pipelne (for in pipeline process) pipeline = Pipeline.get_by_code(current_pipeline_code) my.handle_pipeline(pipeline, current_process, event)
def _add_options(my): ''' add the options to the select ''' search_type = my._get_search_type() if not search_type: return # get all processes if no search type is given proj_code = Project.extract_project_code(search_type) is_group_restricted = False if my.has_empty: my.add_first_option() else: from asset_filter_wdg import ProcessFilterWdg if ProcessFilterWdg.has_restriction(): is_group_restricted = True process_names, process_values = Pipeline.get_process_select_data(\ search_type, is_filter=my.is_filter, project_code=proj_code,\ is_group_restricted=is_group_restricted, sobject = my._sobject) my.set_option("values", process_values) my.set_option("labels", process_names) if not my.is_filter: behavior = { 'type': 'onchange', 'cbjs_action': "if (bvr.src_el.value=='')\ {alert('Please choose a valid process.');}" }
def handle_td(my, td): super(LoginTableElementWdg, my).handle_td(td) task = my.get_current_sobject() if task: search_type = task.get_value('search_type') search_id = task.get_value('search_id') if not search_type or not search_id: return search_key = SearchKey.build_search_key(search_type, search_id, column='id') from pyasm.common import SObjectSecurityException try: parent = Search.get_by_search_key(search_key) pipeline = Pipeline.get_by_sobject(parent) if pipeline: attrs = pipeline.get_process_attrs(task.get_value('process')) td.add_attr('spt_pipeline_code', attrs.get('%s_login_group'%my.get_name())) except SObjectSecurityException, e: pass except SearchException, e: if e.__str__().find('not registered') != -1: pass elif e.__str__().find('does not exist for database') != -1: pass elif e.__str__().find('Cannot find project') != -1: pass else: raise
def execute(my): input = my.get_input() search_key = input.get("search_key") update_data = input.get("update_data") if not search_key or search_key.startswith('sthpw/'): return mode = input.get("mode") if mode not in ['insert']: return sobject = my.get_caller() pipeline_code = sobject.get_value("pipeline_code", no_exception=True) if not pipeline_code: return from pyasm.biz import Pipeline, Task from pyasm.search import SearchType pipeline = Pipeline.get_by_code(pipeline_code) if not pipeline: return if pipeline.get_value("autocreate_tasks", no_exception=True) not in ['true', True]: return #import time #start = time.time() Task.add_initial_tasks(sobject, pipeline_code=pipeline_code, skip_duplicate=True, mode='standard')
def get_context_data(my, search_type=None): '''get the list of contexts that can be checked in with this widget''' # usually there is no pipeline for prod/shot_instance #search_type = my.search_type labels, values = Pipeline.get_process_select_data(search_type, \ project_code=Project.get_project_code()) return labels, values
def get_color(my, sobject, index): div = DivWdg() colors = [ div.get_color("background3"), div.get_color("background3", -10), div.get_color("background3", -20), ] default_color = colors[index%3] pipeline_code = sobject.get_value("pipeline_code") if not pipeline_code: pipeline_code = "task" """ parent = sobject.get_parent() if not parent: #return default_color pipeline_code = "task" else: pipeline_code = parent.get_value("pipeline_code", no_exception=True) if not pipeline_code: #return default_color pipeline_code = "task" """ pipeline = Pipeline.get_by_code(pipeline_code) if not pipeline: return default_color """ process_name = sobject.get_value("process") if not process_name: process_name = sobject.get_value("context") # get the process process = pipeline.get_process(process_name) if not process: return default_color """ status = sobject.get_value("status") process = pipeline.get_process(status) if not process: return default_color color = process.get_color() if not color: return default_color else: color = Common.modify_color(color, 0) return color
def execute(my): input = my.get_input() sobject = my.get_caller() if isinstance(sobject, Task): task = sobject else: process = input.get("process") raise Exception("Not supported yet") # get the task process process = task.get_value("process") status = task.get_value("status") pipeline_code = task.get_value("pipeline_code") if not pipeline_code: pipeline_code = 'task' task_pipeline = Pipeline.get_by_code(pipeline_code) if not task_pipeline: return # get the last process statuses = task_pipeline.get_process_names() if not statuses: return completion_statuses = [] for status in statuses: status_obj = task_pipeline.get_process(status) attrs = status_obj.get_attributes() completion = attrs.get("completion") if completion == "100": completion_statuses.append(status) if not completion_statuses: completion_statuses.append(statuses[-1]) is_complete = False update_data = input.get('update_data') if update_data.get("status") in completion_statuses: is_complete = True if is_complete == True: #task.set_value("is_complete", True) if not task.get_value("actual_end_date"): task.set_now("actual_end_date") my.add_description('Internal Task Complete Trigger') task.commit(triggers=False)
def get_process_names(my): '''get a unique list of process names''' search_type = my._get_search_type() proj_code = Project.extract_project_code(search_type) dict = Pipeline.get_process_name_dict(search_type, project_code=proj_code) process_list = [] for x in dict.values(): process_list.extend(x) names = Common.get_unique_list(process_list) return names
def get_file_in_package_status_select(): task_status_select = SelectWdg('file_status_select') task_status_select.set_id('file_status_select') task_status_select.add_style('width: 165px;') task_status_select.add_empty_option() pipeline = Pipeline.get_by_code('twog_Delivery') for status in pipeline.get_process_names(): task_status_select.append_option(status, status) return task_status_select
def get_display(my): widget = DivWdg() pipeline_code = my.get_option('pipeline') pipeline = Pipeline.get_by_code(pipeline_code) if not pipeline: widget.add("No pipeline defined") return widget processes = pipeline.get_process_names() widget.add_style("border: solid 1px blue") widget.add_style("position: absolute") widget.add_style("top: 300") widget.add_style("left: -500") for process in processes: #inputs = pipeline.get_input_processes(process) outputs = pipeline.get_output_processes(process) div = DivWdg() widget.add(div) div.add_class("spt_input_option") div.add_attr("spt_input_key", process) #if not outputs: # # then we can't go anywhere, so just add a message # text = "" # div.add(text) # continue values = [] #values.extend( [str(x) for x in inputs] ) values.append(process) values.extend( [str(x) for x in outputs] ) select = SelectWdg(my.get_input_name()) select.set_value(process) select.add_empty_option('-- Select --') select.set_option("values", values) div.add(select) from tactic.ui.panel import CellEditWdg CellEditWdg.add_edit_behavior(select) return widget
def last_process_finished(my, pipeline, task_process, is_subpipeline=False): ''' find if the last process is finished ''' if not pipeline: return True last_processes = pipeline.get_backward_connects(task_process) # TODO: use get_input_processes #last_processes = pipeline.get_input_processes(task_process) # subpipeline scenario if task_process.find("/") != -1: pipeline_code, process = task_process.split("/", 1) pipeline = Pipeline.get_by_code(pipeline_code) return my.last_process_finished(pipeline, process, is_subpipeline=True) # the first process of the pipe should be green-lit if not last_processes: return True for process in last_processes: # if the process is from another pipeline # TODO: disabling for now full_process = process if is_subpipeline: full_process = '%s/%s' %(pipeline.get_code(), process) complete_list = my.process_completion_dict.get(full_process) # skip processes that have no tasks # count is a safe-guard in case pipeline.get_backward_connects() # does not return None or [] in the future by accident # so the limit for a pipeline is 60 processes for now. count = 0 while not complete_list and last_processes and count < 60: count = count + 1 last_processes = pipeline.get_backward_connects(process) for process in last_processes: full_process = process if is_subpipeline: full_process = '%s/%s' %(pipeline.get_code(), process) complete_list = my.process_completion_dict.get(full_process) # previous processes have no tasks assigned, in other words, they are finished if not complete_list: return True for item in complete_list: if item != 100: return False return True
def get_color(my, sobject, index): div = DivWdg() colors = [ div.get_color("background3"), div.get_color("background3", -10), div.get_color("background3", -20), ] default_color = colors[index%3] try: color = sobject.get("color") if color: return color except: pass bg_color, text_color = my.color_map.get('status') if bg_color: color_value = bg_color.get(sobject.get_value('status')) if color_value: return color_value pipeline_code = sobject.get_value("pipeline_code", no_exception=True) if not pipeline_code: pipeline_code = "task" pipeline = Pipeline.get_by_code(pipeline_code) if not pipeline: return default_color status = sobject.get_value("status", no_exception=True) process = pipeline.get_process(status) if not process: return default_color color = process.get_color() if not color: return default_color else: color = Common.modify_color(color, 0) return color
def notify_listeners(my, sobject, process, status): # find all of the nodes that are listening to this status event = "%s|%s|%s" % (sobject.get_search_key(), process, status) #Trigger.call(my, event, my.input) # or search = Search("sthpw/process") search.add_filter("type", "listen") search.add_filter("key", event) process_sobjs = search.get_sobjects() # we have all of the processes that are listening for process_sobj in process_sobjs: # for each process, we need to find the related sobjects # so what exactly does this do ... # shouldn't this use triggers? pipeline_code = process_sobj.get_value("pipeline_code") pipeline = Pipeline.get_by_code(pipeline_code) # find all of the related sobjects process_obj = pipeline.get_process(process) related_search_type = process_obj.get_attribute("search_type") related_status = process_obj.get_attribute("status") related_process = process_obj.get_attribute("process") related_scope = process_obj.get_attribute("scope") # get the node's triggers if not related_search_type: search = Search("config/process") search.add_filter("process", my.process) search.add_filter("pipeline_code", pipeline.get_code()) process_sobj = search.get_sobject() workflow = process_sobj.get_json_value("workflow") related_search_type = workflow.get("search_type") related_proces = workflow.get("proces") related_status = workflow.get("status") related_scope = workflow.get("scope")
def execute(my): from pyasm.biz import Task, Pipeline src_task = my.get_caller() process = src_task.get_value("process") status = src_task.get_value("status") pipeline_code = src_task.get_value("pipeline_code") if pipeline_code == "approval": tasks = src_task.get_output_tasks() if status == "Revise": pass else: tasks = src_task.get_output_tasks(type="approval") # for approval, the task must be completed completion = src_task.get_completion() if completion != 100: return if not tasks: # autocreate ?? parent = src_task.get_parent() pipeline = Pipeline.get_by_sobject(parent) if not pipeline: return processes = pipeline.get_output_processes(process, type="approval") if not processes: return if processes: print "Missing task: ", processes # set those approvals to "Pending" for task in tasks: task.set_value("status", "Pending") task.commit()
def get_context_data(my, search_type='', process=''): '''get the labels and values of contexts that can be checked in with this widget''' # TODO: this also shows input contexts ... it should only show output # contexts if not search_type: search_type = my.search_type pipelines = Pipeline.get_by_search_type(search_type, Project.get_project_code() ) if not pipelines: return [], [] # account for sub-pipeline if '/' in process: process = process.split('/', 1)[1] contexts = [] for pipeline in pipelines: pipeline_contexts = [] pipeline_processes = pipeline.get_process_names() if process: if process not in pipeline_processes: continue pipeline_contexts = pipeline.get_output_contexts(process) else: pipeline_contexts = pipeline.get_all_contexts() for context in pipeline_contexts: # for now, cut out the sub_context, until the pipeline # completely defines the sub contexts as well if context.find("/") != -1: parts = context.split("/") context = parts[0] if context not in contexts: contexts.append(context) labels = contexts values = contexts return labels, values
def get_display(my): current = my.get_current_sobject() search_type = get_search_type() parent_key = WebContainer.get_web().get_form_value("edit|asset") if parent_key != "": parent = Search.get_by_search_key(parent_key) # get all of the options for this search type status_attr_name = "status" status_attr = parent.get_attr(status_attr_name) pipeline = status_attr.get_pipeline() else: # FIXME: make this general by looking at the current asset pipeline = Pipeline.get_by_name("flash_shot") processes = pipeline.get_process_names() my.set_option("values", "|".join(processes) ) return super(TaskProcessSelectWdg,my).get_display()
def preprocess(my): if my.sobjects: try: search = Search(Task) search_ids = [x.get_id() for x in my.sobjects] search.add_filters("search_id", search_ids) search_type = my.sobjects[0].get_search_type() search.add_filter("search_type", search_type) # go thru children of main search search = my.alter_task_search(search, prefix='children') # go thru Local Search search = my.alter_task_search(search, prefix='main_body', prefix_namespace=my.__class__.__name__) sobj = my.sobjects[0] pipeline = Pipeline.get_by_sobject(sobj) if pipeline: process_names = pipeline.get_process_names(True) search.add_enum_order_by("process", process_names) else: search.add_order_by("process") search.add_order_by("id") tasks = search.get_sobjects() # create a data structure for task in tasks: search_type = task.get_value("search_type") search_id = task.get_value("search_id") search_key = "%s|%s" % (search_type, search_id) sobject_tasks = my.data.get(search_key) if not sobject_tasks: sobject_tasks = [] my.data[search_key] = sobject_tasks sobject_tasks.append(task) except: from tactic.ui.app import SearchWdg parent_search_type = get_search_type() SearchWdg.clear_search_data(parent_search_type) raise
def check_rule(my): task = my.sobject assigned = task.get_value("assigned") task_process = task.get_value("process") task_description = task.get_value("description") # get the pipeline my.parent = task.get_parent() pipeline_code = my.parent.get_value("pipeline_code") my.pipeline = Pipeline.get_by_code(pipeline_code) if not my.pipeline: # No pipeline, so don't email print "Warning: No Pipeline" return False task_status = task.get_value("status") if task_status == "Review": return True else: return False
def get_color(my, sobject, index): div = DivWdg() pipeline_code = sobject.get_value("pipeline_code") if not pipeline_code: pipeline_code = "task" pipeline = Pipeline.get_by_code(pipeline_code) if not pipeline: return default_color status = sobject.get_value("status") process = pipeline.get_process(status) if not process: return default_color color = process.get_color() if not color: return default_color else: color = Common.modify_color(color, 0) return color
def execute(self): input = self.get_input() search_key = input.get("search_key") update_data = input.get("update_data") if not search_key or search_key.startswith('sthpw/'): return mode = input.get("mode") if mode not in ['insert']: return sobject = self.get_caller() pipeline_code = sobject.get_value("pipeline_code", no_exception=True) if not pipeline_code: return from pyasm.biz import Pipeline, Task from pyasm.search import SearchType pipeline = Pipeline.get_by_code(pipeline_code) if not pipeline: return if pipeline.get_value("autocreate_tasks", no_exception=True) not in ['true', True]: return #import time #start = time.time() Task.add_initial_tasks(sobject, pipeline_code=pipeline_code, skip_duplicate=True, mode='standard')
def get_legend_wdg(my): #my.search_type = my.kwargs.get("search_type") #if not my.search_type == "sthpw/task": # return None div = DivWdg() div.add_style("margin: 20px 10px 20px 10px") div.add_style("font-size: 0.8em") table = Table() div.add(table) table.add_row() pipeline_code = 'task' pipeline = Pipeline.get_by_code(pipeline_code) process_names = pipeline.get_process_names() for process_name in process_names: color = pipeline.get_process(process_name).get_color() color_div = DivWdg() td = table.add_cell(color_div) color_div.add(" ") color_div.add_style("width: 10px") color_div.add_style("height: 10px") color_div.add_style("float: left") color_div.add_style("background: %s" % color) color_div.add_style("margin: 2px 5px 0px 15px") color_div.add_border() #color_div.set_box_shadow("0px 0px 5px") td.add(process_name) #td.add(color) return div
def handle_td(self, td): super(LoginTableElementWdg, self).handle_td(td) task = self.get_current_sobject() if task: search_type = task.get_value('search_type') search_id = task.get_value('search_id') if not search_type or not search_id: return search_key = SearchKey.build_search_key(search_type, search_id, column='id') from pyasm.common import SObjectSecurityException try: parent = Search.get_by_search_key(search_key) pipeline = Pipeline.get_by_sobject(parent) if pipeline: attrs = pipeline.get_process_attrs( task.get_value('process')) td.add_attr('spt_pipeline_code', attrs.get('%s_login_group' % self.get_name())) except SObjectSecurityException as e: pass except SearchException as e: if e.__str__().find('not registered') != -1: pass elif e.__str__().find('does not exist for database') != -1: pass elif e.__str__().find('Cannot find project') != -1: pass else: raise
def init(my): web = WebContainer.get_web() my.parent_key = my.kwargs.get('parent_key') my.append_context = my.kwargs.get('append_context') my.is_refresh = my.kwargs.get('is_refresh') == 'true' my.resize = my.kwargs.get('resize') == 'true' my.checkbox_name = my.kwargs.get('checkbox_name') my.orig_parent = None my.show_context = my.kwargs.get('show_context') if not my.show_context: my.show_context = web.get_form_value('show_context') my.show_context = my.show_context == 'true' my.view = my.kwargs.get('view') incoming_process = False if my.parent_key: my.parent = Search.get_by_search_key(my.parent_key) my.orig_parent = my.parent my.orig_parent_search_type = my.parent.get_search_type() my.parent_search_type = my.parent.get_search_type() my.parent_search_id = my.parent.get_id() else: my.parent_search_type = my.kwargs.get('search_type') my.orig_parent_search_type = my.parent_search_type my.parent_search_id = my.kwargs.get('search_id') my.parent = Search.get_by_id(my.parent_search_type, my.parent_search_id) my.orig_parent = my.parent if my.use_parent: my.parent = my.parent.get_parent() if not my.parent: raise TacticException( 'Try not to use the display option [use_parent] since the parent cannot be found.' ) if my.parent: my.parent_key = SearchKey.get_by_sobject(my.parent) if my.use_parent: my.kwargs['parent_key'] = my.parent_key my.kwargs['use_parent'] = 'false' my.process_names = [] my.checked_processes = [] # get the process names process_names = web.get_form_values('process_names') #process_names = my.kwargs.get('process_names') if not process_names: if my.orig_parent_search_type in ['sthpw/task', 'sthpw/snapshot']: #my.parent = my.parent.get_parent() # most tasks don't have context by default if my.orig_parent_search_type == 'sthpw/task': context = my.orig_parent.get_value('context') if not context: context = my.orig_parent.get_value('process') else: context = my.orig_parent.get_value('context') my.process_names = [context] my.child_mode = True my.kwargs['child_mode'] = 'true' else: my.pipeline_code = my.kwargs.get('pipeline_code') if not my.pipeline_code and my.parent.has_value( 'pipeline_code'): my.pipeline_code = my.parent.get_value('pipeline_code') pipeline = Pipeline.get_by_code(my.pipeline_code) if pipeline: my.process_names = pipeline.get_process_names() else: my.process_names = process_names incoming_process = True # if nothing is derived from pipeline, use defualts if not my.process_names: my.process_names = ['default'] if my.append_context and not incoming_process: contexts = my.append_context.split('|') my.process_names.extend(contexts)
def get_display(self): web = WebContainer.get_web() # this needs to be a BaseInputWdg since UserFilterWdg is hideable user_filter = FilterSelectWdg("user_filter") user_filter = user_filter.get_values() #login = Environment.get_security().get_login() #user = login.get_value("login") if self.is_refresh: widget = Widget() self.init_cgi() else: self.sobject = self.get_current_sobject() widget = DivWdg(id="task_elem_%s"% self.sobject.get_id()) widget.add_class('spt_task_panel') try: self.set_as_panel(widget) except: pass #TODO: remove this self.init_setup(widget) #self.set_ajax_top(widget) table = Table(css="minimal") table.add_style("width: 100%") # get all of the tasks related to this sobject search_type = self.sobject.get_search_type() search_id = self.sobject.get_id() if self.data: tasks = self.data.get("%s|%s" % (search_type,search_id) ) else: tasks = Task.get_by_sobject(self.sobject) self.data[self.sobject.get_search_key()] = tasks if not tasks: tasks = [] task_statuses_filter = web.get_form_values("task_status") show_sub_tasks = False if not task_statuses_filter: # NOTE: Not sure if this is correct!! # have to do this because it is impossible to tell if a checkbox # is empty or not there. This is used for pages that do not have # tasks_status checkboxes show_all_tasks = True else: cb = FilterCheckboxWdg('show_all_tasks') show_all_tasks = cb.is_checked(False) sub_cb = FilterCheckboxWdg('show_sub_tasks') show_sub_tasks = sub_cb.is_checked(False) # trim down the process list """ if not show_sub_tasks: process_list = [x for x in process_list if "/" not in x] """ pipeline = Pipeline.get_by_sobject(self.sobject) # retrieve the pipeline if not pipeline: td = table.add_cell("<br/><i>No pipeline</i>") td.add_style("text-align: center") return table # store completion per process first in a dict # reset it first self.process_completion_dict = {} for task in tasks: task_process = task.get_value("process") status_attr = task.get_attr('status') percent = status_attr.get_percent_completion() self.store_completion(task_process, percent) security = WebContainer.get_security() me = Environment.get_user_name() for task in tasks: has_valid_status = True task_pipeline = task.get_pipeline() task_statuses = task_pipeline.get_process_names() task_process = task.get_value("process") # Commenting this out. It is not very meaningful in 2.5 ... # we need a better mechanism. The end result of this code # is that "admin" never sees any tasks #if security.check_access("public_wdg", "SObjectTaskTableElement|unassigned", "deny", is_match=True): # assignee = task.get_value("assigned") # if assignee != me: # continue if not show_all_tasks: """ if process_list and task_process not in process_list: continue """ # skip sub tasks if not show_sub_tasks and '/' in task_process: continue task_status = task.get_value("status") if task_status not in task_statuses: has_valid_status = False if has_valid_status and task_status \ and task_status not in task_statuses_filter: continue # the first one shouldn't be empty if user_filter and user_filter[0] and task.get_value("assigned") not in user_filter: continue table.add_row() #link = "%s/Maya/?text_filter=%s&load_asset_process=%s" % (web.get_site_context_url().to_string(), self.sobject.get_code(), task_process) #icon = IconButtonWdg("Open Loader", IconWdg.LOAD, False) #table.add_cell( HtmlElement.href(icon, link, target='maya') ) td = table.add_cell(css='no_wrap') description = task.get_value("description") expand = ExpandableTextWdg() expand.set_max_length(50) expand.set_value(description) assigned = task.get_value("assigned").strip() status_wdg = SimpleStatusWdg() status_wdg.set_sobject(task) status_wdg.set_name("status") # refresh myself on execution of SimpleStatusCmd #post_scripts = self.get_refresh_script(show_progress=False) post_scripts = '''var panel = bvr.src_el.getParent('.spt_task_panel'); var search_top = spt.get_cousin(bvr.src_el, '.spt_view_panel','.spt_search'); var search_val = spt.dg_table.get_search_values(search_top); var values = spt.api.Utility.get_input_values(panel); values['json'] = search_val; spt.panel.refresh(panel, values);''' status_wdg.set_post_ajax_script(post_scripts) if assigned: user_info = UserExtraInfoWdg(assigned).get_buffer_display() else: user_info = HtmlElement.i(" unassigned").get_buffer_display() info_span = SpanWdg() info_span.add(TaskExtraInfoWdg(task)) info_span.add("- ") info_span.add(" [%s]" % user_info) if UserAssignWdg.has_access() and self.get_option('supe')=='true': self._add_user_assign_wdg(task, info_span, widget) td.add( info_span ) #-------------- self.calendar_bar.set_sobject(task) # set always recalculate since each task is set individually self.calendar_bar.set_always_recal(True) #--------------- td.add_color('color','color') td.add(HtmlElement.br()) if description: td.add(expand) td.add(HtmlElement.br()) td.add(status_wdg) if self.last_process_finished(pipeline, task_process): dot = IconWdg(icon=IconWdg.DOT_GREEN) dot.add_tip("All dependent processs complete") dot.add_style('float','left') dot.add_style('display','block') td.add(dot) else: dot = IconWdg(icon=IconWdg.DOT_RED) dot.add_tip("Dependent process in progress") dot.add_style('float','left') dot.add_style('display','block') td.add(dot) date_display = None if self.get_option('simple_date') == 'true': start_wdg = DateWdg() start_wdg.set_option("pattern", "%b %d") start_wdg.set_name('bid_start_date') start_wdg.set_sobject(task) end_wdg = DateWdg() end_wdg.set_name('bid_end_date') end_wdg.set_option("pattern", "%b %d") end_wdg.set_sobject(task) date_display = '%s - %s' %(start_wdg.get_buffer_display(), \ end_wdg.get_buffer_display()) else: self.calendar_bar.set_sobject(task) # set always recalculate since each task is set individuallly self.calendar_bar.set_always_recal(True) self.calendar_bar.set_option("width", "40") self.calendar_bar.set_option("bid_edit", self.get_option('bid_edit')) date_display = self.calendar_bar.get_buffer_display() #td = table.add_cell(date_display, css='smaller') td.add(FloatDivWdg(date_display, float='right', css='smaller')) #td.set_style("width: 120; padding-left: 15px") # This uses the parallel status widget to display status of # dependent tasks dependent_processes = pipeline.get_input_contexts(task_process) from parallel_status import ParallelStatusWdg dep_status_div = DivWdg() dep_status_div.add_style("padding-right: 10px") dep_status_wdg = ParallelStatusWdg() dep_status_wdg.set_process_names(dependent_processes) dep_status_wdg.set_label_format("abbr") dep_status_wdg.set_sobject(self.sobject) #dep_status_wdg.preprocess() dep_status_wdg.set_data(self.data) dep_status_div.add(dep_status_wdg) td.add(dep_status_div) #td.add_style("border-style: solid") #td.add_style("border-bottom: 1px") #td.add_style("border-color: #999") td.add_style("padding: 3px 0 3px 0") widget.add(table) return widget
def process_sobjects(sobjects, search=None): '''process sobjects order according to pipeline process order''' if not sobjects: return if search: order_list = search.get_order_bys() # it could be search_type asc or search_tpe desc # that means the user has applied an order by in some specific column if order_list and not order_list[0].startswith('search_type'): return parent = None last_parent = None last_parent_key = None parents = [] groups = [] group = None # group tasks according to parent for i, sobject in enumerate(sobjects): # get the parent key search_type = sobject.get_value("search_type") search_id = sobject.get_value("search_id") parent_key = "%s|%s" % (search_type, search_id) process = sobject.get_value('process') if parent_key != last_parent_key: parent = SearchKey.get_by_search_key(parent_key) parents.append(parent) group = [] groups.append(group) group.append(sobject) last_parent_key = parent_key new_sobjects = [] # reorder each group for i, group in enumerate(groups): parent = parents[i] processes = [] if parent: pipeline_code = parent.get_value("pipeline_code") pipeline = Pipeline.get_by_code(pipeline_code) if pipeline: processes = pipeline.get_process_names(recurse=True) if processes: # build a sorting key dict sort_dict = {} for sobject in group: process = sobject.get_value('process') try: sort_dict[sobject] = processes.index(process) except ValueError: # put at the bottom for outdated processes # this is important to still display tasks with outdated processe names sort_dict[sobject] = len(processes) sorted_group = sorted(group, key=sort_dict.__getitem__) new_sobjects.extend(sorted_group) else: new_sobjects.extend(group) return new_sobjects
def init(my): # for snapshot and task my.child_mode = my.kwargs.get('child_mode') == 'true' my.search_key = my.kwargs.get('search_key') my.element_class = my.kwargs.get('element_class') my.use_parent = my.kwargs.get('use_parent') == 'true' my.append_context = my.kwargs.get('append_context') my.orig_parent = None incoming_process = False if my.search_key: # coming in as search_key but it's actually the note's parent my.parent = Search.get_by_search_key(my.search_key) my.orig_parent = my.parent my.orig_parent_search_type = my.parent.get_search_type() if my.use_parent: my.parent = my.parent.get_parent() if not my.parent: raise TacticException( 'Try not to set the display option [use_parent] to true since the parent cannot be found.' ) my.search_key = SearchKey.get_by_sobject(my.parent) # swap the kwargs key my.kwargs['search_key'] = my.search_key my.kwargs['use_parent'] = 'false' my.parent_search_type = my.parent.get_search_type() my.parent_search_id = my.parent.get_id() else: my.parent_search_type = my.kwargs.get('search_type') my.orig_parent_search_type = my.parent_search_type my.parent_search_id = my.kwargs.get('search_id') my.parent = Search.get_by_id(my.parent_search_type, my.parent_search_id) my.orig_parent = my.parent if my.use_parent: my.parent = my.parent.get_parent() if not my.parent: raise TacticException( 'Try not to use the display option [use_parent] since the parent cannot be found.' ) if my.parent: my.search_key = SearchKey.get_by_sobject(my.parent) if my.use_parent: my.kwargs['search_key'] = my.search_key my.kwargs['use_parent'] = 'false' my.process_names = [] # get the process names process_names = my.kwargs.get('process_names') if not process_names: if my.orig_parent_search_type in ['sthpw/task', 'sthpw/snapshot']: #my.parent = my.parent.get_parent() # most tasks don't have context by default if my.orig_parent_search_type == 'sthpw/task': context = my.orig_parent.get_value('context') if not context: context = my.orig_parent.get_value('process') else: context = my.orig_parent.get_value('context') my.process_names = [context] my.child_mode = True my.kwargs['child_mode'] = 'true' else: my.pipeline_code = my.kwargs.get('pipeline_code') if not my.pipeline_code and my.parent.has_value( 'pipeline_code'): my.pipeline_code = my.parent.get_value('pipeline_code') pipeline = Pipeline.get_by_code(my.pipeline_code) if pipeline: my.process_names = pipeline.get_process_names() else: my.process_names = process_names.split("|") incoming_process = True my.is_refresh = my.kwargs.get('is_refresh') # if nothing is derived from pipeline, use defualts if not my.process_names: my.process_names = ['default'] if my.append_context and not incoming_process: contexts = my.append_context.split('|') my.process_names.extend(contexts) # for proper refresh my.kwargs['process_names'] = '|'.join(my.process_names)
def execute(my): web = WebContainer.get_web() value = web.get_form_value('value') if my.search_key == None or value == None or my.attr_name == None: raise CommandExitException() sobject = Search.get_by_search_key(my.search_key) old_value = sobject.get_value(my.attr_name) sobject.set_value(my.attr_name, value) sobject.commit() # setting target attributes if sobject is a task if sobject.get_search_type_obj().get_base_key() == Task.SEARCH_TYPE: task = sobject # FIXME: not sure what this if for??? my.users = [task.get_value("assigned")] process_name = task.get_value('process') task_description = task.get_value("description") my.parent = task.get_parent() # it should be task, notification will get the parent in the # email trigger logic my.sobject = task code = my.parent.get_code() name = my.parent.get_name() my.info['parent_centric'] = True my.description = "%s set to '%s' for %s (%s), task: %s, %s" % (\ my.attr_name.capitalize(), value, code, name, process_name, task_description) # set the states of the command pipeline = Pipeline.get_by_sobject(my.parent) process = pipeline.get_process(process_name) completion = task.get_completion() if pipeline and process: my.set_process(process_name) my.set_pipeline_code( pipeline.get_code() ) if completion == 100: my.set_event_name("task/approved") else: my.set_event_name("task/change") else: my.sobject = sobject code = my.sobject.get_code() my.description = "%s set to '%s' for %s" % (\ my.attr_name.capitalize(), value, code) process_name = "None" my.info['parent_centric'] = False my.sobjects.append(my.sobject) # set the information about this command my.info['to'] = value my.info['process'] = process_name
def get_shelf_wdg(my): process = my.get_value("process") versions = my.get_value("versions") div = DivWdg() filter_table = Table() div.add(filter_table) filter_table.add_row() button = SingleButtonWdg(title="Refresh", icon=IconWdg.REFRESH) filter_table.add_cell(button) filter_table.add_cell(" "*5) button.add_behavior( { 'type': 'click_up', 'cbjs_action': ''' spt.panel.refresh(bvr.src_el); ''' } ) # get all of the pipelnes for this search type pipeline_code = my.sobject.get_value("pipeline_code", no_exception=True) processes = [] if pipeline_code: pipeline = Pipeline.get_by_code(pipeline_code) if pipeline: process_names = pipeline.get_process_names() processes.extend(process_names) processes.insert(0, "all") filter_table.add_cell("Process: ") select = SelectWdg("process") select.add_style("width: 200px") if process != 'all': select.set_value(process) select.set_option("values", processes) filter_table.add_cell(select) filter_table.add_cell(" "*10) filter_table.add_cell("Versions: ") select = SelectWdg("versions") select.add_style("width: 200px") select.set_option("values", "latest|current|today|last 10|all") if versions: select.set_value(versions) filter_table.add_cell(select) asset_dir = Environment.get_asset_dir() select = IconButtonWdg( tip="Toggle Selection", icon=IconWdg.SELECT, show_arrow=False ) div.add(select) select.add_style("float: right") select.add_behavior( { 'type': 'click_up', 'cbjs_action': ''' var top_class = 'spt_sobject_dir_list_top' var toggle_state = bvr.src_el.getAttribute('toggle'); if (toggle_state && toggle_state=='true') bvr.src_el.setAttribute('toggle','false'); else bvr.src_el.setAttribute('toggle','true'); var top = bvr.src_el.getParent("."+top_class); spt.selection.set_top(top); toggle_state = bvr.src_el.getAttribute('toggle'); if (toggle_state == 'true') spt.selection.select_all_items(); else spt.selection.unselect_all_items(); ''' } ) show = IconButtonWdg( tip="Switch View", icon=IconWdg.VIEW, show_arrow=False ) div.add(show) show.add_style("float: right") show.add_behavior( { 'type': 'click_up', 'cbjs_action': ''' var top_class = 'spt_sobject_dir_list_top' var top = bvr.src_el.getParent("."+top_class); spt.selection.set_top(top); var els = top.getElements(".spt_file_dir_item"); for (var i = 0; i < els.length; i++) { var el = els[i]; if (el.getStyle("display") == "none") { els[i].setStyle("display", ""); } else { els[i].setStyle("display", "none"); } } var els = top.getElements(".spt_file_item"); for (var i = 0; i < els.length; i++) { var el = els[i]; if (el.getStyle("padding-left") == "6px") { var padding = el.getAttribute("spt_padding_left"); el.setStyle("padding-left", padding); } else { el.setStyle("padding-left", "6px"); } } ''' } ) gear = IconButtonWdg( tip="Download", icon=IconWdg.DOWNLOAD, show_arrow=False ) div.add(gear) gear.add_style("float: right") gear.add_behavior( { 'type': 'click_up', 'cbjs_action': ''' spt.app_busy.show('Select a folder to download to...',''); var top_class = 'spt_sobject_dir_list_top'; var top = bvr.src_el.getParent("."+top_class); spt.selection.set_top(top); var items = spt.selection.get_selected(); setTimeout( function() { var applet = spt.Applet.get(); var select_dir =true; var dir = applet.open_file_browser('', select_dir); if (dir.length == 0) dir = applet.get_current_dir(); else dir = dir[0]; if (!dir) { spt.alert("No folder selected to copy to."); spt.app_busy.hide(); return; } if (items.length == 0){ spt.alert("Please select at least one file to download."); spt.app_busy.hide(); return; } var asset_dir = '%s'; for (var i = 0; i < items.length; i++) { var path = items[i].getAttribute("spt_path"); var env = spt.Environment.get(); var server_url = env.get_server_url(); var url = server_url + "/assets/" + path.replace(asset_dir, ""); var parts = path.split("/"); var filename = parts[parts.length-1]; spt.app_busy.show("Downloading file", filename); applet.download_file(url, dir + "/" + filename); } spt.app_busy.hide(); if (dir) spt.notify.show_message("Download to '" + dir + "' completed.") }, 100); ''' % asset_dir } ) return div
def handle_td(self, td): sobject = self.get_current_sobject() edit_scope = self.get_option("edit_scope") if edit_scope == "assigned": login = Environment.get_user_name() user = Environment.get_login() security = Environment.get_security() if not security.is_admin() and login != sobject.get_value("assigned"): td.add_class("spt_cell_no_edit") # find the pipeline code of the task pipeline_code = sobject.get_value('pipeline_code', no_exception=True) parent_pipeline_code = '' if self.parent: parent_pipeline_code = self.parent.get_value('pipeline_code', no_exception=True) if sobject.get_base_search_type() == "sthpw/snapshot": pipeline_code = "snapshot" # if not find the pipeline of the parent and match the process if not pipeline_code: task_process = sobject.get_value("process") if task_process: parent = self.parent if parent: parent_pipeline_code = parent.get_value('pipeline_code', no_exception=True) pipeline = Pipeline.get_by_code(parent_pipeline_code) if pipeline: attributes = pipeline.get_process_attrs(task_process) pipeline_code = attributes.get('task_pipeline') value = self.get_value() color = Task.get_default_color(value) # If task status pipeline is chosen, # use color attribute from status (process) if pipeline_code: td.set_attr("spt_pipeline_code", pipeline_code) pipeline = Pipeline.get_by_code(pipeline_code) if pipeline: #attributes = pipeline.get_process_attrs(value) #color = attributes.get("color") process = pipeline.get_process(value) if process: color = process.get_color() if not color: process_sobject = pipeline.get_process_sobject(value) if process_sobject: color = process_sobject.get_value("color") if color: td.add_style("background-color: %s" % color) if parent_pipeline_code: td.set_attr("spt_parent_pipeline_code", parent_pipeline_code) super(TaskStatusElementWdg, self).handle_td(td)
def get_shelf_wdg(self): process = self.get_value("process") versions = self.get_value("versions") div = DivWdg() filter_table = Table() div.add(filter_table) filter_table.add_row() button = SingleButtonWdg(title="Refresh", icon=IconWdg.REFRESH) filter_table.add_cell(button) filter_table.add_cell(" " * 5) button.add_behavior({ 'type': 'click_up', 'cbjs_action': ''' spt.panel.refresh(bvr.src_el); ''' }) # get all of the pipelnes for this search type pipeline_code = self.sobject.get_value("pipeline_code", no_exception=True) processes = [] if pipeline_code: pipeline = Pipeline.get_by_code(pipeline_code) if pipeline: process_names = pipeline.get_process_names() processes.extend(process_names) processes.insert(0, "all") filter_table.add_cell("Process: ") select = SelectWdg("process") select.add_style("width: 200px") if process != 'all': select.set_value(process) select.set_option("values", processes) filter_table.add_cell(select) filter_table.add_cell(" " * 10) filter_table.add_cell("Versions: ") select = SelectWdg("versions") select.add_style("width: 200px") select.set_option("values", "latest|current|today|last 10|all") if versions: select.set_value(versions) filter_table.add_cell(select) asset_dir = Environment.get_asset_dir() select = IconButtonWdg(tip="Toggle Selection", icon=IconWdg.SELECT, show_arrow=False) div.add(select) select.add_style("float: right") select.add_behavior({ 'type': 'click_up', 'cbjs_action': ''' var top_class = 'spt_sobject_dir_list_top' var toggle_state = bvr.src_el.getAttribute('toggle'); if (toggle_state && toggle_state=='true') bvr.src_el.setAttribute('toggle','false'); else bvr.src_el.setAttribute('toggle','true'); var top = bvr.src_el.getParent("."+top_class); spt.selection.set_top(top); toggle_state = bvr.src_el.getAttribute('toggle'); if (toggle_state == 'true') spt.selection.select_all_items(); else spt.selection.unselect_all_items(); ''' }) show = IconButtonWdg(tip="Switch View", icon=IconWdg.VIEW, show_arrow=False) div.add(show) show.add_style("float: right") show.add_behavior({ 'type': 'click_up', 'cbjs_action': ''' var top_class = 'spt_sobject_dir_list_top' var top = bvr.src_el.getParent("."+top_class); spt.selection.set_top(top); var els = top.getElements(".spt_file_dir_item"); for (var i = 0; i < els.length; i++) { var el = els[i]; if (el.getStyle("display") == "none") { els[i].setStyle("display", ""); } else { els[i].setStyle("display", "none"); } } var els = top.getElements(".spt_file_item"); for (var i = 0; i < els.length; i++) { var el = els[i]; if (el.getStyle("padding-left") == "6px") { var padding = el.getAttribute("spt_padding_left"); el.setStyle("padding-left", padding); } else { el.setStyle("padding-left", "6px"); } } ''' }) gear = IconButtonWdg(tip="Download", icon=IconWdg.DOWNLOAD, show_arrow=False) div.add(gear) gear.add_style("float: right") gear.add_behavior({ 'type': 'click_up', 'cbjs_action': ''' spt.app_busy.show('Select a folder to download to...',''); var top_class = 'spt_sobject_dir_list_top'; var top = bvr.src_el.getParent("."+top_class); spt.selection.set_top(top); var items = spt.selection.get_selected(); setTimeout( function() { var applet = spt.Applet.get(); var select_dir =true; var dir = applet.open_file_browser('', select_dir); if (dir.length == 0) dir = applet.get_current_dir(); else dir = dir[0]; if (!dir) { spt.alert("No folder selected to copy to."); spt.app_busy.hide(); return; } if (items.length == 0){ spt.alert("Please select at least one file to download."); spt.app_busy.hide(); return; } var asset_dir = '%s'; for (var i = 0; i < items.length; i++) { var path = items[i].getAttribute("spt_path"); var env = spt.Environment.get(); var server_url = env.get_server_url(); var url = server_url + "/assets/" + path.replace(asset_dir, ""); var parts = path.split("/"); var filename = parts[parts.length-1]; spt.app_busy.show("Downloading file", filename); applet.download_file(url, dir + "/" + filename); } spt.app_busy.hide(); if (dir) spt.notify.show_message("Download to '" + dir + "' completed.") }, 100); ''' % asset_dir }) return div
def get_display(my): show_context = my.get_option('context') == 'true' top = DivWdg() # put in a js callback to determine the to use. top.add_class("spt_input_top") context_list = [] my.pipeline_codes = [] my.pipelines = [] my.in_edit_wdg = False parent_key = my.get_option("parent_key") if not parent_key: state = my.get_state() parent_key = state.get("parent_key") if parent_key: parent = Search.get_by_search_key(parent_key) pipeline_code = parent.get_value("pipeline_code", no_exception=True) if pipeline_code: top.add_attr("spt_cbjs_get_input_key", "return '%s'" % pipeline_code) else: # This is quite slow, but it works #top.add_attr("spt_cbjs_get_input_key", "var server=TacticServerStub.get(); var parent_key = cell_to_edit.getParent('.spt_table_tbody').getAttribute('spt_parent_key'); var parent = server.get_by_search_key(parent_key); return parent.pipeline_code") # ProcessElementWdg's handle_td() sets the spt_pipeline_code attribute top.add_attr( "spt_cbjs_get_input_key", "return cell_to_edit.getAttribute('spt_pipeline_code')") # Need to import this dynamically from tactic.ui.panel import EditWdg # This is only executed for the popup edit widget if hasattr(my, 'parent_wdg') and isinstance(my.get_parent_wdg(), EditWdg): my.in_edit_wdg = True sobject = my.get_current_sobject() parent = sobject.get_parent() if not parent: parent_key = my.get_option('parent_key') if parent_key: parent = SearchKey.get_by_search_key(parent_key) if parent: if not parent.has_value('pipeline_code'): name = my.get_input_name() text = TextWdg(name) top.add(text) sobject = my.get_current_sobject() name = my.get_name() value = sobject.get_value(name) text.set_value(value) return top #raise TacticException('[%s] needs a pipeline_code attribute to insert task.'%parent.get_code()) pipe_code = parent.get_value('pipeline_code') if pipe_code: my.pipeline_codes = [pipe_code] my.pipelines = [Pipeline.get_by_code(pipe_code)] else: # just get all of the pipelines # Cannot use expression here, because entries are added to the # result ... this causes further queries to return with the # added entries #my.pipelines = Search.eval("@SOBJECT(sthpw/pipeline)") search = Search("sthpw/pipeline") my.pipelines = search.get_sobjects() my.pipeline_codes = [x.get_code() for x in my.pipelines] # add the default my.pipeline_codes.append("") my.pipelines.append(None) for i, pipeline_code in enumerate(my.pipeline_codes): pipeline = my.pipelines[i] div = DivWdg() top.add(div) div.add_class("spt_input_option") div.add_attr("spt_input_key", pipeline_code) name = my.get_input_name() # If the pipeline code is empty, make it free form (for now) if not pipeline_code: text = TextWdg(name) div.add(text) continue select = SelectWdg(name) select.add_empty_option("-- Select a %s --" % my.get_name()) # TODO: make spt.dg_table.select_wdg_clicked keyboard action free so it won't interfere with # normal usage of the select if not my.in_edit_wdg: select.add_behavior({ 'type': 'click', 'cbjs_action': 'spt.dg_table.select_wdg_clicked( evt, bvr.src_el );' }) if not pipeline: continue # get the sub-pipeline processes as well processes = pipeline.get_processes(recurse=True) values = [] labels = [] for process in processes: is_sub_pipeline = False if process.is_from_sub_pipeline(): process_name = process.get_full_name() is_sub_pipeline = True else: process_name = process.get_name() # show context instead if show_context: output_contexts = pipeline.get_output_contexts( process.get_name()) for context in output_contexts: values.append(context) if is_sub_pipeline: #label = process_name label = context else: label = context labels.append(label) else: values.append(process_name) labels.append(process_name) select.set_option("values", values) select.set_option("labels", labels) div.add(select) # there is only 1 select for EditWdg if hasattr(my, 'parent_wdg') and isinstance( my.get_parent_wdg(), EditWdg): sobject = my.get_current_sobject() # this could be either process or context name = my.get_name() value = sobject.get_value(name) # special case to append a context with subcontext so it will stay selected in EditWdg if name == 'context' and value.find('/') != -1: select.append_option(value, value) if value: select.set_value(value) return top
def handle_instance(my, table, instance, asset, node_name='', publish=True, allow_ref_checkin=False): # handle the case where asset is not defined if not asset: table.add_row() table.add_blank_cell() table.add_blank_cell() # FIXME: Maya specific parts = instance.split(":") instance_name = parts[0] asset_code = parts[1] if instance_name == asset_code: table.add_cell(instance_name) else: table.add_cell(instance) td = table.add_cell() td.add("< %s node >" % my.session.get_node_type(instance_name)) table.add_blank_cell() return # get the pipeline for this asset and handlers for the pipeline process_name = my.process_select.get_value() handler_hidden = my.get_handler_input(asset, process_name) pipeline = Pipeline.get_by_sobject(asset) # TEST: switch this to using node name instead, if provided if node_name: instance_node = my.session.get_node(node_name) else: instance_node = my.session.get_node(instance) if instance_node is None: return if Xml.get_attribute(instance_node, "reference") == "true": is_ref = True else: is_ref = False namespace = Xml.get_attribute(instance_node, "namespace") if not namespace: namespace = instance asset_code = asset.get_code() is_set = False if asset.get_value('asset_type', no_exception=True) in ['set', 'section']: is_set = True tr = table.add_row() if is_set: tr.add_class("group") if publish and (allow_ref_checkin or not is_ref): checkbox = CheckboxWdg("asset_instances") if is_set: checkbox = CheckboxWdg("set_instances") checkbox.set_option("value", "%s|%s|%s" % \ (namespace, asset_code, instance) ) checkbox.set_persist_on_submit() td = table.add_cell(checkbox) else: td = table.add_blank_cell() # only one will be added even if there are multiple if handler_hidden: td.add(handler_hidden) # add the thumbnail thumb = ThumbWdg() thumb.set_name("images") thumb.set_sobject(asset) thumb.set_icon_size(60) table.add_cell(thumb) info_wdg = Widget() info_wdg.add(HtmlElement.b(instance)) if not node_name: node_name = '%s - %s' % (asset_code, asset.get_name()) info_div = DivWdg(node_name) info_div.add_style('font-size: 0.8em') info_wdg.add(info_div) info_div.add(HtmlElement.br(2)) if pipeline: info_div.add(pipeline.get_code()) table.add_cell(info_wdg) # by default can't checkin references if not allow_ref_checkin and is_ref: #icon = IconWdg("error", IconWdg.ERROR) #td = table.add_cell(icon) td = table.add_cell() td.add(HtmlElement.b("Ref. instance")) ''' import_button = ProdIconButtonWdg('import') import_button.add_event('onclick', "import_instance('%s')" %instance) td.add(import_button) ''' table.add_cell(my.get_save_wdg(my.current_sobject)) elif publish: textarea = TextAreaWdg() textarea.set_persist_on_submit() textarea.set_name("%s_description" % instance) textarea.set_attr("cols", "35") textarea.set_attr("rows", "2") table.add_cell(textarea) table.add_cell(my.get_save_wdg(my.current_sobject)) else: table.add_blank_cell() table.add_blank_cell()
def preprocess(my): '''determine if this is for EditWdg or EDIT ROW of a table''' # get the number of task pipelines needed for EditWdg, which is one # for the EDIT ROW , there could be more than 1 my.task_mapping = None from tactic.ui.panel import EditWdg if hasattr(my, 'parent_wdg') and isinstance(my.get_parent_wdg(), EditWdg): task = my.get_current_sobject() task_pipe_code = task.get_value('pipeline_code') # if the current task has no pipeline, then search for # any task pipeline if not task_pipe_code: # just use the default task_pipe_code = 'task' pipeline = Pipeline.get_by_code(task_pipe_code) if not pipeline: pipeline = Pipeline.get_by_code('task') my.task_pipelines = [pipeline] else: # get all of the pipelines for tasks search = Search('sthpw/pipeline') search.add_regex_filter('search_type', 'sthpw/task') my.task_pipelines = search.get_sobjects() # get all of the pipelines for the current search_type search_type = my.state.get("search_type"); search = Search('sthpw/pipeline') if search_type: search.add_filter('search_type', search_type) my.sobject_pipelines = search.get_sobjects() # insert the default task pipeline if not overridden in the db default_task_found = False pipeline_codes = SObject.get_values(my.task_pipelines, 'code') if 'task' in pipeline_codes: default_task_found = True if not default_task_found: default_pipe = Pipeline.get_by_code('task') my.task_pipelines.append(default_pipe) my.task_mapping = {} # the following works for insert but on edit, it should read from pipeline_code attribute for pipeline in my.sobject_pipelines: processes = pipeline.get_process_names() for process in processes: attrs = pipeline.get_process_attrs(process) task_pipeline = attrs.get('task_pipeline') if task_pipeline: key = '%s|%s' %(pipeline.get_code(), process) my.task_mapping[key] = task_pipeline #my.task_mapping = "|".join(my.task_mapping) my.is_preprocess = True
def execute(self): data = self.kwargs.get("data") for pipeline_code, pipeline_data in data.items(): pipeline = Pipeline.get_by_code(pipeline_code) if not pipeline: pipeline = SearchType.create("sthpw/pipeline") pipeline.set_value("code", pipeline_code) # get the task_pipeline for this process prev_pipeline_xml = pipeline.get_value("pipeline") # get the input data processes = pipeline_data.get("process") process_types = pipeline_data.get("process_type") process_xpos = pipeline_data.get("process_xpos") process_ypos = pipeline_data.get("process_ypos") statuses = pipeline_data.get("task_status") descriptions = pipeline_data.get("description") # go through each process and build up the xml pipeline_xml = self.create_pipeline_xml(processes, process_types, process_xpos, process_ypos) pipeline.set_value("pipeline", pipeline_xml) pipeline.set_pipeline(pipeline_xml) pipeline.on_insert() pipeline_xml = pipeline.get_xml_value("pipeline") # need to commit to get the pipeline code pipeline.commit() pipeline_code = pipeline.get_value("code") # this one doesn't call pipeline.update_process_table() since it adds additional description for i, process in enumerate(processes): if not process: continue description = descriptions[i] # create the process as well search = Search("config/process") search.add_filter("pipeline_code", pipeline_code) search.add_filter("process", process) process_obj = search.get_sobject() if process_obj: if description != process_obj.get_value("description"): process_obj.set_value("description", description) process_obj.commit() # handle the statuses for each process for process, process_type, xpos, ypos, status in \ zip(processes, process_types, process_xpos, process_ypos, statuses): if process == '': continue # skip if it's not task related if process_type not in ['manual','approval']: continue if status == '(default)': node = pipeline_xml.get_node("/pipeline/process[@name='%s']" % process) pipeline_xml.del_attribute(node, "task_pipeline") default_pipeline = Pipeline.get_by_code('task') default_pipeline.update_process_table() continue status_list = status.split(",") # task status pipeline status_xml = self.create_pipeline_xml(status_list) project_code = Project.get_project_code() status_code = "%s/%s" % (project_code, process) status_pipeline = Search.get_by_code("sthpw/pipeline", status_code) if not status_pipeline: status_pipeline = SearchType.create("sthpw/pipeline") status_pipeline.set_value("description", 'Status pipeline for process [%s]'%process) status_pipeline.set_value("code", status_code) # since pipeline name is preferred now status_pipeline.set_value("name", status_code) status_pipeline.set_value("search_type", "sthpw/task") # update_process_table relies on this status_pipeline.set_pipeline(status_xml) else: status_pipeline.set_pipeline(status_xml) status_pipeline.on_insert() status_pipeline.set_value("pipeline", status_xml) status_pipeline.commit() status_pipeline_code = status_pipeline.get_code() # get the process node node = pipeline_xml.get_node("/pipeline/process[@name='%s']" % process) pipeline_xml.set_attribute(node, "task_pipeline", status_pipeline_code) # commit the changes again to get the task pipelines pipeline.set_value("pipeline", pipeline_xml.to_string()) pipeline.commit()
def get_display(self): top = self.top top.add_color("background", "background") top.add_class("spt_pipelines_top") self.set_as_panel(top) inner = DivWdg() top.add(inner) search_type = self.kwargs.get("search_type") pipeline_code = self.kwargs.get("pipeline_code") if search_type: search = Search("sthpw/pipeline") search.add_filter("search_type", search_type) pipelines = search.get_sobjects() else: pipeline = Pipeline.get_by_code(pipeline_code) if pipeline: pipelines = [pipeline] else: pipelines = [] if not pipelines: div = DivWdg() inner.add(div) inner.add_style("padding: 50px") div.add_border() div.add_color("color", "color3") div.add_color("background", "background3") div.add_style("width: 400px") div.add_style("height: 100px") div.add_style("padding: 30px") icon = IconWdg("WARNING", IconWdg.WARNING) div.add(icon) div.add("<b>This Searchable Type does not have pipelines defined.</b>") div.add("<br/>"*2) div.add("<b style='padding-left: 35px'>Click Create to add one...</b>") div.add("<br/>"*2) button_div = DivWdg() div.add(button_div) button = ActionButtonWdg(title="Create", tip="Create pipeline") button_div.add(button) button.add_style("margin: auto") button.add_behavior( { 'type': 'click_up', 'search_type': search_type, 'cbjs_action': ''' var server = TacticServerStub.get(); var cmd = 'tactic.ui.startup.PipelineCreateCbk'; var kwargs = { search_type: bvr.search_type } server.execute_cmd(cmd, kwargs) var top = bvr.src_el.getParent(".spt_pipelines_top"); spt.panel.refresh(top); ''' } ) return top # get the defalt task statuses task_pipeline = Pipeline.get_by_code("task") if task_pipeline: statuses = task_pipeline.get_process_names() else: statuses = ['Pending', 'In Progress', 'Complete'] statuses_str = ",".join(statuses) pipelines_div = DivWdg() inner.add( pipelines_div ) pipelines_div.add_style("font-size: 12px") pipelines_div.add_style("padding: 10px") buttons_div = DivWdg() pipelines_div.add(buttons_div) #button = SingleButtonWdg( title="Save Pipelines", icon=IconWdg.SAVE ) button = ActionButtonWdg( title="Save" ) buttons_div.add(button) button.add_behavior( { 'type': 'click_up', 'default_statuses': statuses_str, 'cbjs_action': ''' spt.app_busy.show("Saving Pipeline...") setTimeout(function() { try { var top = bvr.src_el.getParent(".spt_pipelines_top"); // get all the pipeline divs var pipeline_els = top.getElements(".spt_pipeline_top"); var data = {}; for ( var i = 0; i < pipeline_els.length; i++) { var pipeline_code = pipeline_els[i].getAttribute("spt_pipeline_code"); var values = spt.api.Utility.get_input_values(pipeline_els[i]); data[pipeline_code] = values; } var class_name = 'tactic.ui.startup.PipelineEditCbk'; var kwargs = { data: data } var server = TacticServerStub.get(); server.execute_cmd(class_name, kwargs); } catch(e) { spt.alert(spt.exception.handler(e)); } spt.app_busy.hide(); } , 100); ''' } ) buttons_div.add("<br clear='all'/>") buttons_div.add_style("margin-bottom: 5px") for pipeline in pipelines: pipeline_div = DivWdg() pipelines_div.add(pipeline_div) pipeline_div.add_class("spt_pipeline_top") code = pipeline.get_code() label = '%s (%s)' %(pipeline.get('name'), code) pipeline_div.add_attr("spt_pipeline_code", code) title = DivWdg() pipeline_div.add(title) title.add("Pipeline: ") title.add(label) title.add_style("padding: 8px 10px") title.add_color("background", "background3") title.add_style("font-weight: bold") title.add_style("margin: -10 -10 5 -10") header_wdg = DivWdg() pipeline_div.add(header_wdg) header_wdg.add_color("background", "background", -5) headers = ['Process', 'Description', 'Task Status'] widths = ['100px', '180px', '210px'] for header, width in zip(headers,widths): th = DivWdg() header_wdg.add(th) th.add("<b>%s</b>" % header) th.add_style("float: left") th.add_style("width: %s" % width) th.add_style("padding: 8px 3px") header_wdg.add("<br clear='all'/>") # get all of the process sobjects from this pipeline pipeline_code = pipeline.get_code() search = Search("config/process") search.add_filter("pipeline_code", pipeline.get_code() ) process_sobjs = search.get_sobjects() process_sobj_dict = {} for process_sobj in process_sobjs: process = process_sobj.get_value("process") process_sobj_dict[process] = process_sobj from tactic.ui.container import DynamicListWdg dyn_list = DynamicListWdg() pipeline_div.add(dyn_list) pipeline_div.add_style("width: 725px") processes = pipeline.get_process_names() if not processes: processes.append("") processes.append("") processes.append("") processes.insert(0, "") for i, process in enumerate(processes): if process == '': process_name = '' description = '' else: process_sobj = process_sobj_dict.get(process) if process_sobj: process_name = process_sobj.get_value("process") description = process_sobj.get_value("description") else: if isinstance(process,basestring): process_name = process else: process_name = process.get_name() deccription = '' process_type = 'manual' process_xpos = '' process_ypos = '' # get the task pipeline for this process if process_name: process = pipeline.get_process(process_name) process_type = process.get_type() process_xpos = process.get_attribute('xpos') process_ypos = process.get_attribute('ypos') task_pipeline_code = process.get_task_pipeline() if task_pipeline_code != "task": task_pipeline = Search.get_by_code("sthpw/pipeline", task_pipeline_code) else: task_pipeline = None else: task_pipeline_code = "task" task_pipeline = None process_div = DivWdg() process_div.add_style("float: left") process_div.add_class("spt_process_top") if i == 0: dyn_list.add_template(process_div) else: dyn_list.add_item(process_div) #process_div.add_style("padding-left: 10px") #process_div.add_style("margin: 5px") table = Table() process_div.add(table) table.add_row() text = TextInputWdg(name="process") process_cell = table.add_cell(text) text.add_style("width: 95px") text.add_style("margin: 5px") text.set_value(process_name) text.add_class("spt_process") # the template has a border if i == 0: text.add_style("border: solid 1px #AAA") hidden = HiddenWdg(name='process_type') hidden.set_value(process_type) process_cell.add(hidden) hidden = HiddenWdg(name='process_xpos') hidden.set_value(process_xpos) process_cell.add(hidden) hidden = HiddenWdg(name='process_ypos') hidden.set_value(process_ypos) process_cell.add(hidden) text = TextInputWdg(name="description") table.add_cell(text) text.add_style("width: 175px") text.add_style("margin: 5px") text.set_value(description) # the template has a border if i == 0: text.add_style("border: solid 1px #AAA") if process_type in ['manual','approval']: read_only = False else: read_only = True text = TextInputWdg(name="task_status", read_only=read_only) table.add_cell(text) text.add_style("width: 325px") text.add_style("margin: 5px") #text.set_value(statuses_str) #text.add_style("opacity: 0.5") text.add_style("border-style: none") if process_type in ['manual','approval']: if task_pipeline: statuses = task_pipeline.get_process_names() text.set_value(",".join(statuses)) else: text.set_value("(default)") text.add_behavior( { 'type': 'click_up', 'statuses': statuses_str, 'cbjs_action': ''' if (bvr.src_el.value == '(default)') { bvr.src_el.value = bvr.statuses; } ''' } ) table.add_cell(" "*2) button = IconButtonWdg(tip="Trigger", icon=IconWdg.ARROW_OUT) table.add_cell(button) button.add_behavior( { 'type': 'click_up', 'search_type': search_type, 'pipeline_code': pipeline_code, 'cbjs_action': ''' var top = bvr.src_el.getParent(".spt_process_top"); var process_el = top.getElement(".spt_process"); var process = process_el.value; if (process == "") { alert("Process value is empty"); return; } var class_name = 'tactic.ui.tools.TriggerToolWdg'; var kwargs = { mode: "pipeline", process: process, pipeline_code: bvr.pipeline_code }; spt.panel.load_popup("Trigger", class_name, kwargs); ''' } ) """ button = IconButtonWdg(tip="Edit", icon=IconWdg.EDIT) table.add_cell(button) button.add_behavior( { 'type': 'click_up', 'search_type': search_type, 'pipeline_code': pipeline_code, 'cbjs_action': ''' var top = bvr.src_el.getParent(".spt_process_top"); var process_el = top.getElement(".spt_process"); var process = process_el.value; if (process == "") { alert("Process value is empty"); return; } var class_name = 'tactic.ui.panel.EditWdg'; var kwargs = { expression: "@SOBJECT(config/process['process','"+process+"'])" } spt.panel.load_popup("Trigger", class_name, kwargs); ''' } ) """ table.add_cell(" "*3) pipeline_div.add("<br clear='all'/>") pipeline_div.add("<br clear='all'/>") if self.kwargs.get("is_refresh"): return inner else: return top
def get_pipeline(my): return Pipeline.get_by_code(my.get_value('pipeline'))
def get_display(self): self.task_per_process_dict = {} # get the sobject and relevent parameters sobject = self.get_current_sobject() search_type = sobject.get_search_type() if self.pipeline_code: pipeline = Pipeline.get_by_code(self.pipeline_code) else: pipeline = Pipeline.get_by_sobject(sobject, allow_default=True) if not pipeline: # while default is auto-generated, an empty pipeline code will trigger this Environment.add_warning('missing pipeline code', \ "Pipeline code is empty for [%s]" %sobject.get_code()) return if self.include_sub_task_value: self.recurse = True processes = pipeline.get_processes(recurse=self.recurse) # filter out process names if self.process_names != None: filtered_processes = [] for process in processes: if process.get_name() in self.process_names: filtered_processes.append(process) processes = filtered_processes # draw the proceses top = DivWdg() action = DivWdg() action.add_style("float: right") top.add(action) table = Table() table.add_style("font-size: 11px") top.add(table) #if self.max_count: # percent_width = float(len(processes)) / float(self.max_count+1) * 100 #else: # percent_width = 100 # we want them more squeezed together when in abbr mode if self.label_select_value != 'abbr': percent_width = 100 table.add_style("width: %d%%" % percent_width) tr = table.add_row() for process in processes: completion_wdg = self.get_completion(sobject, process,\ len(processes)) if not completion_wdg: continue td = table.add_cell(completion_wdg) td.add_style('border-width: 0px') tr = table.add_row(css='underline') tr.add_color("color", "color") label_format = self.get_option("label_format") if not label_format: label_format = self.label_select_value tup_list = self._get_labels(processes, label_format, show_sub_pipeline=self.is_ajax()) style = '' for i, tup in enumerate(tup_list): name, process = tup span = SpanWdg() child_pipeline = process.get_child_pipeline() if child_pipeline: title = SpanWdg() title.add("[%s]" % name) title.add_style("margin-left: -5px") swap = SwapDisplayWdg.get_triangle_wdg() content_id = '%s_%s' % (sobject.get_search_key(), child_pipeline.get_id()) content_id = self.generate_unique_id(content_id) content = DivWdg(id=content_id) SwapDisplayWdg.create_swap_title(title, swap, content) dyn_load = AjaxLoader(display_id=content_id) args_dict = {'search_type': sobject.get_search_type()} args_dict['search_id'] = sobject.get_id() args_dict['pipeline_skey'] = child_pipeline.get_search_key() dyn_load.set_load_method('_get_child_wdg') dyn_load.set_load_class('pyasm.widget.ParallelStatusWdg', load_args=args_dict) dyn_load.add_element_name('cal_sub_task') on_script = dyn_load.get_on_script(load_once=True) swap.add_action_script(on_script, "set_display_off('%s')" % content_id) script = "if ($(%s).getStyle('display')=='none') {%s}" \ %(swap.swap1_id, on_script) title.add_event('onclick', script) span.add(swap) span.add(title) span.add(HtmlElement.br()) span.add(HtmlElement.br()) span.add(content) else: span.add(name) if self.task_per_process_dict.get(process) == 0: span.add_class('unused') if label_format == 'small' or label_format == 'abbr': span.add_class('smaller') if not label_format == "none": table.add_cell(span) return top
def get_color(self, sobject, index): #color_mode = "custom" color_mode = self.kwargs.get("color_mode") if color_mode == "custom": column = "assigned" color_column = self.kwargs.get("color_column") color = self.kwargs.get("custom_colors") colors = {'admin': '#ACC', 'librarian': '#CAA', 'NULL': '#CCC'} value = sobject.get(column) color = colors.get(value) if not color: color = colors.get("NULL") if not color: color = "#BBB" return color elif color_mode == "single": color = self.kwargs.get("color") if color: return color div = DivWdg() colors = [ div.get_color("background3"), div.get_color("background3", -10), div.get_color("background3", -20), ] default_color = colors[index % 3] try: color = sobject.get("color") if color: return color except: pass bg_color, text_color = self.color_map.get('status') if bg_color: color_value = bg_color.get(sobject.get_value('status')) if color_value: return color_value pipeline_code = sobject.get_value("pipeline_code", no_exception=True) if not pipeline_code: pipeline_code = "task" pipeline = Pipeline.get_by_code(pipeline_code) if not pipeline: return default_color status = sobject.get_value("status", no_exception=True) process = pipeline.get_process(status) if not process: return default_color color = process.get_color() if not color: return default_color else: color = Common.modify_color(color, 0) return color
def get_display(my): top = my.top #top.add_color("background", "background" ) top.add_gradient("background", "background", 0, -10 ) search_type = my.kwargs.get("search_type") assert(search_type) search_type_obj = SearchType.get(search_type) title = my.kwargs.get("title") if not title: title = search_type_obj.get_title() if title: date = "@FORMAT(@STRING($TODAY),'Dec 31, 1999')" date = Search.eval(date, single=True) title_wdg = DivWdg() top.add(title_wdg) title_wdg.add(title) title_wdg.add(" [%s]" % date) title_wdg.add_style("font-size: 14") title_wdg.add_color("background", "background3") title_wdg.add_color("color", "color3") title_wdg.add_style("padding: 10px") title_wdg.add_style("font-weight: bold") title_wdg.add_style("text-align: center") search = Search("sthpw/task") full_search_type = Project.get_full_search_type(search_type) search.add_filter("search_type", full_search_type) tasks = search.get_sobjects() # organize by search_key tasks_dict = {} for task in tasks: parent_search_type = task.get_value("search_type") parent_search_id = task.get_value("search_id") key = "%s|%s" % (parent_search_type, parent_search_id) task_list = tasks_dict.get(key) if task_list == None: task_list = [] tasks_dict[key] = task_list task_list.append(task) # go through each sobject and find out where it is "at" search = Search(search_type) sobjects = search.get_sobjects() sobject_statuses = {} for sobject in sobjects: # get all the tasks for this sobject sobject_search_type = sobject.get_search_type() sobject_search_id = sobject.get_id() key = "%s|%s" % (sobject_search_type, sobject_search_id) tasks = tasks_dict.get(key) if not tasks: tasks = [] # figure out where in the pipeline this sobject is based # on the statuses process_statuses = {} for task in tasks: actual_end_date = task.get_value("actual_end_date") if actual_end_date: is_complete = True else: is_complete = False process = task.get_value("process") process_statuses[process] = is_complete pipeline_code = sobject.get_value("pipeline_code") pipeline = Pipeline.get_by_code(pipeline_code) if not pipeline: process_names = [] else: process_names = pipeline.get_process_names() sobject_status = None none_complete = True for process_name in process_names: is_complete = process_statuses.get(process_name) if is_complete == None: continue if is_complete == False: sobject_status = process_name break none_complete = False if sobject_status == None: if none_complete: if process_names: sobject_status = process_names[0] else: sobject_status = "No process" else: sobject_status = "Complete" sobject_statuses[key] = sobject_status # count the number of sobjects in each process count_dict = {} for key, process in sobject_statuses.items(): count = count_dict.get(process) if count == None: count = 1 else: count += 1 count_dict[process] = count # find the pipelines search = Search("sthpw/pipeline") search.add_filter("search_type", search_type) pipelines = search.get_sobjects() chart_div = DivWdg() top.add(chart_div) chart_div.add_border() chart_div.add_style("width: 900") #chart_div.set_box_shadow("0px 0px 3px 3px") chart_div.center() chart_div.add_style("margin-top: 30px") chart_div.add_style("margin-bottom: 30px") #chart_div.add_gradient("background", "background", 0, -10 ) chart_div.add_color("background", "background") # go through each process and find out how many sobjects are in each for pipeline in pipelines: process_names = pipeline.get_process_names() process_names.append("Complete") data_values = [] for process in process_names: count = count_dict.get(process) data_values.append(count) from tactic.ui.chart.chart2_wdg import ChartWdg as ChartWdg from tactic.ui.chart.chart2_wdg import ChartData as ChartData width = 800 height = 500 chart_labels = process_names x_data=[i+0.5 for i,x in enumerate(chart_labels)] chart = ChartWdg( width=width, height=height, chart_type='bar', labels=chart_labels, label_values=x_data ) chart_div.add(chart) chart_data = ChartData( #chart_type=chart_type, data=data_values, color="#00F", x_data=x_data ) chart.add(chart_data) top.add("<br clear='all'/>") return top
def process_sobjects(sobjects, search=None): '''process sobjects order according to pipeline process order''' if not sobjects: return if search: order_list = search.get_order_bys() # it could be search_type asc or search_tpe desc # that means the user has applied an order by in some specific column if order_list and not order_list[0].startswith('search_type'): return parent = None last_parent = None last_parent_key = None parents = [] groups = [] group = None # group tasks according to parent for i, sobject in enumerate(sobjects): # get the parent key search_type = sobject.get_value("search_type") search_id = sobject.get_value("search_id") parent_key = "%s|%s" % (search_type, search_id) process = sobject.get_value('process') if parent_key != last_parent_key: parent = SearchKey.get_by_search_key(parent_key) parents.append(parent) group = [] groups.append(group) group.append(sobject) last_parent_key = parent_key new_sobjects = [] # reorder each group for i, group in enumerate(groups): parent = parents[i] processes = [] if parent: pipeline_code = parent.get_value("pipeline_code") pipeline = Pipeline.get_by_code( pipeline_code ) if pipeline: processes = pipeline.get_process_names(recurse=True) if processes: # build a sorting key dict sort_dict = {} for sobject in group: process = sobject.get_value('process') try: sort_dict[sobject] = processes.index(process) except ValueError: # put at the bottom for outdated processes # this is important to still display tasks with outdated processe names sort_dict[sobject] = len(processes) sorted_group = sorted(group, key=sort_dict.__getitem__) new_sobjects.extend(sorted_group) else: new_sobjects.extend(group) return new_sobjects
def init(self): # for snapshot and task # self.child_mode = self.kwargs.get('child_mode') == 'true' self.parent_key = self.kwargs.get('parent_key') self.append_context = self.kwargs.get('append_context') self.is_refresh = self.kwargs.get('is_refresh') == 'true' self.view = self.kwargs.get('view') if not self.view: self.view = 'table' self.orig_parent = None self.use_parent = False incoming_process = False if self.parent_key: self.parent = Search.get_by_search_key(self.parent_key) self.orig_parent = self.parent self.orig_parent_search_type = self.parent.get_search_type() self.parent_search_type = self.parent.get_search_type() self.parent_search_id = self.parent.get_id() else: self.parent_search_type = self.kwargs.get('search_type') self.orig_parent_search_type = self.parent_search_type self.parent_search_id = self.kwargs.get('search_id') self.parent = Search.get_by_id(self.parent_search_type, self.parent_search_id) self.orig_parent = self.parent if self.use_parent: self.parent = self.parent.get_parent() if not self.parent: raise TacticException( 'Try not to use the display option [use_parent] since the parent cannot be found.' ) if self.parent: self.parent_key = SearchKey.get_by_sobject(self.parent) if self.use_parent: self.kwargs['parent_key'] = self.parent_key self.kwargs['use_parent'] = 'false' self.process_names = [] self.checked_processes = [] # get the process names web = WebContainer.get_web() process_names = web.get_form_values('process_names') #process_names = self.kwargs.get('process_names') if not process_names: if self.orig_parent_search_type in [ 'sthpw/task', 'sthpw/snapshot' ]: #self.parent = self.parent.get_parent() # most tasks don't have context by default if self.orig_parent_search_type == 'sthpw/task': context = self.orig_parent.get_value('context') if not context: context = self.orig_parent.get_value('process') else: context = self.orig_parent.get_value('context') self.process_names = [context] self.child_mode = True self.kwargs['child_mode'] = 'true' else: self.pipeline_code = self.kwargs.get('pipeline_code') if not self.pipeline_code and self.parent.has_value( 'pipeline_code'): self.pipeline_code = self.parent.get_value('pipeline_code') pipeline = Pipeline.get_by_code(self.pipeline_code) if pipeline: self.process_names = pipeline.get_process_names() else: self.process_names = process_names incoming_process = True # if nothing is derived from pipeline, use defualts if not self.process_names: self.process_names = ['default'] if self.append_context and not incoming_process: contexts = self.append_context.split('|') self.process_names.extend(contexts)
def get_display(my): my.labels_attr = my.get_option('label_attr') if my.labels_attr: my.labels_attr = my.labels_attr.split('|') from tactic.ui.panel import EditWdg if hasattr(my, 'parent_wdg') and isinstance(my.get_parent_wdg(), EditWdg): sobject = my.get_current_sobject() parent = sobject.get_parent() group = None pipeline_code = None if parent: pipeline_code = parent.get_value('pipeline_code') pipeline = Pipeline.get_by_code(pipeline_code) labels_expr = None if pipeline: attrs = pipeline.get_process_attrs(sobject.get_value('process')) group = attrs.get('%s_login_group'%my.get_name()) if group: values_expr = "@GET(sthpw/login_group['login_group', '%s'].sthpw/login_in_group.sthpw/login.login)"%group if my.labels_attr: labels_expr = ["@GET(sthpw/login_group['login_group', '%s'].sthpw/login_in_group.sthpw/login.%s)"%(group, x.strip()) for x in my.labels_attr] labels_expr = ' +   + '.join(labels_expr) else: values_expr = "@GET(sthpw/login.login)" if my.labels_attr: labels_expr = ["@GET(sthpw/login.%s)"%(x.strip()) for x in my.labels_attr] labels_expr = ' +   + '.join(labels_expr) select = SelectWdg(my.get_input_name()) select.add_empty_option("-- Select a User --") """ values = [] labels = [] for user in group_users: values.append(user) labels.append(' %s'%user) """ select.set_option('values_expr', values_expr) if labels_expr: select.set_option('labels_expr', labels_expr) current_value = sobject.get_value(my.get_name()) if current_value: select.set_value(current_value) return select #all_users = Search.eval("@GET(sthpw/login.login)") all_users = Search.eval("@SOBJECT(sthpw/login)") all_users_label = [] # don't use expression here since it's not as db-efficient as retrieving the sobjects """ if my.labels_attr: labels_expr = ["@GET(sthpw/login.login.%s)"%x.strip() for x in my.labels_attr] """ ''' groups = Search.eval("@SOBJECT(sthpw/login_group)") group_dict = {} for group in groups: group_users = Search.eval("@GET(sthpw/login_group['login_group', '%s'].sthpw/login_in_group.sthpw/login.login)"%group.get_value('login_group')) group_dict[group.get_value('login_group')] = group_users ''' logins_dict = {} for user in all_users: user_name = user.get_value('login') logins_dict[user_name] = {} group_dict = {} items = Search.eval("@SOBJECT(sthpw/login_in_group)") for item in items: item_login = item.get_value("login") if logins_dict.get(item_login) == None: continue item_group = item.get_value("login_group") group_list = group_dict.get(item_group) if group_list == None: group_list = [] group_dict[item_group] = group_list group_list.append(item_login) top = DivWdg() top.add_class("spt_input_top") # HACK! This isn't very well constructed ### Tore: Not my code! Copied from ProcessContextInputWdg. Seems to work though. top.add_attr("spt_cbjs_get_input_key", "return cell_to_edit.getAttribute('spt_pipeline_code');") # Adding an "all users" select option in case it can't find a useful select widget. div = DivWdg() div.add_class("spt_input_option") #div.add_attr("spt_input_key", '__all__') #Not needed, since it defaults to the first one anyway. select = SelectWdg(my.get_name()) select.add_empty_option("-- Select a User --") values = [] labels = [] labels_dict = {} for user in all_users: user_name = user.get_value('login') values.append(user_name) label = user_name if my.labels_attr: user_labels = [user.get_value(x) for x in my.labels_attr] label = ' '.join(user_labels) labels_dict[user_name] = label labels.append('%s'%label) #print "select ", user_name # -- NOTE: leaving this commented out code here for reference. Not sure why this is the case but when # -- this click behavior is used instead of a 'change' behavior that forces a blur on select, # -- click selection only works for this widget in Firefox and does NOT work in IE # # select.add_behavior( { 'type': 'click', # 'cbjs_action': 'spt.dg_table.select_wdg_clicked( evt, bvr.src_el );' } ) # -- Replace previous 'click' behavior with a 'change' behavior to force blur() of select element ... # -- this works for both Firefox and IE # select.add_behavior( { 'type': 'change', 'cbjs_action': 'bvr.src_el.blur();' } ) #behavior = { # 'type': 'keyboard', # 'kbd_handler_name': 'DgTableSelectWidgetKeyInput', #} #select.add_behavior( behavior ) select.set_option("values", values) select.set_option("labels", labels) div.add(select) top.add(div) #Building each of the select widgets per group here. for group in group_dict.keys(): div = DivWdg() div.add_class("spt_input_option") div.add_attr("spt_input_key", group) select = SelectWdg(my.get_name()) select.add_empty_option("-- Select a User --") values = [''] labels = ['<< %s >>'%group] for user in group_dict[group]: values.append(user) label = labels_dict.get(user) labels.append(' %s'%label) select.add_behavior( { 'type': 'click', 'cbjs_action': 'spt.dg_table.select_wdg_clicked( evt, bvr.src_el );' } ) #behavior = { # 'type': 'keyboard', # 'kbd_handler_name': 'DgTableSelectWidgetKeyInput', #} #select.add_behavior( behavior ) select.set_option("values", values) select.set_option("labels", labels) div.add(select) top.add(div) return top
def get_info_wdg(my): widget = Widget() table = Table() table.set_class("minimal") table.add_style("font-size: 0.8em") context_option = my.kwargs.get('context') context_expr_option = my.kwargs.get('context_expr') pipeline_option = my.kwargs.get('pipeline') in ['true', True, 'True'] setting_option = my.kwargs.get('setting') context_name = "%s|context" % my.get_input_name() text = None span1 = SpanWdg("Context", id='context_mode') span2 = SpanWdg("Context<br/>/Subcontext", id='subcontext_mode') span2.add_style('display', 'none') table.add_cell(span1) table.add_data(span2) if context_expr_option or context_option or setting_option: # add swap display for subcontext only if there is setting or context option swap = SwapDisplayWdg() table.add_data(SpanWdg(swap, css='small')) swap.set_display_widgets(StringWdg('[+]'), StringWdg('[-]')) subcontext_name = "%s|subcontext" % my.get_input_name() subcontext = SpanWdg('/ ', css='small') subcontext.add(TextWdg(subcontext_name)) subcontext.add_style('display', 'none') subcontext.set_id(subcontext_name) on_script = "set_display_on('%s');swap_display('subcontext_mode','context_mode')" % subcontext_name off_script = "set_display_off('%s');get_elements('%s').set_value(''); "\ "swap_display('context_mode','subcontext_mode')"%(subcontext_name, subcontext_name) swap.add_action_script(on_script, off_script) text = SelectWdg(context_name) if my.sobjects: text.set_sobject(my.sobjects[0]) if context_expr_option: text.set_option('values_expr', context_expr_option) elif context_option: text.set_option('values', context_option) elif setting_option: text.set_option('setting', setting_option) td = table.add_cell(text) table.add_data(subcontext) elif pipeline_option: from pyasm.biz import Pipeline sobject = my.sobjects[0] pipeline = Pipeline.get_by_sobject(sobject) context_names = [] process_names = pipeline.get_process_names(recurse=True) for process in process_names: context_names.append(pipeline.get_output_contexts(process)) text = SelectWdg(context_name) text.set_option('values', process_names) table.add_cell(text) else: text = TextWdg(context_name) table.add_cell(text) hint = HintWdg('If not specified, the default is [publish]') table.add_data(hint) revision_cb = CheckboxWdg('%s|is_revision' %my.get_input_name(),\ label='is revision', css='med') table.add_data(revision_cb) table.add_row() table.add_cell("Comment") textarea = TextAreaWdg("%s|description" % my.get_input_name()) table.add_cell(textarea) widget.add(table) return widget
def get_display(my): sobject = my.get_current_sobject() search_key = sobject.get_search_key() value = sobject.get_value(my.name) my.select = ActionSelectWdg("status_%s" % search_key) empty = my.get_option("empty") if empty: my.select.set_option("empty", empty ) pipeline_code = my.get_option("pipeline") widget = Widget() my.select.set_id("status_%s" % search_key) setting = my.get_option("setting") if setting: my.select.set_option("setting", setting ) else: if pipeline_code: pipeline = Pipeline.get_by_code(pipeline_code) else: if sobject.has_value('pipeline_code'): pipeline_code = sobject.get_value('pipeline_code') if isinstance(sobject, Task): if not pipeline_code: pipeline_code = 'task' pipeline = Pipeline.get_by_code(pipeline_code) if not pipeline: return "No pipeline" """ status_attr = sobject.get_attr("status") if status_attr: pipeline = status_attr.get_pipeline() else: return "No pipeline" """ processes = pipeline.get_process_names() allowed_processes = [] security = Environment.get_security() # has to allow it if it has already been set for process in processes: if value == process or security.check_access("process_select", process, access='view'): allowed_processes.append(process) my.select.set_option("values", "|".join(allowed_processes) ) if not value and processes: value = processes[0] # add the item if it is an obsolete status, alert # the user to change to the newly-defined statuses if value not in processes: my.select.append_option(value, value) my.select.set_class('action_warning') my.select.set_value( value ) # TODO: this is a little cumbersome to know all this simply to # execute a command using ajax """ div_id = widget.generate_unique_id('simple_status_wdg') cmd = AjaxLoader(div_id) marshaller = cmd.register_cmd("SimpleStatusCmd") marshaller.set_option('search_key', search_key) marshaller.set_option('attr_name', my.name) my.select.add_event("onchange", cmd.get_on_script(True) ) """ js_action = "TacticServerCmd.execute_cmd('pyasm.widget.SimpleStatusCmd', '',\ {'search_key': '%s', 'attr_name': '%s'}, {'value': bvr.src_el.value});" %(search_key, my.name) # build the search key #search_key = "%s|%s" % (my.search_type, my.search_id) bvr = {'type': 'change', 'cbjs_action': js_action} if my.post_ajax_script: bvr['cbjs_postaction'] = my.post_ajax_script my.select.add_behavior(bvr) div = DivWdg(my.select) div.add_style('float: left') widget.add(div) return widget
def get_display(my): my.search_type = my.kwargs.get("search_type") if not my.search_type: my.search_type = 'sthpw/task' my.column = my.kwargs.get("column") if not my.column: my.column = 'status' my.project_code = my.kwargs.get("project_code") if not my.project_code: my.project_code = Project.get_project_code() my.bar_width = my.kwargs.get("bar_width") if not my.bar_width: my.bar_width = 200 values = my.kwargs.get("values") if values: values = values.split("|") else: pipeline_code = my.kwargs.get("pipeline_code") if pipeline_code: pipeline = Pipeline.get_by_code(pipeline_code) values = pipeline.get_process_names() else: search = Search(my.search_type) search.add_filter("project_code", my.project_code) search.add_column(my.column, distinct=True) xx = search.get_sobjects() values = [x.get_value(my.column) for x in xx] search = Search(my.search_type) search.add_filter("project_code", my.project_code) search.add_filters(my.column, values) total = search.get_count() colors = [ '#900', '#090', '#009', '#990', '#099', '#909', '#900', '#090', '#009', '#990' ] while len(values) > len(colors): colors.extend(colors) top = DivWdg() top.add_color("background", "background") date = "@FORMAT(@STRING($TODAY),'Dec 31, 1999')" date = Search.eval(date, single=True) title = "Tasks Status Chart" title_wdg = DivWdg() top.add(title_wdg) title_wdg.add(title) title_wdg.add(" [%s]" % date) title_wdg.add_style("font-size: 14") title_wdg.add_color("background", "background3") title_wdg.add_color("color", "color3") title_wdg.add_style("padding: 10px") title_wdg.add_style("font-weight: bold") title_wdg.add_style("text-align: center") inner = DivWdg() top.add(inner) inner.center() inner.add_style("width: 500px") inner.add_style("padding: 30px") for i, status in enumerate(values): if not status: continue count = my.get_count(status) div = my.get_div(status, count, total, colors[i]) inner.add(div.get_buffer_display()) inner.add("<br clear='all'/>") inner.add("<hr/>") div = my.get_div("Total", total, total, "gray") inner.add(div.get_buffer_display()) inner.add("<br clear='all'/>") return top
def get_display(self): div = DivWdg() div.add_style("padding: 10px 0px 10px 0px") behavior = { 'type': 'keyboard', 'kbd_handler_name': 'DgTableMultiLineTextEdit' } div.add_behavior(behavior) project_code = None sobject = self.get_current_sobject() if sobject: project_code = sobject.get_project_code() project_filter = Project.get_project_filter(project_code) query_filter = self.get_option("query_filter") if not query_filter: # try getting it from the search_type web = WebContainer.get_web() search_type = web.get_form_value("search_type") if search_type: search_type_obj = SearchType.get(search_type) base_search_type = search_type_obj.get_base_search_type() query_filter = "search_type = '%s'" % base_search_type # add the project filter if query_filter: query_filter = "%s and %s" % (query_filter, project_filter) else: query_filter = project_filter self.set_option("query_filter", query_filter) select = SelectWdg() select.add_empty_option("-- Select --") select.copy(self) select.add_event("onchange", "alert('cow')") div.add(select) span = SpanWdg(css="med") span.add("Add Initial Tasks: ") checkbox = CheckboxWdg("add_initial_tasks") checkbox.set_persistence() if checkbox.is_checked(False): checkbox.set_checked() span.add(checkbox) div.add(span) # list all of the processes with checkboxes pipeline_code = select.get_value() if pipeline_code: pipeline = Pipeline.get_by_code(pipeline_code) if not pipeline: print "WARNING: pipeline '%s' does not exist" % pipeline_code return process_names = pipeline.get_process_names(recurse=True) process_div = DivWdg() for process in process_names: checkbox = CheckboxWdg("add_initial_tasks") process_div.add(checkbox) process_div.add(" ") process_div.add(process) process_div.add(HtmlElement.br()) div.add(process_div) return div
def preprocess(my): '''determine if this is for EditWdg or EDIT ROW of a table''' # get the number of task pipelines needed for EditWdg, which is one # for the EDIT ROW , there could be more than 1 my.task_mapping = None from tactic.ui.panel import EditWdg if hasattr(my, 'parent_wdg') and isinstance(my.get_parent_wdg(), EditWdg): task = my.get_current_sobject() task_pipe_code = task.get_value('pipeline_code') # if the current task has no pipeline, then search for # any task pipeline if not task_pipe_code: # just use the default task_pipe_code = 'task' pipeline = Pipeline.get_by_code(task_pipe_code) if not pipeline: pipeline = Pipeline.get_by_code('task') my.task_pipelines = [pipeline] else: # get all of the pipelines for tasks search = Search('sthpw/pipeline') search.add_regex_filter('search_type', 'sthpw/task') my.task_pipelines = search.get_sobjects() # get all of the pipelines for the current search_type search_type = my.state.get("search_type") search = Search('sthpw/pipeline') if search_type: search.add_filter('search_type', search_type) my.sobject_pipelines = search.get_sobjects() # insert the default task pipeline if not overridden in the db default_task_found = False pipeline_codes = SObject.get_values(my.task_pipelines, 'code') if 'task' in pipeline_codes: default_task_found = True if not default_task_found: default_pipe = Pipeline.get_by_code('task') my.task_pipelines.append(default_pipe) my.task_mapping = {} # the following works for insert but on edit, it should read from pipeline_code attribute for pipeline in my.sobject_pipelines: processes = pipeline.get_process_names() for process in processes: attrs = pipeline.get_process_attrs(process) task_pipeline = attrs.get('task_pipeline') if task_pipeline: key = '%s|%s' % (pipeline.get_code(), process) my.task_mapping[key] = task_pipeline #my.task_mapping = "|".join(my.task_mapping) my.is_preprocess = True