ソースを参照

allow to activate/desactive content view in left side treeview

Damien ACCORSI 10 年 前
コミット
aa75de6267

+ 2 - 0
tracim/development.ini.base ファイルの表示

122
 website.home.subtitle = Default login: admin@admin.admin (password: admin@admin.admin)
122
 website.home.subtitle = Default login: admin@admin.admin (password: admin@admin.admin)
123
 website.home.tag_line = <div class="text-center" style="font-weight: bold;">Collaboration, versionning and traceability</div>
123
 website.home.tag_line = <div class="text-center" style="font-weight: bold;">Collaboration, versionning and traceability</div>
124
 website.home.below_login_form = in case of problem, please contact the administrator.
124
 website.home.below_login_form = in case of problem, please contact the administrator.
125
+# Values may be 'all' or 'folders'
126
+website.treeview.content = all
125
 
127
 
126
 # The following base_url is used for links and icons
128
 # The following base_url is used for links and icons
127
 # integrated in the email notifcations
129
 # integrated in the email notifcations

+ 12 - 1
tracim/tracim/config/app_cfg.py ファイルの表示

79
 from sqlalchemy import and_
79
 from sqlalchemy import and_
80
 #This tells to TurboGears how to retrieve the data for your user
80
 #This tells to TurboGears how to retrieve the data for your user
81
 class ApplicationAuthMetadata(TGAuthMetadata):
81
 class ApplicationAuthMetadata(TGAuthMetadata):
82
+
82
     def __init__(self, sa_auth):
83
     def __init__(self, sa_auth):
83
         self.sa_auth = sa_auth
84
         self.sa_auth = sa_auth
85
+
84
     def authenticate(self, environ, identity):
86
     def authenticate(self, environ, identity):
85
-        user = self.sa_auth.dbsession.query(self.sa_auth.user_class).filter(and_(self.sa_auth.user_class.is_active==True, self.sa_auth.user_class.email==identity['login'])).first()
87
+        user = self.sa_auth.dbsession.query(self.sa_auth.user_class).filter(and_(
88
+            self.sa_auth.user_class.is_active==True,
89
+            self.sa_auth.user_class.email==identity['login']
90
+        )).first()
91
+
86
         if user and user.validate_password(identity['password']):
92
         if user and user.validate_password(identity['password']):
87
             return identity['login']
93
             return identity['login']
88
     def get_user(self, identity, userid):
94
     def get_user(self, identity, userid):
222
         self.TRACKER_JS_PATH = tg.config.get('js_tracker_path')
228
         self.TRACKER_JS_PATH = tg.config.get('js_tracker_path')
223
         self.TRACKER_JS_CONTENT = self.get_tracker_js_content(self.TRACKER_JS_PATH)
229
         self.TRACKER_JS_CONTENT = self.get_tracker_js_content(self.TRACKER_JS_PATH)
224
 
230
 
231
+        self.WEBSITE_TREEVIEW_CONTENT = tg.config.get('website.treeview.content')
232
+
225
 
233
 
226
     def get_tracker_js_content(self, js_tracker_file_path = None):
234
     def get_tracker_js_content(self, js_tracker_file_path = None):
227
         js_tracker_file_path = tg.config.get('js_tracker_path', None)
235
         js_tracker_file_path = tg.config.get('js_tracker_path', None)
239
         ASYNC = 'ASYNC'
247
         ASYNC = 'ASYNC'
240
         SYNC = 'SYNC'
248
         SYNC = 'SYNC'
241
 
249
 
250
+        TREEVIEW_FOLDERS = 'folders'
251
+        TREEVIEW_ALL = 'all'
252
+
242
 #######
253
 #######
243
 #
254
 #
244
 # INFO - D.A. - 2014-11-05
255
 # INFO - D.A. - 2014-11-05

+ 32 - 7
tracim/tracim/controllers/workspace.py ファイルの表示

5
 from tg.i18n import ugettext as _
5
 from tg.i18n import ugettext as _
6
 from tg.predicates import not_anonymous
6
 from tg.predicates import not_anonymous
7
 
7
 
8
+from tracim.config.app_cfg import CFG
9
+
8
 from tracim.controllers import TIMRestController
10
 from tracim.controllers import TIMRestController
9
 from tracim.controllers.content import UserWorkspaceFolderRestController
11
 from tracim.controllers.content import UserWorkspaceFolderRestController
10
 
12
 
20
 from tracim.model.serializers import Context, CTX, DictLikeClass
22
 from tracim.model.serializers import Context, CTX, DictLikeClass
21
 
23
 
22
 
24
 
23
-
24
-
25
 class UserWorkspaceRestController(TIMRestController):
25
 class UserWorkspaceRestController(TIMRestController):
26
 
26
 
27
     allow_only = not_anonymous()
27
     allow_only = not_anonymous()
88
         # including the selected node, all parents (and their siblings)
88
         # including the selected node, all parents (and their siblings)
89
         workspace, content = convert_id_into_instances(current_id)
89
         workspace, content = convert_id_into_instances(current_id)
90
 
90
 
91
+        # The following step allow to select the parent folder when content itself is not visible in the treeview
92
+        if content.type!=ContentType.Folder and CFG.CST.TREEVIEW_ALL!=CFG.get_instance().WEBSITE_TREEVIEW_CONTENT:
93
+            content = content.parent if content.parent else None
94
+
91
         # This is the init of the recursive-like build of the tree
95
         # This is the init of the recursive-like build of the tree
92
         content_parent = content
96
         content_parent = content
93
         tree_items = []
97
         tree_items = []
114
 
118
 
115
         return Context(CTX.MENU_API_BUILD_FROM_TREE_ITEM).toDict(full_tree, 'd')
119
         return Context(CTX.MENU_API_BUILD_FROM_TREE_ITEM).toDict(full_tree, 'd')
116
 
120
 
117
-
118
     def _build_sibling_list_of_workspaces(self, workspace: Workspace, child_contents: [NodeTreeItem], select_active_workspace = False, all_workspaces = True) -> [NodeTreeItem]:
121
     def _build_sibling_list_of_workspaces(self, workspace: Workspace, child_contents: [NodeTreeItem], select_active_workspace = False, all_workspaces = True) -> [NodeTreeItem]:
119
 
122
 
120
         root_items = []
123
         root_items = []
141
 
144
 
142
         return root_items
145
         return root_items
143
 
146
 
147
+
144
     def _build_sibling_list_of_tree_items(self,
148
     def _build_sibling_list_of_tree_items(self,
145
                                           workspace: Workspace,
149
                                           workspace: Workspace,
146
                                           content: Content,
150
                                           content: Content,
152
         tree_items = []
156
         tree_items = []
153
 
157
 
154
         parent = content.parent if content else None
158
         parent = content.parent if content else None
155
-        for child in api.get_child_folders(parent, workspace, allowed_content_types, ignored_item_ids):
159
+
160
+        viewable_content_types = self._get_treeviewable_content_types_or_none()
161
+        child_contents = api.get_child_folders(parent, workspace, allowed_content_types, ignored_item_ids, viewable_content_types)
162
+        for child in child_contents:
156
             children_to_add = children if child==content else []
163
             children_to_add = children if child==content else []
157
-            is_selected = True if select_active_node and child==content else False
164
+            if child==content and select_active_node:
165
+                # The item is the requested node, so we select it
166
+                is_selected = True
167
+            elif content not in child_contents and select_active_node and child==content:
168
+                # The item is not present in the list, so we select its parent node
169
+                is_selected = True
170
+            else:
171
+                is_selected = False
172
+
158
             new_item = NodeTreeItem(child, children_to_add, is_selected)
173
             new_item = NodeTreeItem(child, children_to_add, is_selected)
159
             tree_items.append(new_item)
174
             tree_items.append(new_item)
160
 
175
 
176
+        # This allow to show contents and folders group by type
177
+        tree_items = ContentApi.sort_tree_items(tree_items)
161
 
178
 
162
         return parent, tree_items
179
         return parent, tree_items
163
 
180
 
172
 
189
 
173
         ignore_item_ids = [int(ignore_id)] if ignore_id else []
190
         ignore_item_ids = [int(ignore_id)] if ignore_id else []
174
         workspace, content = convert_id_into_instances(id)
191
         workspace, content = convert_id_into_instances(id)
175
-        contents = ContentApi(tmpl_context.current_user).get_child_folders(content, workspace, [], ignore_item_ids)
176
 
192
 
177
-        dictified_contents = Context(CTX.MENU_API).toDict(contents, 'd')
193
+        viewable_content_types = self._get_treeviewable_content_types_or_none()
194
+        contents = ContentApi(tmpl_context.current_user).get_child_folders(content, workspace, [], ignore_item_ids, viewable_content_types)
195
+        # This allow to show contents and folders group by type
196
+        sorted_contents = ContentApi.sort_content(contents)
197
+
198
+        dictified_contents = Context(CTX.MENU_API).toDict(sorted_contents, 'd')
178
         return dictified_contents
199
         return dictified_contents
179
 
200
 
201
+    def _get_treeviewable_content_types_or_none(self):
202
+        if CFG.get_instance().WEBSITE_TREEVIEW_CONTENT==CFG.CST.TREEVIEW_ALL:
203
+            return ContentType.Any
204
+        return None # None means "workspaces and folders"

+ 23 - 0
tracim/tracim/lib/__init__.py ファイルの表示

38
 # l_('November')
38
 # l_('November')
39
 # l_('December')
39
 # l_('December')
40
 
40
 
41
+
42
+def cmp_to_key(mycmp):
43
+    """
44
+    List sort related function
45
+
46
+    Convert a cmp= function into a key= function
47
+    """
48
+    class K(object):
49
+        def __init__(self, obj, *args):
50
+            self.obj = obj
51
+        def __lt__(self, other):
52
+            return mycmp(self.obj, other.obj) < 0
53
+        def __gt__(self, other):
54
+            return mycmp(self.obj, other.obj) > 0
55
+        def __eq__(self, other):
56
+            return mycmp(self.obj, other.obj) == 0
57
+        def __le__(self, other):
58
+            return mycmp(self.obj, other.obj) <= 0
59
+        def __ge__(self, other):
60
+            return mycmp(self.obj, other.obj) >= 0
61
+        def __ne__(self, other):
62
+            return mycmp(self.obj, other.obj) != 0
63
+    return K

+ 69 - 4
tracim/tracim/lib/content.py ファイルの表示

5
 import tg
5
 import tg
6
 
6
 
7
 from sqlalchemy.orm.attributes import get_history
7
 from sqlalchemy.orm.attributes import get_history
8
+from tracim.lib import cmp_to_key
8
 from tracim.lib.notifications import Notifier
9
 from tracim.lib.notifications import Notifier
9
 from tracim.model import DBSession
10
 from tracim.model import DBSession
10
 from tracim.model.auth import User
11
 from tracim.model.auth import User
11
 from tracim.model.data import ContentStatus, ContentRevisionRO, ActionDescription
12
 from tracim.model.data import ContentStatus, ContentRevisionRO, ActionDescription
12
 from tracim.model.data import Content
13
 from tracim.model.data import Content
13
 from tracim.model.data import ContentType
14
 from tracim.model.data import ContentType
15
+from tracim.model.data import NodeTreeItem
14
 from tracim.model.data import Workspace
16
 from tracim.model.data import Workspace
15
 
17
 
18
+def compare_content_for_sorting_by_type_and_name(content1: Content, content2: Content):
19
+    """
20
+    :param content1:
21
+    :param content2:
22
+    :return:    1 if content1 > content2
23
+                -1 if content1 < content2
24
+                0 if content1 = content2
25
+    """
26
+
27
+    if content1.type==content2.type:
28
+        if content1.get_label().lower()>content2.get_label().lower():
29
+            return 1
30
+        elif content1.get_label().lower()<content2.get_label().lower():
31
+            return -1
32
+        return 0
33
+    else:
34
+        # TODO - D.A. - 2014-12-02 - Manage Content Types Dynamically
35
+        content_type_order = [ContentType.Folder, ContentType.Page, ContentType.Thread, ContentType.File]
36
+        result = content_type_order.index(content1.type)-content_type_order.index(content2.type)
37
+        if result<0:
38
+            return -1
39
+        elif result>0:
40
+            return 1
41
+        else:
42
+            return 0
43
+
44
+def compare_tree_items_for_sorting_by_type_and_name(item1: NodeTreeItem, item2: NodeTreeItem):
45
+    return compare_content_for_sorting_by_type_and_name(item1.node, item2.node)
46
+
47
+
16
 class ContentApi(object):
48
 class ContentApi(object):
17
 
49
 
18
-    def __init__(self, current_user: User, show_archived=False, show_deleted=False):
50
+    def __init__(self, current_user: User, show_archived=False, show_deleted=False, all_content_in_treeview=True):
19
         self._user = current_user
51
         self._user = current_user
20
         self._show_archived = show_archived
52
         self._show_archived = show_archived
21
         self._show_deleted = show_deleted
53
         self._show_deleted = show_deleted
54
+        self._show_all_type_of_contents_in_treeview = all_content_in_treeview
55
+
56
+
57
+    @classmethod
58
+    def sort_tree_items(cls, content_list: [NodeTreeItem])-> [Content]:
59
+        news = []
60
+        for item in content_list:
61
+            news.append(item)
62
+
63
+        content_list.sort(key=cmp_to_key(compare_tree_items_for_sorting_by_type_and_name))
64
+
65
+        return content_list
66
+
67
+
68
+    @classmethod
69
+    def sort_content(cls, content_list: [Content])-> [Content]:
70
+        content_list.sort(key=cmp_to_key(compare_content_for_sorting_by_type_and_name))
71
+        return content_list
72
+
22
 
73
 
23
     def _base_query(self, workspace: Workspace=None):
74
     def _base_query(self, workspace: Workspace=None):
24
         result = DBSession.query(Content)
75
         result = DBSession.query(Content)
33
 
84
 
34
         return result
85
         return result
35
 
86
 
36
-    def get_child_folders(self, parent: Content=None, workspace: Workspace=None, filter_by_allowed_content_types: list=[], removed_item_ids: list=[]) -> [Content]:
87
+    def get_child_folders(self, parent: Content=None, workspace: Workspace=None, filter_by_allowed_content_types: list=[], removed_item_ids: list=[], allowed_node_types=None) -> [Content]:
88
+        """
89
+        This method returns child items (folders or items) for left bar treeview.
90
+
91
+        :param parent:
92
+        :param workspace:
93
+        :param filter_by_allowed_content_types:
94
+        :param removed_item_ids:
95
+        :param allowed_node_types:
96
+        :return:
97
+        """
98
+        if not allowed_node_types:
99
+            allowed_node_types = [ContentType.Folder]
100
+        elif allowed_node_types==ContentType.Any:
101
+            allowed_node_types = ContentType.all()
37
 
102
 
38
         parent_id = parent.content_id if parent else None
103
         parent_id = parent.content_id if parent else None
39
         folders = self._base_query(workspace).\
104
         folders = self._base_query(workspace).\
40
             filter(Content.parent_id==parent_id).\
105
             filter(Content.parent_id==parent_id).\
41
-            filter(Content.type==ContentType.Folder).\
106
+            filter(Content.type.in_(allowed_node_types)).\
42
             filter(Content.content_id.notin_(removed_item_ids)).\
107
             filter(Content.content_id.notin_(removed_item_ids)).\
43
             all()
108
             all()
44
 
109
 
49
         result = []
114
         result = []
50
         for folder in folders:
115
         for folder in folders:
51
             for allowed_content_type in filter_by_allowed_content_types:
116
             for allowed_content_type in filter_by_allowed_content_types:
52
-                if folder.properties['allowed_content'][allowed_content_type]==True:
117
+                if folder.type==ContentType.Folder and folder.properties['allowed_content'][allowed_content_type]==True:
53
                     result.append(folder)
118
                     result.append(folder)
54
 
119
 
55
         return result
120
         return result

+ 1 - 1
tracim/tracim/lib/helpers.py ファイルの表示

131
     try:
131
     try:
132
         content_data = content_str.split(CST.TREEVIEW_MENU.ID_SEPARATOR)
132
         content_data = content_str.split(CST.TREEVIEW_MENU.ID_SEPARATOR)
133
         content_id = int(content_data[1])
133
         content_id = int(content_data[1])
134
-        content = ContentApi(tg.tmpl_context.current_user).get_one(content_id, ContentType.Folder)
134
+        content = ContentApi(tg.tmpl_context.current_user).get_one(content_id, ContentType.Any)
135
     except (IndexError, ValueError) as e:
135
     except (IndexError, ValueError) as e:
136
         content = None
136
         content = None
137
 
137
 

+ 0 - 1
tracim/tracim/lib/workspace.py ファイルの表示

86
     def get_notifiable_roles(self, workspace: Workspace) -> [UserRoleInWorkspace]:
86
     def get_notifiable_roles(self, workspace: Workspace) -> [UserRoleInWorkspace]:
87
         roles = []
87
         roles = []
88
         for role in workspace.roles:
88
         for role in workspace.roles:
89
-            print(role.user.email)
90
             if role.do_notify==True and role.user!=self._user:
89
             if role.do_notify==True and role.user!=self._user:
91
                 roles.append(role)
90
                 roles.append(role)
92
         return roles
91
         return roles

+ 39 - 1
tracim/tracim/model/data.py ファイルの表示

56
                 return role.role
56
                 return role.role
57
         return UserRoleInWorkspace.NOT_APPLICABLE
57
         return UserRoleInWorkspace.NOT_APPLICABLE
58
 
58
 
59
-
59
+    def get_label(self):
60
+        """ this method is for interoperability with Content class"""
61
+        return self.label
60
 
62
 
61
 class UserRoleInWorkspace(DeclarativeBase):
63
 class UserRoleInWorkspace(DeclarativeBase):
62
 
64
 
276
         'comment': 'apps/internet-group-chat',
278
         'comment': 'apps/internet-group-chat',
277
     }
279
     }
278
 
280
 
281
+    _ORDER_WEIGHT = {
282
+        'folder': 0,
283
+        'page': 1,
284
+        'thread': 2,
285
+        'file': 3,
286
+        'comment': 4,
287
+    }
288
+
279
     @classmethod
289
     @classmethod
280
     def icon(cls, type: str):
290
     def icon(cls, type: str):
281
         assert(type in ContentType._ICONS) # DYN_REMOVE
291
         assert(type in ContentType._ICONS) # DYN_REMOVE
282
         return ContentType._ICONS[type]
292
         return ContentType._ICONS[type]
283
 
293
 
284
     @classmethod
294
     @classmethod
295
+    def all(cls):
296
+        return cls.allowed_types()
297
+
298
+    @classmethod
285
     def allowed_types(cls):
299
     def allowed_types(cls):
286
         return [cls.Folder, cls.File, cls.Comment, cls.Thread, cls.Page]
300
         return [cls.Folder, cls.File, cls.Comment, cls.Thread, cls.Page]
287
 
301
 
294
                 allowed_types.append(item)
308
                 allowed_types.append(item)
295
         return allowed_types
309
         return allowed_types
296
 
310
 
311
+    @classmethod
312
+    def fill_url(cls, content: 'Content'):
313
+        # TODO - DYNDATATYPE - D.A. - 2014-12-02
314
+        # Make this code dynamic loading data types
315
+
316
+        if content.type==ContentType.Folder:
317
+            return '/workspaces/{}/folders/{}'.format(content.workspace_id, content.content_id)
318
+        elif content.type==ContentType.File:
319
+            return '/workspaces/{}/folders/{}/files/{}'.format(content.workspace_id, content.parent_id, content.content_id)
320
+        elif content.type==ContentType.Thread:
321
+            return '/workspaces/{}/folders/{}/threads/{}'.format(content.workspace_id, content.parent_id, content.content_id)
322
+        elif content.type==ContentType.Page:
323
+            return '/workspaces/{}/folders/{}/pages/{}'.format(content.workspace_id, content.parent_id, content.content_id)
324
+
325
+    @classmethod
326
+    def fill_url_for_workspace(cls, workspace: Workspace):
327
+        # TODO - DYNDATATYPE - D.A. - 2014-12-02
328
+        # Make this code dynamic loading data types
329
+        return '/workspaces/{}'.format(workspace.workspace_id)
330
+
331
+
297
 class Content(DeclarativeBase):
332
 class Content(DeclarativeBase):
298
 
333
 
299
     __tablename__ = 'contents'
334
     __tablename__ = 'contents'
379
                     child_nb = child_nb+1
414
                     child_nb = child_nb+1
380
         return child_nb
415
         return child_nb
381
 
416
 
417
+    def get_label(self):
418
+        return self.label if self.label else self.file_name if self.file_name else ''
419
+
382
     def get_status(self) -> ContentStatus:
420
     def get_status(self) -> ContentStatus:
383
         return ContentStatus(self.status, self.type.__str__())
421
         return ContentStatus(self.status, self.type.__str__())
384
 
422
 

+ 13 - 11
tracim/tracim/model/serializers.py ファイルの表示

278
     result = DictLikeClass(
278
     result = DictLikeClass(
279
         id = CST.TREEVIEW_MENU.ID_TEMPLATE__FULL.format(workspace_id, content_id),
279
         id = CST.TREEVIEW_MENU.ID_TEMPLATE__FULL.format(workspace_id, content_id),
280
         children = True, # TODO: make this dynamic
280
         children = True, # TODO: make this dynamic
281
-        text = content.label,
282
-        a_attr = { 'href' : context.url('/workspaces/{}/folders/{}'.format(workspace_id, content_id)) },
283
-        li_attr = { 'title': content.label, 'class': 'tracim-tree-item-is-a-folder' },
281
+        text = content.get_label(),
282
+        a_attr = { 'href' : context.url(ContentType.fill_url(content)) },
283
+        li_attr = { 'title': content.get_label(), 'class': 'tracim-tree-item-is-a-folder' },
284
         type = content.type,
284
         type = content.type,
285
         state = { 'opened': False, 'selected': False }
285
         state = { 'opened': False, 'selected': False }
286
     )
286
     )
770
 @pod_serializer(NodeTreeItem, CTX.MENU_API_BUILD_FROM_TREE_ITEM)
770
 @pod_serializer(NodeTreeItem, CTX.MENU_API_BUILD_FROM_TREE_ITEM)
771
 def serialize_node_tree_item_for_menu_api_tree(item: NodeTreeItem, context: Context):
771
 def serialize_node_tree_item_for_menu_api_tree(item: NodeTreeItem, context: Context):
772
     if isinstance(item.node, Content):
772
     if isinstance(item.node, Content):
773
+        ContentType.fill_url(item.node)
773
         return DictLikeClass(
774
         return DictLikeClass(
774
             id=CST.TREEVIEW_MENU.ID_TEMPLATE__FULL.format(item.node.workspace_id, item.node.content_id),
775
             id=CST.TREEVIEW_MENU.ID_TEMPLATE__FULL.format(item.node.workspace_id, item.node.content_id),
775
-            children=True if len(item.children)<=0 else context.toDict(item.children),
776
-            text=item.node.label,
777
-            a_attr={'href': context.url('/workspaces/{}/folders/{}'.format(item.node.workspace_id, item.node.content_id)) },
778
-            li_attr={'title': item.node.label, 'class': 'tracim-tree-item-is-a-folder'},
779
-            type='folder',
780
-            state={'opened': True if len(item.children)>0 else False, 'selected': item.is_selected}
776
+            children=True if ContentType.Folder==item.node.type and len(item.children)<=0 else context.toDict(item.children),
777
+            text=item.node.get_label(),
778
+            a_attr={'href': context.url(ContentType.fill_url(item.node)) },
779
+            li_attr={'title': item.node.get_label()},
780
+            # type='folder',
781
+            type=item.node.type,
782
+            state={'opened': True if ContentType.Folder==item.node.type and len(item.children)>0 else False, 'selected': item.is_selected}
781
         )
783
         )
782
     elif isinstance(item.node, Workspace):
784
     elif isinstance(item.node, Workspace):
783
         return DictLikeClass(
785
         return DictLikeClass(
784
             id=CST.TREEVIEW_MENU.ID_TEMPLATE__WORKSPACE_ONLY.format(item.node.workspace_id),
786
             id=CST.TREEVIEW_MENU.ID_TEMPLATE__WORKSPACE_ONLY.format(item.node.workspace_id),
785
             children=True if len(item.children)<=0 else context.toDict(item.children),
787
             children=True if len(item.children)<=0 else context.toDict(item.children),
786
             text=item.node.label,
788
             text=item.node.label,
787
-            a_attr={'href': context.url('/workspaces/{}'.format(item.node.workspace_id))},
788
-            li_attr={'title': item.node.label, 'class': 'tracim-tree-item-is-a-workspace'},
789
+            a_attr={'href': context.url(ContentType.fill_url_for_workspace(item.node))},
790
+            li_attr={'title': item.node.get_label()},
789
             type='workspace',
791
             type='workspace',
790
             state={'opened': True if len(item.children)>0 else False, 'selected': item.is_selected}
792
             state={'opened': True if len(item.children)>0 else False, 'selected': item.is_selected}
791
         )
793
         )

+ 1 - 1
tracim/tracim/templates/user_workspace_folder_file_get_one.mak ファイルの表示

8
 
8
 
9
 <%def name="SIDEBAR_LEFT_CONTENT()">
9
 <%def name="SIDEBAR_LEFT_CONTENT()">
10
     <h4>${_('Workspaces')}</h4>
10
     <h4>${_('Workspaces')}</h4>
11
-    ${WIDGETS.TREEVIEW('sidebar-left-menu', 'workspace_{}__folder_{}'.format(result.file.workspace.id, result.file.parent.id))}
11
+    ${WIDGETS.TREEVIEW('sidebar-left-menu', 'workspace_{}__item_{}'.format(result.file.workspace.id, result.file.id))}
12
     <hr/>
12
     <hr/>
13
 </%def>
13
 </%def>
14
 
14
 

+ 1 - 1
tracim/tracim/templates/user_workspace_folder_get_one.mak ファイルの表示

9
 
9
 
10
 <%def name="SIDEBAR_LEFT_CONTENT()">
10
 <%def name="SIDEBAR_LEFT_CONTENT()">
11
     <h4>${_('Workspaces')}</h4>
11
     <h4>${_('Workspaces')}</h4>
12
-    ${WIDGETS.TREEVIEW('sidebar-left-menu', 'workspace_{}__folder_{}'.format(result.folder.workspace.id, result.folder.id))}
12
+    ${WIDGETS.TREEVIEW('sidebar-left-menu', 'workspace_{}__item_{}'.format(result.folder.workspace.id, result.folder.id))}
13
     <hr/>
13
     <hr/>
14
 </%def>
14
 </%def>
15
 
15
 

+ 1 - 1
tracim/tracim/templates/user_workspace_folder_page_get_one.mak ファイルの表示

9
 
9
 
10
 <%def name="SIDEBAR_LEFT_CONTENT()">
10
 <%def name="SIDEBAR_LEFT_CONTENT()">
11
     <h4>${_('Workspaces')}</h4>
11
     <h4>${_('Workspaces')}</h4>
12
-    ${WIDGETS.TREEVIEW('sidebar-left-menu', 'workspace_{}__folder_{}'.format(result.page.workspace.id, result.page.parent.id))}
12
+    ${WIDGETS.TREEVIEW('sidebar-left-menu', 'workspace_{}__item_{}'.format(result.page.workspace.id, result.page.id))}
13
     <hr/>
13
     <hr/>
14
 </%def>
14
 </%def>
15
 
15
 

+ 2 - 1
tracim/tracim/templates/user_workspace_folder_thread_get_one.mak ファイルの表示

9
 
9
 
10
 <%def name="SIDEBAR_LEFT_CONTENT()">
10
 <%def name="SIDEBAR_LEFT_CONTENT()">
11
     <h4>${_('Workspaces')}</h4>
11
     <h4>${_('Workspaces')}</h4>
12
-    ${WIDGETS.TREEVIEW('sidebar-left-menu', 'workspace_{}__folder_{}'.format(result.thread.workspace.id, result.thread.parent.id))}
12
+    ${WIDGETS.TREEVIEW('sidebar-left-menu', 'workspace_{}__item_{}'.format(result.thread.workspace.id, result.thread.id))}
13
     <hr/>
13
     <hr/>
14
 </%def>
14
 </%def>
15
 
15
 
19
 
19
 
20
 <%def name="REQUIRED_DIALOGS()">
20
 <%def name="REQUIRED_DIALOGS()">
21
     ${TIM.MODAL_DIALOG('thread-edit-modal-dialog', 'modal-lg')}
21
     ${TIM.MODAL_DIALOG('thread-edit-modal-dialog', 'modal-lg')}
22
+    ${TIM.MODAL_DIALOG('thread-move-modal-dialog')}
22
 </%def>
23
 </%def>
23
 
24
 
24
 ############################################################################
25
 ############################################################################

+ 10 - 1
tracim/tracim/templates/user_workspace_widgets.mak ファイルの表示

142
                         "default" : {
142
                         "default" : {
143
                             "icon" : "${TIM.ICO_URL(16, 'places/jstree-folder')}"
143
                             "icon" : "${TIM.ICO_URL(16, 'places/jstree-folder')}"
144
                         },
144
                         },
145
+                        "page" : {
146
+                            "icon" : "${TIM.ICO_URL(16, 'mimetypes/text-html')}"
147
+                        },
148
+                        "file" : {
149
+                            "icon" : "${TIM.ICO_URL(16, 'status/mail-attachment')}"
150
+                        },
151
+                        "thread" : {
152
+                            "icon" : "${TIM.ICO_URL(16, 'apps/internet-group-chat')}"
153
+                        },
145
                         "workspace" : {
154
                         "workspace" : {
146
                             "icon" : "${TIM.ICO_URL(16, 'places/folder-remote')}"
155
                             "icon" : "${TIM.ICO_URL(16, 'places/folder-remote')}"
147
                         },
156
                         },
167
                                 };
176
                                 };
168
                             },
177
                             },
169
                             'success': function (new_data) {
178
                             'success': function (new_data) {
170
-                                console.log('loaded new menu data' + new_data)
179
+                                console.log('loaded new menu data' + JSON.stringify(new_data))
171
                                 return new_data;
180
                                 return new_data;
172
                             },
181
                             },
173
                         },
182
                         },