def set(self, owner_id=None, dashboard_id=None, old_layout_id=None): """Set a new layout definition for the dashboard (replacing the existing one), using the current content of the :attr:`layout_dict`. The parameters are optional - if not specified, the current values of :attr:`owner_id`, :attr:`dashboard_id` and :attr:`layout_id` are used. :param owner_id: the owner ID of the dashboard :param dashboard_id: the dashboard's ID :param old_layout_id: ``None`` if this should be a new layout definition for the dashboard, ``layout_id`` of the existing layout otherwise :return: a ``layout_id`` of a newly set layout if the operation was successful, ``None`` otherwise (ie. when the passed ``old_layout_id`` didn't match the version in the database) """ owner_id = owner_id or self.owner_id if not owner_id: raise ValueError( 'owner_id not set in Layout and not passed as an argument') dashboard_id = dashboard_id or self.dashboard_id if not dashboard_id: raise ValueError( 'dashboard_id not set in Layout and not passed as an argument') old_layout_id = old_layout_id or self.layout_id # a layout def is a layout_dict serialized as a list of items. The list is # sorted by tile creation time (but this assumption should not be generally made). new_layout_def = serialize.mjson( sorted(self.layout_dict.items(), key=lambda (tile_id, vo): tile_id.time)) # Merge old layout_props with new data old_layout_props_row = c.dao.LayoutDAO.select(owner_id, dashboard_id, ['layout_props']) if not old_layout_props_row and old_layout_id: return None if old_layout_props_row and old_layout_props_row['layout_props']: old_layout_props = serialize.json_loads( old_layout_props_row['layout_props']) else: old_layout_props = {'by_tile_id': []} by_tile_id = {} old_by_tile_id = dict(old_layout_props['by_tile_id']) tile_ids_to_fetch = [] for tile_id in self.layout_dict: if tile_id in old_by_tile_id: by_tile_id[tile_id] = old_by_tile_id[tile_id] elif tile_id in self._included_tiles: by_tile_id[tile_id] = self.props_of_tile( self._included_tiles[tile_id]) else: tile_ids_to_fetch.append(tile_id) tile_dict = Tile.select_multi(dashboard_id, tile_ids_to_fetch) for tile_id, tile in tile_dict.items(): by_tile_id[tile.tile_id] = self.props_of_tile(tile) # Compute data for sscreator and tpcreator sscs_data = set() master_data = set() for props in by_tile_id.values(): if props.get('sscs'): #sscs_data.add((props['report_id'], tuple(props['tags']))) sscs_data.add(props['report_id']) if props.get('is_master'): master_data.add(props['report_id']) new_layout_props = serialize.mjson({'by_tile_id': by_tile_id.items()}) # Set the new layout new_layout_id = gen_timeuuid() res = c.dao.LayoutDAO.set(owner_id, dashboard_id, old_layout_id, new_layout_id, new_layout_def, new_layout_props) if not res: log.info('Setting new layout failed') return None # Insert layout_by_report for sscs and tpcreator c.dao.LayoutDAO.insert_layout_by_report_multi(owner_id, sscs_data, [], 'sscs', dashboard_id, new_layout_id) c.dao.LayoutDAO.insert_layout_by_report_multi(owner_id, master_data, [], 'tpcreator', dashboard_id, new_layout_id) self.layout_id = new_layout_id return new_layout_id
def test_handle_tpcreator(self): rd = new_report_data('points') tile_config = { 'tw_type': 'Range', 'tags': ['p1:10'], 'series_spec_list': [ dataseries.SeriesSpec(2, 0, dict(op='eq', args=['monique'])), ], 'tile_options': { 'seconds_back': 600, 'tile_title': 'm0', 'sscs': dataseries.SeriesSpec(2, 0, dict(op='eq', args=['monique'])), } } tile_config['tile_options'][ 'tpcreator_uispec'] = tpcreator.suggested_tpcreator_uispec( tile_config['tags']) master_tile = Tile.insert(rd.owner_id, rd.report.report_id, rd.dashboard_id, tile_config) layouts.place_tile(master_tile) d = [ OrderedDict([('user_name', 'robert3'), ('is_active', True), ('points', 128)]) ] rd.report.process_input(json.dumps(d), tags=['p1:10']) master_tile = rd.only_tile_from_layout() self.assertEqual([], tpcreator.select_tpcreated_tile_ids(master_tile)) self.assertEqual([master_tile.tile_id], _select_tile_ids(rd.dashboard_id)) d = [ OrderedDict([('user_name', 'robert3'), ('is_active', True), ('points', 128)]) ] rd.report.process_input(json.dumps(d), tags=['p1:20']) self.assertEqual(2, len(_select_tile_ids(rd.dashboard_id))) tiles = Tile.select_multi(rd.dashboard_id, _select_tile_ids(rd.dashboard_id)).values() created_tile = util.first(tiles, key=lambda t: not t.is_master_tile()) self.assertEqual(['p1:20'], created_tile.tile_options['tags']) self.assertEqual(600, created_tile.tile_options['seconds_back']) self.assertEqual(tile_config['tile_options']['sscs'], created_tile.tile_options['sscs']) td = created_tile.get_tile_data() self.assertEqual('points (monique, robert3)', td['generated_tile_title']) self.assertEqual('[p1:20]', td['generated_tile_title_postfix']) d = [ OrderedDict([('user_name', 'robert3'), ('is_active', True), ('points', 128)]) ] rd.report.process_input(json.dumps(d), tags=['p1:30', 'p2:30']) self.assertEqual(3, len(_select_tile_ids(rd.dashboard_id))) del tile_config['tile_options']['tpcreator_uispec'] tile_config['tile_options']['tile_title'] = 'ot0' other_tile = Tile.insert(rd.owner_id, rd.report.report_id, rd.dashboard_id, tile_config) layouts.place_tile(other_tile) self.assertEqual(4, len(_select_tile_ids(rd.dashboard_id))) self.assertEqual(2, len(tpcreator.select_tpcreated_tile_ids(master_tile))) for i, tile_id in enumerate( tpcreator.select_tpcreated_tile_ids(master_tile)): tile = Tile.select(rd.dashboard_id, tile_id) tile_config = tile.get_tile_config() tile_config['tile_options']['tile_title'] = 'tpc%d' % i new_tile = tile.insert_similar(tile_config) layouts.replace_tiles({tile: new_tile}, None) return rd, Tile.select(master_tile.dashboard_id, master_tile.tile_id)