def get_display(my): top = my.top my.set_as_panel(top) title_wdg = DivWdg() top.add(title_wdg) title_wdg.add("Local") title_wdg.add_style("padding: 10px") title_wdg.add_color("background", "background", -10) title_wdg.add_border() title_wdg.add_style("margin: -6px -6px 10px -6px") title_wdg.add_style("font-weight: bold") from tactic.ui.container import TabWdg tab = TabWdg(selected="Info", show_add=False) top.add(tab) tab.add(my.get_info_wdg()) return top
def get_panels(my): panels = [] show_security = my.kwargs.get("show_security") show_add = my.kwargs.get("show_add") view = my.kwargs.get("view") filter_mode = my.kwargs.get("filter_mode") from tactic.ui.container import TabWdg config_xml = [] config_xml.append(''' <config> ''') config_xml.append(''' <tab> <element name="Users"> <display class='tactic.ui.startup.UserPanelWdg'> <show_security>%s</show_security> <show_add>%s</show_add> <view>%s</view> <filter_mode>%s</filter_mode> </display> </element> ''' % (show_security, show_add, view, filter_mode)) config_xml.append(''' <element name="Group Assignment"> <display class='tactic.ui.startup.UserSecurityWdg'/> </element> </tab> ''') config_xml.append(''' </config> ''') config_xml = "\n".join(config_xml) tab = TabWdg(show_add=False, config_xml=config_xml) panel = { 'widget': tab, 'title': None, 'width': '100%', 'height': '100%' } panels.append(panel) return panels
def get_display(my): my.search_type = None my.view = 'tab' config_xml = my.get_config_xml() config = WidgetConfig.get(view=my.view, xml=config_xml) top = DivWdg() #tab = TabWdg(width=1000, save_state="admin_tab_state") tab = TabWdg(config=config, view=my.view, width=1000) top.add(tab) for widget in my.widgets: tab.add(widget) # set the current one active div = DivWdg() div.add_style("display: hidden") div.add_behavior( { 'type': 'load', 'cbjs_action': ''' spt.tab.set_main_body_top(); var headers = spt.tab.get_headers(); // if there are no headers, then there was an error if (headers.length == 0) { return; } var name = headers[headers.length-1].getAttribute("spt_element_name"); spt.tab.select(name); ''' } ) top.add(div) return top
def get_display(self): self.search_type = None self.view = 'tab' config_xml = self.get_config_xml() config = WidgetConfig.get(view=self.view, xml=config_xml) top = DivWdg() #tab = TabWdg(width=1000, save_state="admin_tab_state") tab = TabWdg(config=config, view=self.view, width=1000) top.add(tab) for widget in self.widgets: tab.add(widget) # set the current one active div = DivWdg() div.add_style("display: hidden") div.add_behavior({ 'type': 'load', 'cbjs_action': ''' spt.tab.set_main_body_top(); var headers = spt.tab.get_headers(); // if there are no headers, then there was an error if (headers.length == 0) { return; } var name = headers[headers.length-1].getAttribute("spt_element_name"); spt.tab.select(name); ''' }) top.add(div) return top
def get_panels(my): panels = [] search_type_panel = DivWdg() search_type_panel.add_style("padding-top: 3px") search_type_panel.add_style("overflow-y: auto") search_type_panel.add( SearchTypePanel() ) search_type_panel.add_style("min-height: 100px") search_type_panel.add_style("height: 300px") search_type_panel.add_class("spt_resizable") panel = { 'widget': search_type_panel, 'title': 'Searchable Type (sType) List', 'width': '50%' } panels.append(panel) from tactic.ui.container import TabWdg config_xml = ''' <config> <tab> <element name="Help"> <display class='tactic.ui.app.HelpContentWideWdg'> <alias>main</alias> <width>1000px</width> </display> </element> </tab> </config> ''' div = DivWdg() tab = TabWdg(show_add=False, config_xml=config_xml, tab_offset=5) div.add(tab) div.add_style("margin: 0px -6px -6px -6px") panel = { 'widget': div, #'title': 'Data', 'title': None, 'width': '100%', } panels.append(panel) return panels
def get_panels(my): panels = [] user_panel = DivWdg() user_panel.add_style("padding-top: 3px") user_panel.add_style("overflow-y: auto") user_panel.add(UserPanelWdg()) user_panel.add_style("min-height: 100px") user_panel.add_style("height: 400px") user_panel.add_class("spt_resizable") panel = { 'widget': user_panel, 'title': 'List of Users', } panels.append(panel) from tactic.ui.container import TabWdg config_xml = ''' <config> <tab> <element name="Help"> <display class='tactic.ui.app.HelpContentWideWdg'> <alias>main</alias> <width>1000px</width> </display> </element> <element name="Users in Project"> <display class='tactic.ui.startup.UserSecurityWdg'/> </element> </tab> </config> ''' tab = TabWdg(show_add=False, config_xml=config_xml) panel = { 'widget': tab, #'title': 'Data', 'title': None, 'width': '100%', 'height': '100%' } panels.append(panel) return panels
def get_display(self): top = self.top self.set_as_panel(top) top.add_class("spt_share_item") self.server_code = self.kwargs.get("server_code") if not self.server_code: top.add("No server selected") return top self.server = Search.get_by_code("sthpw/sync_server", self.server_code) self.base_dir = self.server.get_value("base_dir") title_wdg = DivWdg() top.add( title_wdg ) title_wdg.add( self.server_code ) title_wdg.add_style("padding: 10px") title_wdg.add_color("background", "background", -10) title_wdg.add_border() title_wdg.add_style("margin: -6px -6px 10px -6px") title_wdg.add_style("font-weight: bold") description = self.server.get_value("description") title_wdg.add(" <i style='font-size: 9px; opacity: 0.5'>( %s )</i>" % description ) from tactic.ui.container import TabWdg tab = TabWdg(selected="Info", show_add=False) top.add(tab) tab.add(self.get_info_wdg()) tab.add(self.get_files_wdg()) tab.add( self.get_tools_wdg() ) return top
def get_display(my): top = my.top my.set_as_panel(top) top.add_class("spt_share_item") my.server_code = my.kwargs.get("server_code") if not my.server_code: top.add("No server selected") return top my.server = Search.get_by_code("sthpw/sync_server", my.server_code) my.base_dir = my.server.get_value("base_dir") title_wdg = DivWdg() top.add( title_wdg ) title_wdg.add( my.server_code ) title_wdg.add_style("padding: 10px") title_wdg.add_color("background", "background", -10) title_wdg.add_border() title_wdg.add_style("margin: -6px -6px 10px -6px") title_wdg.add_style("font-weight: bold") description = my.server.get_value("description") title_wdg.add(" <i style='font-size: 9px; opacity: 0.5'>( %s )</i>" % description ) from tactic.ui.container import TabWdg tab = TabWdg(selected="Info", show_add=False) top.add(tab) tab.add(my.get_info_wdg()) tab.add(my.get_files_wdg()) tab.add( my.get_tools_wdg() ) return top
def get_display(my): my.sobject = my.get_sobject() top = DivWdg() top.add_class("spt_detail_top") top.add_color("background", "background") top.add_color("color", "color") if not my.sobject: top.add("No SObject defined for this widget") return top if my.parent: my.search_type = my.parent.get_base_search_type() my.search_key = SearchKey.get_by_sobject(my.parent) top.add_attr("spt_parent_key", my.search_key) my.pipeline_code = my.parent.get_value("pipeline_code", no_exception=True) my.full_search_type = my.parent.get_search_type() else: my.pipeline_code = my.sobject.get_value("pipeline_code", no_exception=True) my.search_type = my.sobject.get_base_search_type() my.search_key = SearchKey.get_by_sobject(my.sobject) my.full_search_type = my.sobject.get_search_type() if not my.pipeline_code: my.pipeline_code = 'default' top.add_style("text-align: left") my.set_as_panel(top) table = Table() #from tactic.ui.container import ResizableTableWdg #table = ResizableTableWdg() table.add_color("background", "background") table.add_color("color", "color") top.add(table) table.set_max_width() table.add_row() # left #td = table.add_cell(resize=False) td = table.add_cell() #td.add_style("padding: 10px") td.add_style("width: 200px") td.add_style("min-width: 200px") td.add_style("vertical-align: top") #td.add_border() #td.add_style("border-style: solid") #td.add_style("border-width: 1px 0 1px 1px") #td.add_color("border-color", "border") #td.add_color("background", "background", -10) if my.parent: code = my.parent.get_code() else: code = my.sobject.get_code() # add the tile title = DivWdg() td.add(title) title.add_gradient("background", "background3", 0, -10) title.add_style("height: 20px") title.add_style("padding: 4px") title.add_style("font-weight: bold") title.add_style("font-size: 1.4em") title.add("%s" % code) title.add_border() div = DivWdg() td.add(div) div.add_class("spt_sobject_detail_top") thumb_table = Table() div.add(thumb_table) thumb_table.add_row() thumb = ThumbWdg() # use a larger version for clearer display thumb.set_icon_type('web') # prefer to see the original image, then web thumb.set_option('image_link_order', 'main|web|icon') thumb.set_option("detail", "false") thumb.set_option("icon_size", "100%") td = thumb_table.add_cell(thumb) td.add_style("vertical-align: top") td.add_style("width: 240px") td.add_style("padding: 15px") if my.parent: thumb.set_sobject(my.parent) else: thumb.set_sobject(my.sobject) sobject_info_wdg = my.get_sobject_info_wdg() sobject_info_wdg.add_style("width: 200px") td.add(sobject_info_wdg) if my.search_type == 'sthpw/task' and not my.parent: pass else: sobject_info_wdg = my.get_sobject_detail_wdg() td = table.add_cell() td.add(sobject_info_wdg) td.add_style("vertical-align: top") td.add_style("overflow: hidden") # right td = table.add_cell() td.add_style("text-align: left") td.add_style("vertical-align: top") #td.add_color("background", "background", -10) td.add_class("spt_notes_wrapper") #td.add_border() # add the title title = DivWdg() td.add(title) title.add_gradient("background", "background3", 0, -10) title.add_style("height: 20px") title.add_style("padding: 4px") title.add_style("font-weight: bold") title.add("Notes") title.add_border() notes_div = DivWdg() td.add(notes_div) from tactic.ui.widget.discussion_wdg import DiscussionWdg discussion_wdg = DiscussionWdg(search_key=my.search_key, context_hidden=False, show_note_expand=False) notes_div.add(discussion_wdg) notes_div.add_style("min-width: 300px") notes_div.add_style("height: 200") notes_div.add_style("overflow-y: auto") notes_div.add_class("spt_resizable") # get the process if my.parent: process = my.sobject.get_value("process") else: process = '' # content tr = table.add_row() td = table.add_cell() td.add_attr("colspan", "5") #td.add_attr("colspan", "3") # create a state for tab. The tab only passes a search key # parent key search_key = SearchKey.get_by_sobject(my.sobject) parent = my.sobject.get_parent() if parent: parent_key = parent.get_search_key() else: parent_key = "" state = { 'search_key': search_key, 'parent_key': parent_key, 'process': process, } WebState.get().push(state) config_xml = my.get_config_xml() config = WidgetConfig.get(view="tab", xml=config_xml) if process: custom_view = "tab_config_%s" % process else: custom_view = "tab_config" search = Search("config/widget_config") search.add_filter("category", "TabWdg") search.add_filter("search_type", my.search_type) search.add_filter("view", custom_view) custom_config_sobj = search.get_sobject() if custom_config_sobj: custom_config_xml = custom_config_sobj.get_value("config") custom_config = WidgetConfig.get(view=custom_view, xml=custom_config_xml) config = WidgetConfigView(search_type='TabWdg', view=custom_view, configs=[custom_config, config]) #menu = my.get_extra_menu() #tab = TabWdg(config=config, state=state, extra_menu=menu) tab = TabWdg(config=config, state=state, show_add=False, show_remove=False, tab_offset=5) tab.add_style("margin: 0px -2px -2px -2px") td.add(tab) td.add_style("padding-top: 10px") return top
def get_display(my): top = my.top; my.set_as_panel(top) top.add_class("spt_chat_top") inner = DivWdg() top.add(inner) inner.add_behavior( { 'type': 'load', 'cbjs_action': MessageWdg.get_onload_js() } ) search = Search("sthpw/subscription") search.add_filter("category", "chat") search.add_user_filter() chats = search.get_sobjects() keys = [x.get_value("message_code") for x in chats] """ chat_list_div = DivWdg() inner.add(chat_list_div) for i, chat in enumerate(chats): chat_div = DivWdg() chat_list_div.add(chat_div) chat_div.add_style("padding: 5px") chat_div.add_class("hand") # find all the users with the same chat key = chat.get_value("message_code") #chat_div.add(key) chat_div.add("#%s: " % i) search = Search("sthpw/subscription") search.add_filter("message_code", key) subscriptions = search.get_sobjects() users = [x.get_value("login") for x in subscriptions] chat_div.add(", ".join(users)) chat_div.add_behavior( { 'type': 'click_up', 'key': key, 'cbjs_action': ''' var class_name = 'tactic.ui.app.ChatSessionWdg'; var kwargs = { 'key': bvr.key, } spt.panel.load_popup("Chat: " + bvr.key, class_name, kwargs); ''' } ) chat_div.add_behavior( { 'type': 'mouseover', 'cbjs_action': ''' bvr.src_el.setStyle("color", "#214e75"); ''' } ) chat_div.add_behavior( { 'type': 'mouseout', 'cbjs_action': ''' bvr.src_el.setStyle("color", ""); ''' } ) """ #keys = my.kwargs.get("keys") #if not keys: # return inner.add( my.get_add_chat_wdg() ) inner.add("<br/>") from tactic.ui.container import TabWdg tab = TabWdg( show_add=False, show_remove=False ) inner.add(tab) for key in keys: search = Search("sthpw/subscription") search.add_filter("message_code", key) subscriptions = search.get_sobjects() users = [x.get_value("login") for x in subscriptions] users = ", ".join(users) session_div = DivWdg() session_div.set_name(users) session_div.add_style("width: 100%") #inner.add(session_div) tab.add(session_div) session = ChatSessionWdg(key=key) session_div.add(session) inner.add("<br clear='all'/>") if my.kwargs.get("is_refresh") == 'true': return inner else: return top
def get_display(my): my.sobject = my.get_sobject() top = DivWdg() top.add_class("spt_detail_top") top.add_color("background", "background") top.add_color("color", "color") if not my.sobject: top.add("No SObject defined for this widget") return top if my.parent: my.search_type = my.parent.get_base_search_type() my.search_key = SearchKey.get_by_sobject(my.parent) top.add_attr("spt_parent_key", my.search_key) my.pipeline_code = my.parent.get_value("pipeline_code", no_exception=True) my.full_search_type = my.parent.get_search_type() else: my.pipeline_code = my.sobject.get_value("pipeline_code", no_exception=True) my.search_type = my.sobject.get_base_search_type() my.search_key = SearchKey.get_by_sobject(my.sobject) my.full_search_type = my.sobject.get_search_type() if not my.pipeline_code: my.pipeline_code = 'default' top.add_style("text-align: left") my.set_as_panel(top) table = Table() #from tactic.ui.container import ResizableTableWdg #table = ResizableTableWdg() table.add_color("background", "background") table.add_color("color", "color") top.add(table) table.set_max_width() # add the title tr, td = table.add_row_cell() title_wdg = my.get_title_wdg() td.add(title_wdg) table.add_row() # left td = table.add_cell() td.add_style("width: 300px") td.add_style("min-width: 300px") td.add_style("vertical-align: top") div = DivWdg() td.add(div) div.add_class("spt_sobject_detail_top") thumb_table = Table() div.add(thumb_table) thumb_table.add_row() from tactic.ui.panel import ThumbWdg2 thumb = ThumbWdg2() # use a larger version for clearer display #thumb.set_icon_type('web') if my.parent: thumb.set_sobject(my.parent) search_key = my.parent.get_search_key() else: thumb.set_sobject(my.sobject) search_key = my.sobject.get_search_key() gallery_div = DivWdg() div.add( gallery_div ) gallery_div.add_class("spt_tile_gallery") thumb_table.add_behavior( { 'type': 'click_up', 'search_key': search_key, 'cbjs_action': ''' var top = bvr.src_el.getParent(".spt_sobject_detail_top"); var gallery_el = top.getElement(".spt_tile_gallery"); var class_name = 'tactic.ui.widget.gallery_wdg.GalleryWdg'; var kwargs = { search_key: bvr.search_key, search_keys: [bvr.search_key], }; spt.panel.load(gallery_el, class_name, kwargs); ''' } ) # prefer to see the original image, then web #thumb.set_option('image_link_order', 'main|web|icon') #thumb.set_option("detail", "false") #thumb.set_option("icon_size", "100%") td = thumb_table.add_cell(thumb) td.add_style("vertical-align: top") td.add_style("width: auto") td.add_style("padding: 15px") sobject_info_wdg = my.get_sobject_info_wdg() sobject_info_wdg.add_style("width: 100%") td.add(sobject_info_wdg) if my.search_type == 'sthpw/task' and not my.parent: pass else: sobject_info_wdg = my.get_sobject_detail_wdg() td = table.add_cell() td.add(sobject_info_wdg) td.add_style("vertical-align: top") td.add_style("overflow: hidden") # right td = table.add_cell() td.add_style("text-align: left") td.add_style("vertical-align: top") td.add_class("spt_notes_wrapper") td.add_style("padding: 5px 5px") title_wdg = DivWdg() td.add(title_wdg) title_wdg.add_style("width: 100%") title_wdg.add("Notes") title_wdg.add("<hr/>") title_wdg.add_style("font-size: 1.2em") notes_div = DivWdg() td.add(notes_div) from tactic.ui.widget.discussion_wdg import DiscussionWdg discussion_wdg = DiscussionWdg(search_key=my.search_key, context_hidden=False, show_note_expand=False) notes_div.add(discussion_wdg) notes_div.add_style("min-width: 300px") notes_div.add_style("height: 200") notes_div.add_style("overflow-y: auto") notes_div.add_class("spt_resizable") # get the process if my.parent: process = my.sobject.get_value("process") else: process = '' # content tr = table.add_row() td = table.add_cell() td.add_attr("colspan", "5") #td.add_attr("colspan", "3") # create a state for tab. The tab only passes a search key # parent key search_key = SearchKey.get_by_sobject(my.sobject) parent_key = "" if search_key.startswith("sthpw/"): parent = my.sobject.get_parent() if parent: parent_key = parent.get_search_key() state = { 'search_key': search_key, 'parent_key': parent_key, 'process': process, } WebState.get().push(state) config_xml = my.get_config_xml() config = WidgetConfig.get(view="tab", xml=config_xml) if process: custom_view = "tab_config_%s" % process else: custom_view = "tab_config" search = Search("config/widget_config") search.add_filter("category", "TabWdg") search.add_filter("search_type", my.search_type) search.add_filter("view", custom_view) custom_config_sobj = search.get_sobject() if custom_config_sobj: custom_config_xml = custom_config_sobj.get_value("config") custom_config = WidgetConfig.get(view=custom_view, xml=custom_config_xml) config = WidgetConfigView(search_type='TabWdg', view=custom_view, configs=[custom_config, config]) #menu = my.get_extra_menu() #tab = TabWdg(config=config, state=state, extra_menu=menu) tab = TabWdg(config=config, state=state, show_add=False, show_remove=False, tab_offset=5 ) tab.add_style("margin: 0px -2px -2px -2px") td.add(tab) td.add_style("padding-top: 10px") return top
def get_display(my): my.sobject = my.get_sobject() top = DivWdg() top.add_class("spt_detail_top") top.add_color("background", "background") top.add_color("color", "color") if not my.sobject: top.add("No SObject defined for this widget") return top if my.parent: my.search_type = my.parent.get_base_search_type() my.search_key = SearchKey.get_by_sobject(my.parent) top.add_attr("spt_parent_key", my.search_key) my.pipeline_code = my.parent.get_value("pipeline_code", no_exception=True) my.full_search_type = my.parent.get_search_type() else: my.pipeline_code = my.sobject.get_value("pipeline_code", no_exception=True) my.search_type = my.sobject.get_base_search_type() my.search_key = SearchKey.get_by_sobject(my.sobject) my.full_search_type = my.sobject.get_search_type() if not my.pipeline_code: my.pipeline_code = 'default' top.add_style("text-align: left") my.set_as_panel(top) table = Table() #from tactic.ui.container import ResizableTableWdg #table = ResizableTableWdg() table.add_color("background", "background") table.add_color("color", "color") top.add(table) table.set_max_width() table.add_row() # left #td = table.add_cell(resize=False) td = table.add_cell() #td.add_style("padding: 10px") td.add_style("width: 200px") td.add_style("min-width: 200px") td.add_style("vertical-align: top") #td.add_border() #td.add_style("border-style: solid") #td.add_style("border-width: 1px 0 1px 1px") #td.add_color("border-color", "border") #td.add_color("background", "background", -10) if my.parent: code = my.parent.get_code() else: code = my.sobject.get_code() # add the tile title = DivWdg() td.add(title) title.add_gradient("background", "background3", 0, -10) title.add_style("height: 20px") title.add_style("padding: 4px") title.add_style("font-weight: bold") title.add_style("font-size: 1.4em") title.add("%s" % code) title.add_border() div = DivWdg() td.add(div) div.add_class("spt_sobject_detail_top") thumb_table = Table() div.add(thumb_table) thumb_table.add_row() thumb = ThumbWdg() # use a larger version for clearer display thumb.set_icon_type('web') # prefer to see the original image, then web thumb.set_option('image_link_order', 'main|web|.swf') thumb.set_option("detail", "false") thumb.set_option("icon_size", "100%") td = thumb_table.add_cell(thumb) td.add_style("vertical-align: top") td.add_style("width: 200px") td.add_style("padding: 20px") if my.parent: thumb.set_sobject(my.parent) else: thumb.set_sobject(my.sobject) sobject_info_wdg = my.get_sobject_info_wdg() sobject_info_wdg.add_style("width: 200px") td.add(sobject_info_wdg) if my.search_type == 'sthpw/task' and not my.parent: pass else: sobject_info_wdg = my.get_sobject_detail_wdg() td = table.add_cell() td.add(sobject_info_wdg) td.add_style("vertical-align: top") #td.add_color("background", "background", -10) td.add_style("overflow: hidden") #td.add_style("border-style: solid") #td.add_style("border-width: 1px 1px 1px 0px") #td.add_color("border-color", "border") # right td = table.add_cell() td.add_style("text-align: left") td.add_style("vertical-align: top") #td.add_color("background", "background", -10) td.add_class("spt_notes_wrapper") #td.add_border() # add the title title = DivWdg() td.add(title) title.add_gradient("background", "background3", 0, -10) title.add_style("height: 20px") title.add_style("padding: 4px") title.add_style("font-weight: bold") title.add("Notes") title.add_border() notes_div = DivWdg() td.add(notes_div) from tactic.ui.widget.discussion_wdg import DiscussionWdg discussion_wdg = DiscussionWdg(search_key=my.search_key, context_hidden=False, show_note_expand=False) notes_div.add(discussion_wdg) notes_div.add_style("min-width: 300px") notes_div.add_style("height: 200") notes_div.add_style("overflow-y: auto") notes_div.add_class("spt_resizable") # get the process if my.parent: process = my.sobject.get_value("process") else: process = '' # content tr = table.add_row() td = table.add_cell() td.add_attr("colspan", "5") #td.add_attr("colspan", "3") # create a state for tab. The tab only passes a search key # parent key search_key = SearchKey.get_by_sobject(my.sobject) parent = my.sobject.get_parent() if parent: parent_key = parent.get_search_key() else: parent_key = "" state = { 'search_key': search_key, 'parent_key': parent_key, 'process': process, } WebState.get().push(state) config_xml = my.get_config_xml() config = WidgetConfig.get(view="tab", xml=config_xml) if process: custom_view = "tab_config_%s" % process else: custom_view = "tab_config" search = Search("config/widget_config") search.add_filter("category", "TabWdg") search.add_filter("search_type", my.search_type) search.add_filter("view", custom_view) custom_config_sobj = search.get_sobject() if custom_config_sobj: custom_config_xml = custom_config_sobj.get_value("config") custom_config = WidgetConfig.get(view=custom_view, xml=custom_config_xml) config = WidgetConfigView(search_type='TabWdg', view=custom_view, configs=[custom_config, config]) #menu = my.get_extra_menu() #tab = TabWdg(config=config, state=state, extra_menu=menu) tab = TabWdg(config=config, state=state, show_add=False, show_remove=False, tab_offset=5 ) tab.add_style("margin: 0px -2px -2px -2px") td.add(tab) td.add_style("padding-top: 10px") return top
def get_display(self): top = self.top self.config_search_type = self.kwargs.get("config_search_type") if not self.config_search_type: self.config_search_type = "SideBarWdg" view_item = self.kwargs.get("view") if not view_item: view_item = "definition" self.default = self.kwargs.get('default') == 'True' use_default_style = self.kwargs.get("use_default_style") is_personal = False # get the config config = self.get_config(self.config_search_type, view_item, default=self.default, personal=is_personal) element_names = config.get_element_names() new_config_xml = [] new_config_xml.append('''<config>''') new_config_xml.append('''<tab>''') from pyasm.common import Environment from pyasm.biz import Project from tactic.ui.common import WidgetClassHandler security = Environment.get_security() user = Environment.get_user_name() self.project = Project.get() class_handler = WidgetClassHandler() for element_name in element_names: # handle security # TODO: put this in the base class key = {'project': self.project.get_code(), 'element': element_name} key2 = {'element': element_name} key3 = {'project': self.project.get_code(), 'element': '*'} key4 = {'element': '*'} keys = [key, key2, key3, key4] if element_name.startswith('%s.' % user): # personal view is default to be viewable if not security.check_access( "link", keys, "view", default="view"): continue elif not security.check_access( "link", keys, "view", default="deny"): continue display_handler = config.get_display_handler(element_name) display_options = config.get_display_options(element_name) # the sidebar currently uses a different structure than the # tab widget so we have to translate widget_key = display_options.get("widget_key") if widget_key: class_name = class_handler.get_display_handler(widget_key) else: class_name = display_options.get("class_name") new_config_xml.append('''<element name="%s">''' % element_name) if class_name: new_config_xml.append('''<display class="%s">''' % class_name) else: new_config_xml.append('''<display widget_key="%s">''' % widget_key) for name, value in display_options.items(): if name in ['widget_key', 'class_name']: continue new_config_xml.append('''<%s>%s</%s>''' % (name, value, name)) new_config_xml.append('''</display>''') new_config_xml.append('''</element>''') new_config_xml.append('''</tab>''') new_config_xml.append('''</config>''') new_config_xml_str = "\n".join(new_config_xml) from tactic.ui.container import TabWdg tab = TabWdg(config_xml=new_config_xml_str, view="tab", show_add=False, show_remove=False, use_default_style=use_default_style) top.add(tab) return top
def get_display(my): top = DivWdg() top.add_border() top.add_style("padding: 10px") top.add_color("color", "color") top.add_color("background", "background") #top.add_style("height: 550px") top.add_class("spt_reports_top") title = DivWdg() title.add("Searchable Lists") title.add_style("font-size: 18px") title.add_style("font-weight: bold") title.add_style("text-align: center") title.add_style("padding: 10px") title.add_style("margin: -10px -10px 0px -10px") top.add(title) title.add_gradient("background", "background3", 5, -10) top.add("<br/>") button_div = DivWdg() top.add(button_div) button = SingleButtonWdg(title="Collapse", icon=IconWdg.ARROW_UP) button_div.add(button) top.add(button_div) button.add_behavior( { 'type': 'click_up', 'cbjs_action': ''' var top = bvr.src_el.getParent(".spt_reports_top"); var element = top.getElement(".spt_reports_list"); spt.toggle_show_hide(element) ''' } ) #desc = DivWdg() #top.add(desc) #desc.add("Dashboard") #desc.add_style("width: 600px") reports = [] # read the config file """ from pyasm.widget import WidgetConfig tmp_path = __file__ dir_name = os.path.dirname(tmp_path) file_path="%s/../config/reports-conf.xml" % (dir_name) config = WidgetConfig.get(file_path=file_path, view="definition") element_names = config.get_element_names() for element_name in element_names: print "element_name: ", element_name attrs = config.get_element_attributes(element_name) report_data = {} kwargs = config.get_display_options(element_name) class_name = kwargs.get('class_name') report_data['class_name'] = class_name report_data['kwargs'] = kwargs report_data['title'] = attrs.get("title") report_data['description'] = attrs.get("description") reports.append(report_data) """ project = Project.get() project_code = project.get_code() search_type_objs = project.get_search_types() filtered = [] for search_type_obj in search_type_objs: search_type = search_type_obj.get_value("search_type") # FIXME: this code is also present from pyasm.security import get_security_version security_version = get_security_version() if security_version >= 2 and not search_type.startswith("sthpw/") and not search_type.startswith("config/"): security = Environment.get_security() table = search_type_obj.get_value("table_name") default = "deny" key = { "element": "%s_list" % table } key2 = { "element": "%s_list" % table, "project": project_code } key3 = { "element": "*" } key4 = { "element": "*", "project": project_code } keys = [key, key2, key3, key4] if not security.check_access("link", keys, "view", default=default): continue key = { "code": search_type } key2 = { "code": "*" } keys = [key, key2] if not security.check_access("search_type", keys, "view", default=default): continue filtered.append(search_type_obj) search_type_objs = filtered for search_type_sobj in search_type_objs: description = search_type_sobj.get_value("description") search_type = search_type_sobj.get_value("search_type") search = Search(search_type) count = search.get_count() title_div = DivWdg() items_div = DivWdg() title_div.add(items_div) items_div.add_style("font-size: 9px") items_div.add_style("font-weight: italic") items_div.add_style("float: right") items_div.add("%s item/s" % count) title_div.add(search_type_sobj.get_title()) description_div = DivWdg() description_div.add(description) description_div.add_style("padding: 5px") if not description: description_div.add("<br/>(No description)") description_div.add_style("font-style: italic") description_div.add_style("opacity: 0.3") report_data = { 'title': search_type_sobj.get_title(), 'title_wdg': title_div, 'class_name': 'tactic.ui.panel.ViewPanelWdg', 'kwargs': { 'search_type': search_type, 'view': 'table', 'simple_search_view': 'simple_search' }, 'description': description_div, 'search_type': search_type_sobj } reports.append(report_data) # create a bunch of panels list_div = DivWdg() top.add(list_div) list_div.add_class("spt_reports_list") table = Table() list_div.add(table) table.add_color("color", "color") table.add_style("margin-bottom: 5px") table.center() top.add("<br clear='all'/>") for i, report in enumerate(reports): if i == 0 or i%4 == 0: tr = table.add_row() td = table.add_cell() td.add_style("vertical-align: top") td.add_style("padding: 3px") class_name = report.get("class_name") kwargs = report.get("kwargs") title = report.get("title") description = report.get("description") #image = "<img src='/context/images/getting_started_schema.png'/>" image = "<img src='/context/images/getting_started_pipeline.png'/>" thumb_div = DivWdg() image = thumb_div thumb_div.add_border() thumb_div.set_box_shadow("1px 1px 1px 1px") thumb = ThumbWdg() thumb_div.add(thumb) thumb.set_sobject(report.get("search_type")) thumb.set_icon_size(60) behavior = { 'type': 'click_up', 'title': title, 'class_name': class_name, 'kwargs': kwargs, 'cbjs_action': ''' var top = bvr.src_el.getParent(".spt_reports_top"); //spt.tab.set_main_body_tab(); spt.tab.set_tab_top(top); var kwargs = {}; spt.tab.add_new(bvr.title, bvr.title, bvr.class_name, bvr.kwargs); ''' } title_wdg = report.get("title_wdg") schema_wdg = my.get_section_wdg(title_wdg, description, image, behavior) td.add(schema_wdg) from tactic.ui.container import TabWdg tab = TabWdg(show_add=False) top.add(tab) return top
def get_content_wdg(self): base_dir = self.session.get_value("base_dir") location = self.session.get_value("location") session_code = self.session.get_code() div = DivWdg() #repo_dir = "/home/apache/inhance_repo" repo_dir = "/home/apache/assets/simulation/vehicles" repo_location = "server" config_xml = [] config_xml.append(''' <config> <tab> ''') config_xml.append(''' <element name='files'> <display class='tactic.ui.tools.IngestionToolDirListWdg'> <base_dir>%s</base_dir> <location>%s</location> <session_code>%s</session_code> <cache_key>paths</cache_key> </display> </element> ''' % (base_dir, location, session_code)) config_xml.append(''' <element name='rules'> <display class='tactic.ui.tools.IngestionToolWdg'> <session_code>%s</session_code> </display> </element> ''' % (session_code)) config_xml.append(''' <element name='repository'> <display class='tactic.ui.tools.IngestionToolDirListWdg'> <base_dir>%s</base_dir> <location>%s</location> <session_code>%s</session_code> <cache_key>repo_paths</cache_key> </display> </element> ''' % (repo_dir, repo_location, self.session_code)) config_xml.append(''' <element name='tools'> <display class='tactic.ui.tools.IngestionToolShelfWdg'> <base_dir>%s</base_dir> <location>%s</location> </display> </element> ''' % (base_dir, location)) config_xml.append(''' </tab> </config> ''') config_xml = "".join(config_xml) tab = TabWdg(config_xml=config_xml, width="700px") div.add(tab) return div
def get_display(self): top = self.top; self.set_as_panel(top) top.add_class("spt_chat_top") inner = DivWdg() top.add(inner) inner.add_behavior( { 'type': 'load', 'cbjs_action': MessageWdg.get_onload_js() } ) search = Search("sthpw/subscription") search.add_filter("category", "chat") search.add_user_filter() chats = search.get_sobjects() keys = [x.get_value("message_code") for x in chats] """ chat_list_div = DivWdg() inner.add(chat_list_div) for i, chat in enumerate(chats): chat_div = DivWdg() chat_list_div.add(chat_div) chat_div.add_style("padding: 5px") chat_div.add_class("hand") # find all the users with the same chat key = chat.get_value("message_code") #chat_div.add(key) chat_div.add("#%s: " % i) search = Search("sthpw/subscription") search.add_filter("message_code", key) subscriptions = search.get_sobjects() users = [x.get_value("login") for x in subscriptions] chat_div.add(", ".join(users)) chat_div.add_behavior( { 'type': 'click_up', 'key': key, 'cbjs_action': ''' var class_name = 'tactic.ui.app.ChatSessionWdg'; var kwargs = { 'key': bvr.key, } spt.panel.load_popup("Chat: " + bvr.key, class_name, kwargs); ''' } ) chat_div.add_behavior( { 'type': 'mouseover', 'cbjs_action': ''' bvr.src_el.setStyle("color", "#214e75"); ''' } ) chat_div.add_behavior( { 'type': 'mouseout', 'cbjs_action': ''' bvr.src_el.setStyle("color", ""); ''' } ) """ #keys = self.kwargs.get("keys") #if not keys: # return inner.add( self.get_add_chat_wdg() ) inner.add("<br/>") from tactic.ui.container import TabWdg tab = TabWdg( show_add=False, show_remove=False ) inner.add(tab) for key in keys: search = Search("sthpw/subscription") search.add_filter("message_code", key) subscriptions = search.get_sobjects() users = [x.get_value("login") for x in subscriptions] users = ", ".join(users) session_div = DivWdg() session_div.set_name(users) session_div.add_style("width: 100%") #inner.add(session_div) tab.add(session_div) session = ChatSessionWdg(key=key) session_div.add(session) inner.add("<br clear='all'/>") if self.kwargs.get("is_refresh") == 'true': return inner else: return top
def get_display(my): my.sobject = my.get_sobject() top = DivWdg() top.add_class("spt_detail_top") top.add_color("background", "background") top.add_color("color", "color") if not my.sobject: top.add("No SObject defined for this widget") return top if my.parent: my.search_type = my.parent.get_base_search_type() my.search_key = SearchKey.get_by_sobject(my.parent) top.add_attr("spt_parent_key", my.search_key) my.pipeline_code = my.parent.get_value("pipeline_code", no_exception=True) my.full_search_type = my.parent.get_search_type() else: my.pipeline_code = my.sobject.get_value("pipeline_code", no_exception=True) my.search_type = my.sobject.get_base_search_type() my.search_key = SearchKey.get_by_sobject(my.sobject) my.full_search_type = my.sobject.get_search_type() if not my.pipeline_code: my.pipeline_code = 'default' top.add_style("text-align: left") my.set_as_panel(top) table = Table() #from tactic.ui.container import ResizableTableWdg #table = ResizableTableWdg() table.add_color("background", "background") table.add_color("color", "color") top.add(table) table.set_max_width() table.add_row() if my.parent: code = my.parent.get_value("code", no_exception=True) name = my.parent.get_value("name", no_exception=True) search_type_obj = my.parent.get_search_type_obj() else: code = my.sobject.get_value("code", no_exception=True) name = my.sobject.get_value("name", no_exception=True) search_type_obj = my.sobject.get_search_type_obj() # add the title td = table.add_cell() td.add_attr("colspan", "3") title = DivWdg() search = Search("sthpw/snapshot") search.add_filter("search_type", "sthpw/search_type") search.add_filter("search_code", search_type_obj.get_value("code")) if search.get_sobject(): thumb = ThumbWdg() title.add(thumb) thumb.set_icon_size(30) thumb.set_sobject(search_type_obj) thumb.add_style("float: left") td.add(title) title.add_color("background", "background3") title.add_style("height: 20px") title.add_style("padding: 6px") title.add_style("font-weight: bold") title.add_style("font-size: 1.4em") stype_title = search_type_obj.get_value("title") if stype_title: title.add("%s: " % stype_title) if name: title.add("%s" % name) if code: title.add(" <i style='font-size: 0.8; opacity: 0.7'>(%s)</i>" % code) elif code: title.add("%s" % code) else: title.add("(No name)") title.add_border() table.add_row() # left td = table.add_cell() td.add_style("width: 300px") td.add_style("min-width: 300px") td.add_style("vertical-align: top") div = DivWdg() td.add(div) div.add_class("spt_sobject_detail_top") thumb_table = Table() div.add(thumb_table) thumb_table.add_row() from tactic.ui.panel import ThumbWdg2 thumb = ThumbWdg2() # use a larger version for clearer display #thumb.set_icon_type('web') if my.parent: thumb.set_sobject(my.parent) search_key = my.parent.get_search_key() else: thumb.set_sobject(my.sobject) search_key = my.sobject.get_search_key() gallery_div = DivWdg() div.add(gallery_div) gallery_div.add_class("spt_tile_gallery") thumb_table.add_behavior({ 'type': 'click_up', 'search_key': search_key, 'cbjs_action': ''' var top = bvr.src_el.getParent(".spt_sobject_detail_top"); var gallery_el = top.getElement(".spt_tile_gallery"); var class_name = 'tactic.ui.widget.gallery_wdg.GalleryWdg'; var kwargs = { search_key: bvr.search_key, search_keys: [bvr.search_key], }; spt.panel.load(gallery_el, class_name, kwargs); ''' }) # prefer to see the original image, then web #thumb.set_option('image_link_order', 'main|web|icon') #thumb.set_option("detail", "false") #thumb.set_option("icon_size", "100%") td = thumb_table.add_cell(thumb) td.add_style("vertical-align: top") td.add_style("width: auto") td.add_style("padding: 15px") sobject_info_wdg = my.get_sobject_info_wdg() sobject_info_wdg.add_style("width: auto") td.add(sobject_info_wdg) if my.search_type == 'sthpw/task' and not my.parent: pass else: sobject_info_wdg = my.get_sobject_detail_wdg() td = table.add_cell() td.add(sobject_info_wdg) td.add_style("vertical-align: top") td.add_style("overflow: hidden") # right td = table.add_cell() td.add_style("text-align: left") td.add_style("vertical-align: top") td.add_class("spt_notes_wrapper") notes_div = DivWdg() td.add(notes_div) from tactic.ui.widget.discussion_wdg import DiscussionWdg discussion_wdg = DiscussionWdg(search_key=my.search_key, context_hidden=False, show_note_expand=False) notes_div.add(discussion_wdg) notes_div.add_style("min-width: 300px") notes_div.add_style("height: 200") notes_div.add_style("overflow-y: auto") notes_div.add_class("spt_resizable") # get the process if my.parent: process = my.sobject.get_value("process") else: process = '' # content tr = table.add_row() td = table.add_cell() td.add_attr("colspan", "5") #td.add_attr("colspan", "3") # create a state for tab. The tab only passes a search key # parent key search_key = SearchKey.get_by_sobject(my.sobject) parent_key = "" if search_key.startswith("sthpw/"): parent = my.sobject.get_parent() if parent: parent_key = parent.get_search_key() state = { 'search_key': search_key, 'parent_key': parent_key, 'process': process, } WebState.get().push(state) config_xml = my.get_config_xml() config = WidgetConfig.get(view="tab", xml=config_xml) if process: custom_view = "tab_config_%s" % process else: custom_view = "tab_config" search = Search("config/widget_config") search.add_filter("category", "TabWdg") search.add_filter("search_type", my.search_type) search.add_filter("view", custom_view) custom_config_sobj = search.get_sobject() if custom_config_sobj: custom_config_xml = custom_config_sobj.get_value("config") custom_config = WidgetConfig.get(view=custom_view, xml=custom_config_xml) config = WidgetConfigView(search_type='TabWdg', view=custom_view, configs=[custom_config, config]) #menu = my.get_extra_menu() #tab = TabWdg(config=config, state=state, extra_menu=menu) tab = TabWdg(config=config, state=state, show_add=False, show_remove=False, tab_offset=5) tab.add_style("margin: 0px -2px -2px -2px") td.add(tab) td.add_style("padding-top: 10px") return top
def get_display(self): top = self.top login = self.kwargs.get("login") if not login or login == "$LOGIN": login = Environment.get_user_name() login_sobj = Login.get_by_code(login) #top.add_style("margin-top: -2px") #top.add_style("margin-left: -2px") thumb_div = DivWdg() thumb_div.add_style("float: left") thumb_div.add_style("margin-right: 5px") thumb_div.add_style("margin-bottom: 5px") thumb_div.add_style("padding-top: 1px") thumb = ThumbWdg() thumb.set_sobject(login_sobj) thumb_div.add(thumb) thumb.set_icon_size(90) thumb.set_aspect("height") full_name = login_sobj.get_full_name() info_wdg = DivWdg() top.add(info_wdg) name_wdg = DivWdg() info_wdg.add(thumb_div) info_wdg.add(name_wdg) name_wdg.add(" " * 3) name_wdg.add(full_name) name_wdg.add_style("font-size: 1.5em") name_wdg.add_style("font-weight: bold") name_wdg.add_style("padding: 5px") #name_wdg.add_style("margin-left: -10px") name_wdg.add_color("background", "background3") name_wdg.add_style("height: 20px") name_wdg.add_style("margin-bottom: 0px") name_wdg.add_border() info_wdg.add("<br/>") from tactic.ui.container import TabWdg # return if the supplied tab view has a config xml if self.tab_view: search = Search("config/widget_config") search.add_filter("category", "TabWdg") search.add_filter("view", self.tab_view) config_sobj = search.get_sobject() if config_sobj: config_xml = config_sobj.get_value('config') # replace the variable $login with the login clicked if login: config_xml = config_xml.replace('$login', login) tab = TabWdg(config_xml=config_xml, view=self.tab_view, show_add=False, show_remove=False) top.add(tab) return top config_xml = [] config_xml.append('<config>') config_xml.append('<tab>') config_xml.append(''' <element name='schedule'> <display class='tactic.ui.widget.TaskCalendarWdg'> <assigned>%s</assigned> <sobject_display_expr>%s</sobject_display_expr> <show_header>true</show_header> <show_border>false</show_border> </display> </element> ''' % (login, self.sobject_display_expr)) config_xml.append(''' <element name='activity'> <display class='tactic.ui.widget.ActivityCalendarWdg'> <login>%s</login> <cell_width>100px</cell_width> <cell_height>50px</cell_height> <show_header>true</show_header> <show_border>false</show_border> </display> </element> ''' % login) config_xml.append(''' <element name='tasks'> <display class='tactic.ui.panel.FastTableLayoutWdg'> <search_type>sthpw/task</search_type> <view>table</view> <expression>@SOBJECT(sthpw/task['assigned','%s']['@ORDER_BY', 'bid_start_date desc'])</expression> <mode>simple</mode> </display> </element> ''' % login) config_xml.append(''' <element name='work_hours'> <display class='tactic.ui.widget.SObjectCalendarWdg'> <login>%s</login> <!-- <cell_width>100px</cell_width> --> <cell_height>50px</cell_height> <show_header>true</show_header> <show_border>false</show_border> <search_type>sthpw/work_hour</search_type> <handler>tactic.ui.widget.WorkHourCalendarDayWdg</handler> <start_date_col>day</start_date_col> <end_date_col>day</end_date_col> </display> </element> ''' % login) config_xml.append(''' <element name='recent transactions'> <display class='tactic.ui.panel.FastTableLayoutWdg'> <search_type>sthpw/transaction_log</search_type> <view>table</view> <expression>@SOBJECT(sthpw/transaction_log['login','%s']['@ORDER_BY','timestamp desc']['@LIMIT','30'])</expression> <element_names>code,timestamp,namespace,description,transaction_log_hidden</element_names> <show_shelf>false</show_shelf> <show_select>false</show_select> </display> </element> ''' % login) config_xml.append('</tab>') config_xml.append('</config>') config_xml = "".join(config_xml) tab = TabWdg(config_xml=config_xml, view='tab', show_add=False, show_remove=False) top.add(tab) tab.add_style("margin-left: -2px") tab.add_style("margin-right: -2px") return top
def get_display(my): top = my.top login = my.kwargs.get("login") if not login or login == "$LOGIN": login = Environment.get_user_name() login_sobj = Login.get_by_code(login) # top.add_style("margin-top: -2px") # top.add_style("margin-left: -2px") thumb_div = DivWdg() thumb_div.add_style("float: left") thumb_div.add_style("margin-right: 5px") thumb_div.add_style("margin-bottom: 5px") thumb_div.add_style("padding-top: 1px") thumb = ThumbWdg() thumb.set_sobject(login_sobj) thumb_div.add(thumb) thumb.set_icon_size(90) thumb.set_aspect("height") full_name = login_sobj.get_full_name() info_wdg = DivWdg() top.add(info_wdg) name_wdg = DivWdg() info_wdg.add(thumb_div) info_wdg.add(name_wdg) name_wdg.add(" " * 3) name_wdg.add(full_name) name_wdg.add_style("font-size: 1.5em") name_wdg.add_style("font-weight: bold") name_wdg.add_style("padding: 5px") # name_wdg.add_style("margin-left: -10px") name_wdg.add_color("background", "background3") name_wdg.add_style("height: 20px") name_wdg.add_style("margin-bottom: 0px") name_wdg.add_border() info_wdg.add("<br/>") from tactic.ui.container import TabWdg # return if the supplied tab view has a config xml if my.tab_view: search = Search("config/widget_config") search.add_filter("category", "TabWdg") search.add_filter("view", my.tab_view) config_sobj = search.get_sobject() if config_sobj: config_xml = config_sobj.get_value("config") # replace the variable $login with the login clicked if login: config_xml = config_xml.replace("$login", login) tab = TabWdg(config_xml=config_xml, view=my.tab_view, show_add=False, show_remove=False) top.add(tab) return top config_xml = [] config_xml.append("<config>") config_xml.append("<tab>") config_xml.append( """ <element name='activity'> <display class='tactic.ui.widget.ActivityCalendarWdg'> <login>%s</login> <cell_width>100px</cell_width> <cell_height>50px</cell_height> <show_header>true</show_header> <show_border>false</show_border> </display> </element> """ % login ) config_xml.append( """ <element name='schedule'> <display class='tactic.ui.widget.TaskCalendarWdg'> <assigned>%s</assigned> <sobject_display_expr>%s</sobject_display_expr> <show_header>true</show_header> <show_border>false</show_border> </display> </element> """ % (login, my.sobject_display_expr) ) config_xml.append( """ <element name='tasks'> <display class='tactic.ui.panel.FastTableLayoutWdg'> <search_type>sthpw/task</search_type> <view>table</view> <expression>@SOBJECT(sthpw/task['assigned','%s']['@ORDER_BY', 'bid_start_date desc'])</expression> <mode>simple</mode> </display> </element> """ % login ) config_xml.append( """ <element name='work_hours'> <display class='tactic.ui.widget.SObjectCalendarWdg'> <login>%s</login> <!-- <cell_width>100px</cell_width> --> <cell_height>50px</cell_height> <show_header>true</show_header> <show_border>false</show_border> <search_type>sthpw/work_hour</search_type> <handler>tactic.ui.widget.WorkHourCalendarDayWdg</handler> <start_date_col>day</start_date_col> <end_date_col>day</end_date_col> </display> </element> """ % login ) config_xml.append( """ <element name='recent transactions'> <display class='tactic.ui.panel.FastTableLayoutWdg'> <search_type>sthpw/transaction_log</search_type> <view>table</view> <expression>@SOBJECT(sthpw/transaction_log['login','%s']['@ORDER_BY','timestamp desc']['@LIMIT','30'])</expression> <element_names>code,timestamp,namespace,description,transaction_log_hidden</element_names> <show_shelf>false</show_shelf> <show_select>false</show_select> </display> </element> """ % login ) config_xml.append("</tab>") config_xml.append("</config>") config_xml = "".join(config_xml) tab = TabWdg(config_xml=config_xml, view="tab", show_add=False, show_remove=False) top.add(tab) tab.add_style("margin-left: -2px") tab.add_style("margin-right: -2px") return top