Browse Source

added app Admin Workspace User + refactor for app Fullscreen

Skylsmoi 5 years ago
parent
commit
e92507b8c0
46 changed files with 641 additions and 86 deletions
  1. 18 0
      build_full_frontend.sh
  2. 1 1
      frontend/README.md
  3. 22 5
      frontend/dist/appInterface.js
  4. 1 0
      frontend/dist/index.html
  5. 6 6
      frontend/jsonserver/static_db.json
  6. 2 1
      frontend/package.json
  7. 19 6
      frontend/src/appFactory.js
  8. 6 5
      frontend/src/component/Workspace/OpenContentApp.jsx
  9. 1 0
      frontend/src/component/Workspace/OpenCreateContentApp.jsx
  10. 6 4
      frontend/src/container/Account.jsx
  11. 47 0
      frontend/src/container/AppFullscreenManager.jsx
  12. 1 1
      frontend/src/container/Header.jsx
  13. 19 1
      frontend/src/container/Sidebar.jsx
  14. 16 3
      frontend/src/container/Tracim.jsx
  15. 15 42
      frontend/src/container/WorkspaceContent.jsx
  16. 6 1
      frontend/src/helper.js
  17. 13 0
      frontend_app_admin_workspace_user/.editorconfig
  18. 5 0
      frontend_app_admin_workspace_user/.gitignore
  19. 1 0
      frontend_app_admin_workspace_user/README.md
  20. 17 0
      frontend_app_admin_workspace_user/build_admin_workspace_user.sh
  21. 22 0
      frontend_app_admin_workspace_user/dist/index.html
  22. 14 0
      frontend_app_admin_workspace_user/i18next.scanner.js
  23. 1 0
      frontend_app_admin_workspace_user/i18next.scanner/en/translation.json
  24. 1 0
      frontend_app_admin_workspace_user/i18next.scanner/fr/translation.json
  25. 63 0
      frontend_app_admin_workspace_user/package.json
  26. 1 0
      frontend_app_admin_workspace_user/src/action.async.js
  27. 86 0
      frontend_app_admin_workspace_user/src/container/AdminWorkspaceUser.jsx
  28. 1 0
      frontend_app_admin_workspace_user/src/css/index.styl
  29. 53 0
      frontend_app_admin_workspace_user/src/helper.js
  30. 21 0
      frontend_app_admin_workspace_user/src/i18n.js
  31. 16 0
      frontend_app_admin_workspace_user/src/index.dev.js
  32. 24 0
      frontend_app_admin_workspace_user/src/index.js
  33. 87 0
      frontend_app_admin_workspace_user/webpack.config.js
  34. 1 1
      frontend_app_html-document/package.json
  35. 1 1
      frontend_app_html-document/src/container/PopupCreateHtmlDocument.jsx
  36. 1 1
      frontend_app_html-document/src/helper.js
  37. 1 1
      frontend_app_html-document/src/index.js
  38. 1 1
      frontend_app_thread/package.json
  39. 1 1
      frontend_app_thread/src/container/PopupCreateThread.jsx
  40. 1 1
      frontend_app_thread/src/helper.js
  41. 1 1
      frontend_app_thread/src/index.js
  42. 0 0
      frontend_lib/src/component/Layout/PageContent.jsx
  43. 3 2
      frontend_lib/src/component/Layout/PageTitle.jsx
  44. 0 0
      frontend_lib/src/component/Layout/PageWrapper.jsx
  45. 8 0
      frontend_lib/src/index.js
  46. 10 0
      install_frontend_dependencies.sh

+ 18 - 0
build_full_frontend.sh View File

52
 log "cp i18next.scanner/fr/translation.json ../frontend/dist/app/thread_fr_translation.json"
52
 log "cp i18next.scanner/fr/translation.json ../frontend/dist/app/thread_fr_translation.json"
53
 cp i18next.scanner/fr/translation.json ../frontend/dist/app/thread_fr_translation.json
53
 cp i18next.scanner/fr/translation.json ../frontend/dist/app/thread_fr_translation.json
54
 cd -
54
 cd -
55
+
56
+# app Admin Workspace User
57
+
58
+log "cd frontend_app_admin_workspace_user"
59
+cd frontend_app_admin_workspace_user
60
+
61
+log "npm run build$windoz # for frontend_app_thread"
62
+npm run build$windoz
63
+
64
+log "cp dist/admin_workspace_user.app.js"
65
+cp dist/admin_workspace_user.app.js ../frontend/dist/app
66
+
67
+log "cp i18next.scanner/en/translation.json ../frontend/dist/app/admin_workspace_user_en_translation.json"
68
+cp i18next.scanner/en/translation.json ../frontend/dist/app/admin_workspace_user_en_translation.json
69
+
70
+log "cp i18next.scanner/fr/translation.json ../frontend/dist/app/admin_workspace_user_fr_translation.json"
71
+cp i18next.scanner/fr/translation.json ../frontend/dist/app/admin_workspace_user_fr_translation.json
72
+cd -

+ 1 - 1
frontend/README.md View File

58
 You also need to make the mock api able to tell tracim_frontend that it handle you app :
58
 You also need to make the mock api able to tell tracim_frontend that it handle you app :
59
 - add an entry for you App in tracim_frontend/jsonserver/static_db.json in the `app_config` property
59
 - add an entry for you App in tracim_frontend/jsonserver/static_db.json in the `app_config` property
60
 - reload your mock api server
60
 - reload your mock api server
61
-- add the source of your app in tracim_frontend/dist/index.html and an entry to the switch case of the function `GLOBAL_renderAppFull`. All of this will be handled by backend later on, this is all work in progress stuffs.
61
+- add the source of your app in tracim_frontend/dist/index.html and an entry to the switch case of the function `GLOBAL_renderAppFeature`. All of this will be handled by backend later on, this is all work in progress stuffs.
62
 
62
 
63
 
63
 
64
 #### Urls list
64
 #### Urls list

+ 22 - 5
frontend/dist/appInterface.js View File

9
         return appThread
9
         return appThread
10
       case 'file':
10
       case 'file':
11
         return appFile
11
         return appFile
12
+      case 'admin_workspace_user':
13
+        return appAdminWorkspaceUser
12
       default:
14
       default:
13
         return null
15
         return null
14
     }
16
     }
19
   // use module.export and require
21
   // use module.export and require
20
   // doesn't work, cant resolve a file outside of the build dir
22
   // doesn't work, cant resolve a file outside of the build dir
21
 
23
 
22
-  GLOBAL_renderAppFull = app => {
23
-    console.log('%cGLOBAL_renderAppFull', 'color: #5cebeb', app)
24
+  GLOBAL_renderAppFeature = app => {
25
+    console.log('%cGLOBAL_renderAppFeature', 'color: #5cebeb', app)
24
 
26
 
25
     const selectedApp = getSelectedApp(app.config.slug)
27
     const selectedApp = getSelectedApp(app.config.slug)
26
 
28
 
27
     if (selectedApp.isRendered) {
29
     if (selectedApp.isRendered) {
28
-      GLOBAL_dispatchEvent({type: `${app.config.slug}_showApp`, data: app}) // handled by html-documents:src/container/HtmlDocument.jsx
30
+      GLOBAL_dispatchEvent({type: `${app.config.slug}_showApp`, data: app}) // handled by html-documents:src/container/AdminWorkspaceUser.jsx
29
     } else {
31
     } else {
30
-      selectedApp.renderAppFull(app)
32
+      selectedApp.renderAppFeature(app)
33
+      selectedApp.isRendered = true
34
+      prevSelectedApp.isRendered = false
35
+      prevSelectedApp = selectedApp
36
+    }
37
+  }
38
+
39
+  GLOBAL_renderAppFullscreen = app => {
40
+    console.log('%cGLOBAL_renderAppFullscreen', 'color: #5cebeb', app)
41
+
42
+    const selectedApp = getSelectedApp(app.config.slug)
43
+
44
+    if (selectedApp.isRendered) {
45
+      GLOBAL_dispatchEvent({type: `${app.config.slug}_showApp`, data: app}) // handled by html-documents:src/container/AdminWorkspaceUser.jsx
46
+    } else {
47
+      selectedApp.renderAppFullscreen(app)
31
       selectedApp.isRendered = true
48
       selectedApp.isRendered = true
32
       prevSelectedApp.isRendered = false
49
       prevSelectedApp.isRendered = false
33
       prevSelectedApp = selectedApp
50
       prevSelectedApp = selectedApp
64
         console.log('%cGLOBAL_eventReducer Custom Event', 'color: #28a745', type, data)
81
         console.log('%cGLOBAL_eventReducer Custom Event', 'color: #28a745', type, data)
65
         if (prevSelectedApp.name === '') return
82
         if (prevSelectedApp.name === '') return
66
 
83
 
67
-        prevSelectedApp.unmountApp('appContainer')
84
+        prevSelectedApp.unmountApp('appFeatureContainer')
68
         prevSelectedApp.unmountApp('popupCreateContentContainer')
85
         prevSelectedApp.unmountApp('popupCreateContentContainer')
69
         prevSelectedApp.isRendered = false
86
         prevSelectedApp.isRendered = false
70
         break
87
         break

+ 1 - 0
frontend/dist/index.html View File

54
     <script src='/app/html-document.app.js'></script>
54
     <script src='/app/html-document.app.js'></script>
55
     <script src='/app/thread.app.js'></script>
55
     <script src='/app/thread.app.js'></script>
56
     <!-- <script src='/app/file.app.js'></script> -->
56
     <!-- <script src='/app/file.app.js'></script> -->
57
+    <script src='/app/admin_workspace_user.app.js'></script>
57
 
58
 
58
     <script src="/dev/jquery-3.2.1.js"></script>
59
     <script src="/dev/jquery-3.2.1.js"></script>
59
     <script src="/dev/popper-1.12.3.js"></script>
60
     <script src="/dev/popper-1.12.3.js"></script>

+ 6 - 6
frontend/jsonserver/static_db.json View File

35
     "customClass": "wsContentPageHtml",
35
     "customClass": "wsContentPageHtml",
36
     "icon": "fa fa-fw fa-file-text-o",
36
     "icon": "fa fa-fw fa-file-text-o",
37
     "color": "#3f52e3",
37
     "color": "#3f52e3",
38
-    "domContainer": "appContainer"
38
+    "domContainer": "appFeatureContainer"
39
   }, {
39
   }, {
40
     "name": "PageMarkdown",
40
     "name": "PageMarkdown",
41
     "label": {
41
     "label": {
47
     "customClass": "wsContentPageMarkdown",
47
     "customClass": "wsContentPageMarkdown",
48
     "icon": "fa fa-fw fa-file-code-o",
48
     "icon": "fa fa-fw fa-file-code-o",
49
     "color": "#e0082b",
49
     "color": "#e0082b",
50
-    "domContainer": "appContainer"
50
+    "domContainer": "appFeatureContainer"
51
   }, {
51
   }, {
52
     "name": "File",
52
     "name": "File",
53
     "label": {
53
     "label": {
59
     "customClass": "wsContentFile",
59
     "customClass": "wsContentFile",
60
     "icon": "fa fa-fw fa-file-image-o",
60
     "icon": "fa fa-fw fa-file-image-o",
61
     "color": "#263462",
61
     "color": "#263462",
62
-    "domContainer": "appContainer"
62
+    "domContainer": "appFeatureContainer"
63
   }, {
63
   }, {
64
     "name": "Thread",
64
     "name": "Thread",
65
     "label": {
65
     "label": {
71
     "customClass": "wsContentThread",
71
     "customClass": "wsContentThread",
72
     "icon": "fa fa-fw fa-comments-o",
72
     "icon": "fa fa-fw fa-comments-o",
73
     "color": "#2674d3",
73
     "color": "#2674d3",
74
-    "domContainer": "appContainer"
74
+    "domContainer": "appFeatureContainer"
75
   }, {
75
   }, {
76
     "name": "Task",
76
     "name": "Task",
77
     "label": {
77
     "label": {
83
     "customClass": "wsContentTask",
83
     "customClass": "wsContentTask",
84
     "icon": "fa fa-fw fa-list-ul",
84
     "icon": "fa fa-fw fa-list-ul",
85
     "color": "#2d5a88",
85
     "color": "#2d5a88",
86
-    "domContainer": "appContainer"
86
+    "domContainer": "appFeatureContainer"
87
   }, {
87
   }, {
88
     "name": "Issue",
88
     "name": "Issue",
89
     "label": {
89
     "label": {
95
     "customClass": "wsContentIssue",
95
     "customClass": "wsContentIssue",
96
     "icon": "fa fa-fw fa-ticket",
96
     "icon": "fa fa-fw fa-ticket",
97
     "color": "#a4835e",
97
     "color": "#a4835e",
98
-    "domContainer": "appContainer"
98
+    "domContainer": "appFeatureContainer"
99
   }],
99
   }],
100
   "workspace_detail": {
100
   "workspace_detail": {
101
     "id": 1,
101
     "id": 1,

+ 2 - 1
frontend/package.json View File

63
       "fetch",
63
       "fetch",
64
       "btoa",
64
       "btoa",
65
       "history",
65
       "history",
66
-      "GLOBAL_renderAppFull",
66
+      "GLOBAL_renderAppFeature",
67
+      "GLOBAL_renderAppFullscreen",
67
       "GLOBAL_renderAppPopupCreation",
68
       "GLOBAL_renderAppPopupCreation",
68
       "GLOBAL_dispatchEvent",
69
       "GLOBAL_dispatchEvent",
69
       "GLOBAL_hideApp"
70
       "GLOBAL_hideApp"

+ 19 - 6
frontend/src/appFactory.js View File

4
 
4
 
5
 export function appFactory (WrappedComponent) {
5
 export function appFactory (WrappedComponent) {
6
   return class AppFactory extends React.Component {
6
   return class AppFactory extends React.Component {
7
-    renderAppFull = (appConfig, user, content) => GLOBAL_renderAppFull({
7
+    renderAppFeature = (appConfig, user, content) => GLOBAL_renderAppFeature({
8
       loggedUser: user.logged ? user : {},
8
       loggedUser: user.logged ? user : {},
9
       config: {
9
       config: {
10
         ...appConfig,
10
         ...appConfig,
11
-        domContainer: 'appContainer',
11
+        domContainer: 'appFeatureContainer',
12
+        apiUrl: FETCH_CONFIG.apiUrl,
13
+        mockApiUrl: FETCH_CONFIG.mockApiUrl, // Côme - 2018/07/31 - this should not be used, I deprecate it
14
+        apiHeader: FETCH_CONFIG.headers,
15
+        translation: i18n.store.data
16
+      },
17
+      content
18
+    })
19
+
20
+    renderAppFullscreen = (appConfig, user, content) => GLOBAL_renderAppFullscreen({
21
+      loggedUser: user.logged ? user : {},
22
+      config: {
23
+        ...appConfig,
24
+        domContainer: 'appFullscreenContainer',
12
         apiUrl: FETCH_CONFIG.apiUrl,
25
         apiUrl: FETCH_CONFIG.apiUrl,
13
-        mockApiUrl: FETCH_CONFIG.mockApiUrl,
14
         apiHeader: FETCH_CONFIG.headers,
26
         apiHeader: FETCH_CONFIG.headers,
15
         translation: i18n.store.data
27
         translation: i18n.store.data
16
       },
28
       },
31
       idFolder: idFolder === 'null' ? null : idFolder
43
       idFolder: idFolder === 'null' ? null : idFolder
32
     })
44
     })
33
 
45
 
34
-    emitEventApp = (type, data) => GLOBAL_dispatchEvent({ type, data })
46
+    dispatchCustomEvent = (type, data) => GLOBAL_dispatchEvent({ type, data })
35
 
47
 
36
     render () {
48
     render () {
37
       return (
49
       return (
38
         <WrappedComponent
50
         <WrappedComponent
39
           {...this.props}
51
           {...this.props}
40
-          renderAppFull={this.renderAppFull}
52
+          renderAppFeature={this.renderAppFeature}
53
+          renderAppFullscreen={this.renderAppFullscreen}
41
           renderAppPopupCreation={this.renderAppPopupCreation}
54
           renderAppPopupCreation={this.renderAppPopupCreation}
42
-          emitEventApp={this.emitEventApp}
55
+          dispatchCustomEvent={this.dispatchCustomEvent}
43
           // hideApp={this.hideApp}
56
           // hideApp={this.hideApp}
44
         />
57
         />
45
       )
58
       )

+ 6 - 5
frontend/src/component/Workspace/OpenContentApp.jsx View File

3
 import { withRouter } from 'react-router'
3
 import { withRouter } from 'react-router'
4
 import appFactory from '../../appFactory.js'
4
 import appFactory from '../../appFactory.js'
5
 
5
 
6
+// @FIXME Côme - 2018/07/31 - should this be in a component like AppFeatureManager ?
6
 export class OpenContentApp extends React.Component {
7
 export class OpenContentApp extends React.Component {
7
   openContentApp = () => {
8
   openContentApp = () => {
8
-    const { idWorkspace, appOpenedType, user, workspaceContent, contentType, renderAppFull, match } = this.props
9
+    const { idWorkspace, appOpenedType, user, workspaceContent, contentType, renderAppFeature, dispatchCustomEvent, match } = this.props
9
 
10
 
10
     if (isNaN(idWorkspace) || idWorkspace === -1) return
11
     if (isNaN(idWorkspace) || idWorkspace === -1) return
11
 
12
 
21
       console.log('%c<OpenContentApp> contentToOpen', 'color: #dcae84', contentToOpen)
22
       console.log('%c<OpenContentApp> contentToOpen', 'color: #dcae84', contentToOpen)
22
 
23
 
23
       if (appOpenedType === contentToOpen.type) { // app already open
24
       if (appOpenedType === contentToOpen.type) { // app already open
24
-        GLOBAL_dispatchEvent({
25
-          type: `${contentToOpen.type}_reloadContent`, // handled by html-document:src/container/HtmlDocument.jsx
25
+        dispatchCustomEvent({
26
+          type: `${contentToOpen.type}_reloadContent`, // handled by html-document:src/container/AdminWorkspaceUser.jsx
26
           data: contentToOpen
27
           data: contentToOpen
27
         })
28
         })
28
       } else { // open another app
29
       } else { // open another app
29
         // if another app is already visible, hide it
30
         // if another app is already visible, hide it
30
-        if (appOpenedType !== false) GLOBAL_dispatchEvent({type: `${appOpenedType}_hideApp`})
31
+        if (appOpenedType !== false) dispatchCustomEvent({type: `${appOpenedType}_hideApp`})
31
         // open app
32
         // open app
32
-        renderAppFull(
33
+        renderAppFeature(
33
           contentType.find(ct => ct.slug === contentToOpen.type),
34
           contentType.find(ct => ct.slug === contentToOpen.type),
34
           user,
35
           user,
35
           contentToOpen
36
           contentToOpen

+ 1 - 0
frontend/src/component/Workspace/OpenCreateContentApp.jsx View File

5
 
5
 
6
 const qs = require('query-string')
6
 const qs = require('query-string')
7
 
7
 
8
+// @FIXME Côme - 2018/07/31 - should this be in a component like AppFeatureManager ? (or AppCreateContentManager)
8
 export class OpenCreateContentApp extends React.Component {
9
 export class OpenCreateContentApp extends React.Component {
9
   openCreateContentApp = () => {
10
   openCreateContentApp = () => {
10
     const { idWorkspace, user, contentType, renderAppPopupCreation, match, location } = this.props
11
     const { idWorkspace, user, contentType, renderAppPopupCreation, match, location } = this.props

+ 6 - 4
frontend/src/container/Account.jsx View File

1
 import React from 'react'
1
 import React from 'react'
2
 import { connect } from 'react-redux'
2
 import { connect } from 'react-redux'
3
 import Sidebar from './Sidebar.jsx'
3
 import Sidebar from './Sidebar.jsx'
4
-import PageWrapper from '../component/common/layout/PageWrapper.jsx'
5
-import PageTitle from '../component/common/layout/PageTitle.jsx'
6
-import PageContent from '../component/common/layout/PageContent.jsx'
7
 import UserInfo from '../component/Account/UserInfo.jsx'
4
 import UserInfo from '../component/Account/UserInfo.jsx'
8
 import MenuSubComponent from '../component/Account/MenuSubComponent.jsx'
5
 import MenuSubComponent from '../component/Account/MenuSubComponent.jsx'
9
 import PersonalData from '../component/Account/PersonalData.jsx'
6
 import PersonalData from '../component/Account/PersonalData.jsx'
11
 import Notification from '../component/Account/Notification.jsx'
8
 import Notification from '../component/Account/Notification.jsx'
12
 import Password from '../component/Account/Password.jsx'
9
 import Password from '../component/Account/Password.jsx'
13
 import Timezone from '../component/Account/Timezone.jsx'
10
 import Timezone from '../component/Account/Timezone.jsx'
14
-import { Delimiter } from 'tracim_frontend_lib'
11
+import {
12
+  Delimiter,
13
+  PageWrapper,
14
+  PageTitle,
15
+  PageContent
16
+} from 'tracim_frontend_lib'
15
 import { updateUserWorkspaceSubscriptionNotif } from '../action-creator.sync.js'
17
 import { updateUserWorkspaceSubscriptionNotif } from '../action-creator.sync.js'
16
 import {
18
 import {
17
   getTimezone,
19
   getTimezone,

+ 47 - 0
frontend/src/container/AppFullscreenManager.jsx View File

1
+import React from 'react'
2
+import { connect } from 'react-redux'
3
+import { withRouter } from 'react-router'
4
+import { Route } from 'react-router-dom'
5
+import { PAGE } from '../helper.js'
6
+import appFactory from '../appFactory.js'
7
+import Sidebar from './Sidebar.jsx'
8
+
9
+class AppFullscreenManager extends React.Component {
10
+  constructor (props) {
11
+    super(props)
12
+    this.state = {
13
+      AmIMounted: false
14
+    }
15
+  }
16
+
17
+  componentDidMount = () => this.setState({AmIMounted: true})
18
+
19
+  render () {
20
+    const { user, renderAppFullscreen } = this.props
21
+
22
+    return (
23
+      <div className='sidebarpagecontainer'>
24
+        <Sidebar />
25
+
26
+        <div id='appFullscreenContainer' />
27
+
28
+        {this.state.AmIMounted && (// we must wait for the component to be fully mounted to be sure the div#appFullscreenContainer exists in DOM
29
+          <div className='emptyDiForRoute'>
30
+            <Route path={PAGE.ADMIN.WORKSPACE} render={() => {
31
+              renderAppFullscreen({slug: 'admin_workspace_user', hexcolor: '#7d4e24', type: 'workspace'}, user, {})
32
+              return null
33
+            }} />
34
+
35
+            <Route path={PAGE.ADMIN.USER} render={() => {
36
+              renderAppFullscreen({slug: 'admin_workspace_user', hexcolor: '#7d4e24', type: 'user'}, user, {})
37
+              return null
38
+            }} />
39
+          </div>
40
+        )}
41
+      </div>
42
+    )
43
+  }
44
+}
45
+
46
+const mapStateToProps = ({ user }) => ({ user })
47
+export default connect(mapStateToProps)(withRouter(appFactory(AppFullscreenManager)))

+ 1 - 1
frontend/src/container/Header.jsx View File

37
   handleChangeLang = idLang => {
37
   handleChangeLang = idLang => {
38
     this.props.dispatch(setUserLang(idLang))
38
     this.props.dispatch(setUserLang(idLang))
39
     i18n.changeLanguage(idLang)
39
     i18n.changeLanguage(idLang)
40
-    this.props.emitEventApp('allApp_changeLang', idLang)
40
+    this.props.dispatchCustomEvent('allApp_changeLang', idLang)
41
   }
41
   }
42
 
42
 
43
   handleClickHelp = () => {}
43
   handleClickHelp = () => {}

+ 19 - 1
frontend/src/container/Sidebar.jsx View File

6
 import WorkspaceListItem from '../component/Sidebar/WorkspaceListItem.jsx'
6
 import WorkspaceListItem from '../component/Sidebar/WorkspaceListItem.jsx'
7
 import {
7
 import {
8
   setWorkspaceListIsOpenInSidebar,
8
   setWorkspaceListIsOpenInSidebar,
9
-  updateWorkspaceFilter
9
+  updateWorkspaceFilter,
10
+  updateWorkspaceListData
10
 } from '../action-creator.sync.js'
11
 } from '../action-creator.sync.js'
12
+import {
13
+  getWorkspaceList
14
+} from '../action-creator.async.js'
11
 import { PAGE } from '../helper.js'
15
 import { PAGE } from '../helper.js'
12
 
16
 
13
 const qs = require('query-string')
17
 const qs = require('query-string')
21
     }
25
     }
22
   }
26
   }
23
 
27
 
28
+  async componentDidMount () {
29
+    const { workspaceIdInUrl } = this.state
30
+    const { user, workspaceList, dispatch } = this.props
31
+
32
+    if (user.user_id !== -1 && workspaceList.length === 0) {
33
+      const fetchGetWorkspaceList = await dispatch(getWorkspaceList(user))
34
+
35
+      if (fetchGetWorkspaceList.status === 200) {
36
+        dispatch(updateWorkspaceListData(fetchGetWorkspaceList.json))
37
+        dispatch(setWorkspaceListIsOpenInSidebar(workspaceIdInUrl || fetchGetWorkspaceList.json[0].workspace_id, true))
38
+      }
39
+    }
40
+  }
41
+
24
   componentDidUpdate (prevProps, prevState) {
42
   componentDidUpdate (prevProps, prevState) {
25
     // console.log('%c<Sidebar> Did Update', 'color: #c17838')
43
     // console.log('%c<Sidebar> Did Update', 'color: #c17838')
26
     if (this.props.match.params.idws === undefined || isNaN(this.props.match.params.idws)) return
44
     if (this.props.match.params.idws === undefined || isNaN(this.props.match.params.idws)) return

+ 16 - 3
frontend/src/container/Tracim.jsx View File

5
 import Login from './Login.jsx'
5
 import Login from './Login.jsx'
6
 import Dashboard from './Dashboard.jsx'
6
 import Dashboard from './Dashboard.jsx'
7
 import Account from './Account.jsx'
7
 import Account from './Account.jsx'
8
+import AppFullscreenManager from './AppFullscreenManager.jsx'
8
 import FlashMessage from '../component/FlashMessage.jsx'
9
 import FlashMessage from '../component/FlashMessage.jsx'
9
 import WorkspaceContent from './WorkspaceContent.jsx'
10
 import WorkspaceContent from './WorkspaceContent.jsx'
10
 import WIPcomponent from './WIPcomponent.jsx'
11
 import WIPcomponent from './WIPcomponent.jsx'
14
 import PrivateRoute from './PrivateRoute.jsx'
15
 import PrivateRoute from './PrivateRoute.jsx'
15
 import { COOKIE, PAGE } from '../helper.js'
16
 import { COOKIE, PAGE } from '../helper.js'
16
 import {
17
 import {
18
+  getAppList,
17
   getUserIsConnected
19
   getUserIsConnected
18
 } from '../action-creator.async.js'
20
 } from '../action-creator.async.js'
19
 import {
21
 import {
20
   removeFlashMessage,
22
   removeFlashMessage,
23
+  setAppList,
21
   setUserConnected
24
   setUserConnected
22
 } from '../action-creator.sync.js'
25
 } from '../action-creator.sync.js'
23
 import Cookies from 'js-cookie'
26
 import Cookies from 'js-cookie'
34
     const fetchGetUserIsConnected = await dispatch(getUserIsConnected(userFromCookies))
37
     const fetchGetUserIsConnected = await dispatch(getUserIsConnected(userFromCookies))
35
     switch (fetchGetUserIsConnected.status) {
38
     switch (fetchGetUserIsConnected.status) {
36
       case 200:
39
       case 200:
37
-        dispatch(setUserConnected({
40
+        const userLogged = {
38
           ...fetchGetUserIsConnected.json,
41
           ...fetchGetUserIsConnected.json,
39
           auth: userFromCookies.auth,
42
           auth: userFromCookies.auth,
40
           logged: true
43
           logged: true
41
-        }))
44
+        }
45
+
46
+        dispatch(setUserConnected(userLogged))
47
+
48
+        const fetchGetAppList = await dispatch(getAppList(userLogged))
49
+        if (fetchGetAppList.status === 200) dispatch(setAppList(fetchGetAppList.json))
42
         break
50
         break
51
+
43
       case 401:
52
       case 401:
44
         dispatch(setUserConnected({logged: false})); break
53
         dispatch(setUserConnected({logged: false})); break
54
+
45
       default:
55
       default:
46
         dispatch(setUserConnected({logged: null})); break
56
         dispatch(setUserConnected({logged: null})); break
47
     }
57
     }
69
           </Switch>
79
           </Switch>
70
 
80
 
71
           <PrivateRoute path={PAGE.ACCOUNT} component={Account} />
81
           <PrivateRoute path={PAGE.ACCOUNT} component={Account} />
82
+          <PrivateRoute path={PAGE.ADMIN.ROOT} component={AppFullscreenManager} />
72
           <PrivateRoute path={'/wip/:cp'} component={WIPcomponent} /> {/* for testing purpose only */}
83
           <PrivateRoute path={'/wip/:cp'} component={WIPcomponent} /> {/* for testing purpose only */}
84
+
85
+          <div id='appFeatureContainer' />
73
         </div>
86
         </div>
74
 
87
 
75
       </div>
88
       </div>
77
   }
90
   }
78
 }
91
 }
79
 
92
 
80
-const mapStateToProps = ({ flashMessage, user }) => ({ flashMessage, user })
93
+const mapStateToProps = ({ flashMessage }) => ({ flashMessage })
81
 export default withRouter(connect(mapStateToProps)(translate()(Tracim)))
94
 export default withRouter(connect(mapStateToProps)(translate()(Tracim)))

+ 15 - 42
frontend/src/container/WorkspaceContent.jsx View File

7
 import Folder from '../component/Workspace/Folder.jsx'
7
 import Folder from '../component/Workspace/Folder.jsx'
8
 import ContentItem from '../component/Workspace/ContentItem.jsx'
8
 import ContentItem from '../component/Workspace/ContentItem.jsx'
9
 import ContentItemHeader from '../component/Workspace/ContentItemHeader.jsx'
9
 import ContentItemHeader from '../component/Workspace/ContentItemHeader.jsx'
10
-import PageWrapper from '../component/common/layout/PageWrapper.jsx'
11
-import PageTitle from '../component/common/layout/PageTitle.jsx'
12
-import PageContent from '../component/common/layout/PageContent.jsx'
13
 import DropdownCreateButton from '../component/common/Input/DropdownCreateButton.jsx'
10
 import DropdownCreateButton from '../component/common/Input/DropdownCreateButton.jsx'
14
 import OpenContentApp from '../component/Workspace/OpenContentApp.jsx'
11
 import OpenContentApp from '../component/Workspace/OpenContentApp.jsx'
15
 import OpenCreateContentApp from '../component/Workspace/OpenCreateContentApp.jsx'
12
 import OpenCreateContentApp from '../component/Workspace/OpenCreateContentApp.jsx'
16
 import {
13
 import {
17
-  getAppList,
14
+  PageWrapper,
15
+  PageTitle,
16
+  PageContent
17
+} from 'tracim_frontend_lib'
18
+import {
18
   getContentTypeList,
19
   getContentTypeList,
19
   getWorkspaceContentList,
20
   getWorkspaceContentList,
20
-  getFolderContent,
21
-  getWorkspaceList
21
+  getFolderContent
22
 } from '../action-creator.async.js'
22
 } from '../action-creator.async.js'
23
 import {
23
 import {
24
   newFlashMessage,
24
   newFlashMessage,
25
-  setAppList,
26
   setContentTypeList,
25
   setContentTypeList,
27
-  setWorkspaceContent,
28
-  setWorkspaceListIsOpenInSidebar,
29
-  updateWorkspaceListData
26
+  setWorkspaceContent
30
 } from '../action-creator.sync.js'
27
 } from '../action-creator.sync.js'
31
 
28
 
32
 const qs = require('query-string')
29
 const qs = require('query-string')
35
   constructor (props) {
32
   constructor (props) {
36
     super(props)
33
     super(props)
37
     this.state = {
34
     this.state = {
38
-      popupCreateContent: {
39
-        display: false,
40
-        type: undefined,
41
-        folder: undefined
42
-      },
43
       workspaceIdInUrl: props.match.params.idws ? parseInt(props.match.params.idws) : null, // this is used to avoid handling the parseInt every time
35
       workspaceIdInUrl: props.match.params.idws ? parseInt(props.match.params.idws) : null, // this is used to avoid handling the parseInt every time
44
       appOpenedType: false
36
       appOpenedType: false
45
     }
37
     }
69
   }
61
   }
70
 
62
 
71
   async componentDidMount () {
63
   async componentDidMount () {
72
-    const { workspaceIdInUrl } = this.state
73
-    const { user, workspaceList, app, contentType, match, dispatch } = this.props
64
+    const { user, workspaceList, contentType, match, dispatch } = this.props
74
 
65
 
75
     console.log('%c<WorkspaceContent> componentDidMount', 'color: #c17838')
66
     console.log('%c<WorkspaceContent> componentDidMount', 'color: #c17838')
76
 
67
 
77
-    if (app.length === 0) { // @fixme shouldn't this be done by <Sidebar> ?
78
-      const fetchGetAppList = await dispatch(getAppList(user))
79
-      if (fetchGetAppList.status === 200) dispatch(setAppList(fetchGetAppList.json))
80
-    }
81
-
82
     if (contentType.length === 0) {
68
     if (contentType.length === 0) {
83
       const fetchGetContentTypeList = await dispatch(getContentTypeList(user))
69
       const fetchGetContentTypeList = await dispatch(getContentTypeList(user))
84
       if (fetchGetContentTypeList.status === 200) dispatch(setContentTypeList(fetchGetContentTypeList.json))
70
       if (fetchGetContentTypeList.status === 200) dispatch(setContentTypeList(fetchGetContentTypeList.json))
85
     }
71
     }
86
 
72
 
87
     let wsToLoad = null
73
     let wsToLoad = null
88
-    if (match.params.idws !== undefined) wsToLoad = match.params.idws
89
 
74
 
90
-    if (user.user_id !== -1 && workspaceList.length === 0) {
91
-      const fetchGetWorkspaceList = await dispatch(getWorkspaceList(user))
92
-
93
-      if (fetchGetWorkspaceList.status === 200) {
94
-        dispatch(updateWorkspaceListData(fetchGetWorkspaceList.json))
95
-        dispatch(setWorkspaceListIsOpenInSidebar(workspaceIdInUrl || fetchGetWorkspaceList.json[0].workspace_id, true))
96
-
97
-        if (match.params.idws === undefined && fetchGetWorkspaceList.json.length > 0) {
98
-          wsToLoad = fetchGetWorkspaceList.json[0].workspace_id // load first ws if none specified
99
-        }
100
-      }
101
-    }
102
-
103
-    if (wsToLoad === null) return // ws already loaded
75
+    if (match.params.idws === undefined) {
76
+      if (workspaceList.length > 0) wsToLoad = workspaceList[0].id
77
+      else return
78
+    } else wsToLoad = match.params.idws
104
 
79
 
105
     this.loadContentList(wsToLoad)
80
     this.loadContentList(wsToLoad)
106
   }
81
   }
111
     if (this.state.workspaceIdInUrl === null) return
86
     if (this.state.workspaceIdInUrl === null) return
112
 
87
 
113
     const idWorkspace = parseInt(this.props.match.params.idws)
88
     const idWorkspace = parseInt(this.props.match.params.idws)
114
-
115
     if (isNaN(idWorkspace)) return
89
     if (isNaN(idWorkspace)) return
116
 
90
 
117
     const prevFilter = qs.parse(prevProps.location.search).type
91
     const prevFilter = qs.parse(prevProps.location.search).type
126
   }
100
   }
127
 
101
 
128
   componentWillUnmount () {
102
   componentWillUnmount () {
129
-    this.props.emitEventApp('unmount_app')
103
+    this.props.dispatchCustomEvent('unmount_app')
130
     document.removeEventListener('appCustomEvent', this.customEventReducer)
104
     document.removeEventListener('appCustomEvent', this.customEventReducer)
131
   }
105
   }
132
 
106
 
221
           <PageTitle
195
           <PageTitle
222
             parentClass='workspace__header'
196
             parentClass='workspace__header'
223
             customClass='justify-content-between'
197
             customClass='justify-content-between'
224
-            title={workspaceContent.label ? workspaceContent.label : ''}
198
+            title='Liste des Contenus'
199
+            subtitle={workspaceContent.label ? workspaceContent.label : ''}
225
           >
200
           >
226
             <DropdownCreateButton
201
             <DropdownCreateButton
227
               parentClass='workspace__header__btnaddworkspace'
202
               parentClass='workspace__header__btnaddworkspace'
285
               onClickCreateContent={this.handleClickCreateContent}
260
               onClickCreateContent={this.handleClickCreateContent}
286
               availableApp={contentType}
261
               availableApp={contentType}
287
             />
262
             />
288
-
289
-            <div id='appContainer' />
290
           </PageContent>
263
           </PageContent>
291
 
264
 
292
         </PageWrapper>
265
         </PageWrapper>

+ 6 - 1
frontend/src/helper.js View File

26
     ADMIN: (idws = ':idws') => `/workspaces/${idws}/admin`
26
     ADMIN: (idws = ':idws') => `/workspaces/${idws}/admin`
27
   },
27
   },
28
   LOGIN: '/login',
28
   LOGIN: '/login',
29
-  ACCOUNT: '/account'
29
+  ACCOUNT: '/account',
30
+  ADMIN: {
31
+    ROOT: '/admin',
32
+    WORKSPACE: '/admin/workspace',
33
+    USEr: '/admin/user'
34
+  }
30
 }
35
 }
31
 
36
 
32
 export const ROLE = [{
37
 export const ROLE = [{

+ 13 - 0
frontend_app_admin_workspace_user/.editorconfig View File

1
+# doc here : https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties
2
+root = true
3
+
4
+[*]
5
+indent_style = space
6
+indent_size = 2
7
+end_of_line = lf
8
+charset = utf-8
9
+insert_final_newline = true
10
+trim_trailing_whitespace = true
11
+
12
+[*.py]
13
+indent_size = 4

+ 5 - 0
frontend_app_admin_workspace_user/.gitignore View File

1
+# Created by .ignore support plugin (hsz.mobi)
2
+.idea/
3
+.git/
4
+dist/admin_workspace_user.app.js
5
+node_modules/

+ 1 - 0
frontend_app_admin_workspace_user/README.md View File

1
+# app Admin Workspace User

+ 17 - 0
frontend_app_admin_workspace_user/build_admin_workspace_user.sh View File

1
+#!/bin/bash
2
+
3
+. ../bash_library.sh # source bash_library.sh
4
+
5
+windoz=""
6
+if [[ $1 = "-w" ]]; then
7
+    windoz="windoz"
8
+fi
9
+
10
+log "npm run build$windoz"
11
+npm run build$windoz
12
+log "cp dist/admin_workspace_user.app.js ../frontend/dist/app"
13
+cp dist/admin_workspace_user.app.js ../frontend/dist/app
14
+log "cp i18next.scanner/en/translation.json ../frontend/dist/app/admin_workspace_user_en_translation.json"
15
+cp i18next.scanner/en/translation.json ../frontend/dist/app/admin_workspace_user_en_translation.json
16
+log "cp i18next.scanner/fr/translation.json ../frontend/dist/app/admin_workspace_user_fr_translation.json"
17
+cp i18next.scanner/fr/translation.json ../frontend/dist/app/admin_workspace_user_fr_translation.json

+ 22 - 0
frontend_app_admin_workspace_user/dist/index.html View File

1
+<!DOCTYPE html>
2
+<html>
3
+<head>
4
+  <meta charset='utf-8' />
5
+  <meta name="viewport" content="width=device-width, user-scalable=no" />
6
+  <title>Html-document App Tracim</title>
7
+  <link rel='shortcut icon' href='favicon.ico'>
8
+
9
+  <link rel="stylesheet" type="text/css" href="./font/font-awesome-4.7.0/css/font-awesome.css">
10
+  <link href="https://fonts.googleapis.com/css?family=Quicksand:300,400,500,700" rel="stylesheet">
11
+  <link rel="stylesheet" type="text/css" href="./dev/bootstrap-4.0.0-beta.css">
12
+</head>
13
+<body>
14
+  <script src="./dev/jquery-3.2.1.js"></script>
15
+  <script src="./dev/popper-1.12.3.js"></script>
16
+  <script src="./dev/bootstrap-4.0.0-beta.2.js"></script>
17
+
18
+  <div id='content'></div>
19
+
20
+  <script src='./admin_workspace_user.app.dev.js'></script>
21
+</body>
22
+</html>

+ 14 - 0
frontend_app_admin_workspace_user/i18next.scanner.js View File

1
+const scanner = require('i18next-scanner')
2
+const vfs = require('vinyl-fs')
3
+
4
+const option = require('../i18next.option.js')
5
+
6
+// --------------------
7
+// 2018/07/27 - currently, last version is 2.6.5 but a bug is spaming log with errors. So I'm using 2.6.1
8
+// this issue seems related : https://github.com/i18next/i18next-scanner/issues/88
9
+// --------------------
10
+
11
+vfs.src(['./src/**/*.jsx'])
12
+// .pipe(sort()) // Sort files in stream by path
13
+  .pipe(scanner(option))
14
+  .pipe(vfs.dest('./i18next.scanner'))

+ 1 - 0
frontend_app_admin_workspace_user/i18next.scanner/en/translation.json View File

1
+{}

+ 1 - 0
frontend_app_admin_workspace_user/i18next.scanner/fr/translation.json View File

1
+{}

+ 63 - 0
frontend_app_admin_workspace_user/package.json View File

1
+{
2
+  "name": "tracim_app_admin_workspace_user",
3
+  "version": "1.1.2",
4
+  "description": "",
5
+  "main": "index.js",
6
+  "scripts": {
7
+    "servdev": "NODE_ENV=development webpack-dev-server --watch --colors --inline --hot --progress",
8
+    "servdevwindoz": "set NODE_ENV=development&& webpack-dev-server --watch --colors --inline --hot --progress",
9
+    "servdev-dashboard": "NODE_ENV=development webpack-dashboard -m -p 9873 -- webpack-dev-server --watch --colors --inline --hot --progress",
10
+    "build": "NODE_ENV=production webpack -p",
11
+    "build-translation": "node i18next.scanner.js",
12
+    "buildwindoz": "set NODE_ENV=production&& webpack -p",
13
+    "test": "echo \"Error: no test specified\" && exit 1"
14
+  },
15
+  "author": "",
16
+  "license": "ISC",
17
+  "dependencies": {
18
+    "babel-core": "^6.26.0",
19
+    "babel-eslint": "^8.2.1",
20
+    "babel-loader": "^7.1.2",
21
+    "babel-plugin-transform-class-properties": "^6.24.1",
22
+    "babel-plugin-transform-object-assign": "^6.22.0",
23
+    "babel-plugin-transform-object-rest-spread": "^6.26.0",
24
+    "babel-polyfill": "^6.26.0",
25
+    "babel-preset-env": "^1.6.1",
26
+    "babel-preset-react": "^6.24.1",
27
+    "classnames": "^2.2.5",
28
+    "css-loader": "^0.28.7",
29
+    "file-loader": "^1.1.5",
30
+    "i18next": "^10.5.0",
31
+    "prop-types": "^15.6.0",
32
+    "react": "^16.0.0",
33
+    "react-dom": "^16.0.0",
34
+    "react-i18next": "^7.5.0",
35
+    "standard": "^11.0.0",
36
+    "standard-loader": "^6.0.1",
37
+    "style-loader": "^0.19.0",
38
+    "stylus": "^0.54.5",
39
+    "stylus-loader": "^3.0.1",
40
+    "url-loader": "^0.6.2",
41
+    "webpack": "^3.8.1",
42
+    "whatwg-fetch": "^2.0.3"
43
+  },
44
+  "devDependencies": {
45
+    "i18next-scanner": "^2.6.1",
46
+    "webpack-dashboard": "^1.1.1",
47
+    "webpack-dev-server": "^2.9.2"
48
+  },
49
+  "standard": {
50
+    "globals": [
51
+      "fetch",
52
+      "history",
53
+      "btoa",
54
+      "wysiwyg",
55
+      "tinymce",
56
+      "GLOBAL_renderAppFeature",
57
+      "GLOBAL_unmountApp",
58
+      "GLOBAL_dispatchEvent"
59
+    ],
60
+    "parser": "babel-eslint",
61
+    "ignore": []
62
+  }
63
+}

+ 1 - 0
frontend_app_admin_workspace_user/src/action.async.js View File

1
+// import { FETCH_CONFIG } from './helper.js'

+ 86 - 0
frontend_app_admin_workspace_user/src/container/AdminWorkspaceUser.jsx View File

1
+import React from 'react'
2
+import { translate } from 'react-i18next'
3
+import i18n from '../i18n.js'
4
+import {
5
+  addAllResourceI18n,
6
+  // handleFetchResult,
7
+  PageWrapper,
8
+  PageTitle,
9
+  PageContent
10
+} from 'tracim_frontend_lib'
11
+import { debug } from '../helper.js'
12
+import {
13
+} from '../action.async.js'
14
+
15
+class AdminWorkspaceUser extends React.Component {
16
+  constructor (props) {
17
+    super(props)
18
+    this.state = {
19
+      appName: 'admin_workspace_user',
20
+      isVisible: true,
21
+      config: props.data ? props.data.config : debug.config,
22
+      loggedUser: props.data ? props.data.loggedUser : debug.loggedUser,
23
+      content: props.data ? props.data.content : debug.content
24
+    }
25
+
26
+    // i18n has been init, add resources from frontend
27
+    addAllResourceI18n(i18n, this.state.config.translation)
28
+    i18n.changeLanguage(this.state.loggedUser.lang)
29
+
30
+    document.addEventListener('appCustomEvent', this.customEventReducer)
31
+  }
32
+
33
+  customEventReducer = ({ detail: { type, data } }) => { // action: { type: '', data: {} }
34
+    switch (type) {
35
+      // console.log('%c<AdminWorkspaceUser> Custom event', 'color: #28a745', type, data)
36
+      default:
37
+        break
38
+    }
39
+  }
40
+
41
+  componentDidMount () {
42
+    console.log('%c<AdminWorkspaceUser> did mount', `color: ${this.state.config.hexcolor}`)
43
+
44
+    this.loadContent()
45
+  }
46
+
47
+  componentDidUpdate (prevProps, prevState) {
48
+    const { state } = this
49
+
50
+    console.log('%c<AdminWorkspaceUser> did update', `color: ${this.state.config.hexcolor}`, prevState, state)
51
+  }
52
+
53
+  componentWillUnmount () {
54
+    console.log('%c<AdminWorkspaceUser> will Unmount', `color: ${this.state.config.hexcolor}`)
55
+    document.removeEventListener('appCustomEvent', this.customEventReducer)
56
+  }
57
+
58
+  loadContent = () => {
59
+    return null
60
+  }
61
+
62
+  render () {
63
+    const { isVisible } = this.state
64
+    // const { t } = this.props
65
+
66
+    if (!isVisible) return null
67
+
68
+    return (
69
+      <div>
70
+        <PageWrapper customeClass='admin'>
71
+          <PageTitle
72
+            parentClass='admin__header'
73
+            customClass='justify-content-between'
74
+            title={'Admin'}
75
+          />
76
+
77
+          <PageContent parentClass='workspace__content'>
78
+            woot { this.state.config.type }
79
+          </PageContent>
80
+        </PageWrapper>
81
+      </div>
82
+    )
83
+  }
84
+}
85
+
86
+export default translate()(AdminWorkspaceUser)

+ 1 - 0
frontend_app_admin_workspace_user/src/css/index.styl View File

1
+@import "../../node_modules/tracim_frontend_lib/src/css/Variable.styl"

+ 53 - 0
frontend_app_admin_workspace_user/src/helper.js View File

1
+export const FETCH_CONFIG = {
2
+  headers: {
3
+    'Accept': 'application/json',
4
+    'Content-Type': 'application/json'
5
+  }
6
+}
7
+
8
+export const debug = {
9
+  config: {
10
+    label: 'Admin workspace user',
11
+    slug: 'admin_workspace_user',
12
+    faIcon: 'file-text-o',
13
+    hexcolor: '#7d4e24',
14
+    type: 'workspace'
15
+  },
16
+  loggedUser: { // @FIXME this object is outdated
17
+    user_id: 5,
18
+    username: 'Smoi',
19
+    firstname: 'Côme',
20
+    lastname: 'Stoilenom',
21
+    email: 'osef@algoo.fr',
22
+    lang: 'en',
23
+    avatar_url: 'https://avatars3.githubusercontent.com/u/11177014?s=460&v=4',
24
+    auth: btoa(`${'admin@admin.admin'}:${'admin@admin.admin'}`)
25
+  },
26
+  content: {
27
+    author: {
28
+      avatar_url: null,
29
+      public_name: 'Global manager',
30
+      user_id: 1 // -1 or 1 for debug
31
+    },
32
+    content_id: 22, // 1 or 22 for debug
33
+    content_type: 'html-document',
34
+    created: '2018-06-18T14:59:26Z',
35
+    current_revision_id: 11,
36
+    is_archived: false,
37
+    is_deleted: false,
38
+    label: 'Current Menu',
39
+    last_modifier: {
40
+      avatar_url: null,
41
+      public_name: 'Global manager',
42
+      user_id: 1
43
+    },
44
+    modified: '2018-06-18T14:59:26Z',
45
+    parent_id: 2,
46
+    raw_content: '<div>bonjour, je suis un lapin.</div>',
47
+    show_in_ui: true,
48
+    slug: 'current-menu',
49
+    status: 'open',
50
+    sub_content_types: ['thread', 'html-document', 'file', 'folder'],
51
+    workspace_id: 1
52
+  }
53
+}

+ 21 - 0
frontend_app_admin_workspace_user/src/i18n.js View File

1
+import i18n from 'i18next'
2
+import { reactI18nextModule } from 'react-i18next'
3
+
4
+i18n
5
+  .use(reactI18nextModule)
6
+  .init({
7
+    fallbackLng: 'fr',
8
+    // have a common namespace used around the full app
9
+    ns: ['translation'], // namespace
10
+    defaultNS: 'translation',
11
+    debug: true,
12
+    // interpolation: {
13
+    //   escapeValue: false, // not needed for react!!
14
+    // },
15
+    react: {
16
+      wait: true
17
+    },
18
+    resources: {} // init with empty resources, they will come from frontend in app constructor
19
+  })
20
+
21
+export default i18n

+ 16 - 0
frontend_app_admin_workspace_user/src/index.dev.js View File

1
+import React from 'react'
2
+import ReactDOM from 'react-dom'
3
+import AdminWorkspaceUser from './container/AdminWorkspaceUser.jsx'
4
+// import PopupCreateHtmlDocument from './container/PopupCreateHtmlDocument.jsx'
5
+
6
+require('./css/index.styl')
7
+
8
+ReactDOM.render(
9
+  <AdminWorkspaceUser data={undefined} />
10
+  , document.getElementById('content')
11
+)
12
+
13
+// ReactDOM.render(
14
+//   <PopupCreateHtmlDocument />
15
+//   , document.getElementById('content')
16
+// )

+ 24 - 0
frontend_app_admin_workspace_user/src/index.js View File

1
+import React from 'react'
2
+import ReactDOM from 'react-dom'
3
+import AdminWorkspaceUser from './container/AdminWorkspaceUser.jsx'
4
+
5
+require('./css/index.styl')
6
+
7
+const appInterface = {
8
+  name: 'admin_workspace_user',
9
+  isRendered: false,
10
+  renderAppFullscreen: data => {
11
+    return ReactDOM.render(
12
+      <AdminWorkspaceUser data={data} />
13
+      , document.getElementById(data.config.domContainer)
14
+    )
15
+  },
16
+  unmountApp: domId => {
17
+    return ReactDOM.unmountComponentAtNode(document.getElementById(domId)) // returns bool
18
+  }
19
+  // renderAppPopupCreation: data => {
20
+  //   return null
21
+  // }
22
+}
23
+
24
+module.exports = appInterface

+ 87 - 0
frontend_app_admin_workspace_user/webpack.config.js View File

1
+const webpack = require('webpack')
2
+const path = require('path')
3
+const isProduction = process.env.NODE_ENV === 'production'
4
+
5
+console.log('isProduction : ', isProduction)
6
+
7
+module.exports = {
8
+  entry: isProduction
9
+    ? './src/index.js' // only one instance of babel-polyfill is allowed
10
+    : ['babel-polyfill', './src/index.dev.js'],
11
+  output: {
12
+    path: path.resolve(__dirname, 'dist'),
13
+    filename: isProduction ? 'admin_workspace_user.app.js' : 'admin_workspace_user.app.dev.js',
14
+    pathinfo: !isProduction,
15
+    library: isProduction ? 'appAdminWorkspaceUser' : undefined,
16
+    libraryTarget: isProduction ? 'var' : undefined
17
+  },
18
+  externals: {},
19
+  // isProduction ? { // Côme - since plugins are imported through <script>, cannot externalize libraries
20
+  //   react: {commonjs: 'react', commonjs2: 'react', amd: 'react', root: '_'},
21
+  //   'react-dom': {commonjs: 'react-dom', commonjs2: 'react-dom', amd: 'react-dom', root: '_'},
22
+  //   classnames: {commonjs: 'classnames', commonjs2: 'classnames', amd: 'classnames', root: '_'},
23
+  //   'prop-types': {commonjs: 'prop-types', commonjs2: 'prop-types', amd: 'prop-types', root: '_'},
24
+  //   tracim_lib: {commonjs: 'tracim_lib', commonjs2: 'tracim_lib', amd: 'tracim_lib', root: '_'}
25
+  // }
26
+  // : {},
27
+  devServer: {
28
+    contentBase: path.join(__dirname, 'dist/'),
29
+    port: 8073,
30
+    hot: true,
31
+    noInfo: true,
32
+    overlay: {
33
+      warnings: false,
34
+      errors: true
35
+    },
36
+    historyApiFallback: true
37
+    // headers: {
38
+    //   'Access-Control-Allow-Origin': '*'
39
+    // }
40
+  },
41
+  devtool: isProduction ? false : 'cheap-module-source-map',
42
+  module: {
43
+    rules: [{
44
+      test: /\.jsx?$/,
45
+      enforce: 'pre',
46
+      use: 'standard-loader',
47
+      exclude: [/node_modules/]
48
+    }, {
49
+      test: [/\.js$/, /\.jsx$/],
50
+      loader: 'babel-loader',
51
+      options: {
52
+        presets: ['env', 'react'],
53
+        plugins: ['transform-object-rest-spread', 'transform-class-properties', 'transform-object-assign']
54
+      },
55
+      exclude: [/node_modules/]
56
+    }, {
57
+      test: /\.css$/,
58
+      use: ['style-loader', 'css-loader']
59
+    }, {
60
+      test: /\.styl$/,
61
+      use: ['style-loader', 'css-loader', 'stylus-loader']
62
+    }, {
63
+      test: /\.(jpg|png|svg)$/,
64
+      loader: 'url-loader',
65
+      options: {
66
+        limit: 25000
67
+      }
68
+    }]
69
+  },
70
+  resolve: {
71
+    extensions: ['.js', '.jsx']
72
+  },
73
+  plugins: [
74
+    ...[], // generic plugins always present
75
+    ...(isProduction
76
+      ? [ // production specific plugins
77
+        new webpack.DefinePlugin({
78
+          'process.env': { 'NODE_ENV': JSON.stringify('production') }
79
+        }),
80
+        new webpack.optimize.UglifyJsPlugin({
81
+          compress: { warnings: false }
82
+        })
83
+      ]
84
+      : [] // development specific plugins
85
+    )
86
+  ]
87
+}

+ 1 - 1
frontend_app_html-document/package.json View File

53
       "btoa",
53
       "btoa",
54
       "wysiwyg",
54
       "wysiwyg",
55
       "tinymce",
55
       "tinymce",
56
-      "GLOBAL_renderAppFull",
56
+      "GLOBAL_renderAppFeature",
57
       "GLOBAL_unmountApp",
57
       "GLOBAL_unmountApp",
58
       "GLOBAL_dispatchEvent"
58
       "GLOBAL_dispatchEvent"
59
     ],
59
     ],

+ 1 - 1
frontend_app_html-document/src/container/PopupCreateHtmlDocument.jsx View File

15
     faIcon: 'file-text-o',
15
     faIcon: 'file-text-o',
16
     hexcolor: '#3f52e3',
16
     hexcolor: '#3f52e3',
17
     creationLabel: 'Write a document',
17
     creationLabel: 'Write a document',
18
-    domContainer: 'appContainer',
18
+    domContainer: 'appFeatureContainer',
19
     apiUrl: 'http://localhost:3001',
19
     apiUrl: 'http://localhost:3001',
20
     apiHeader: {
20
     apiHeader: {
21
       'Accept': 'application/json',
21
       'Accept': 'application/json',

+ 1 - 1
frontend_app_html-document/src/helper.js View File

20
     faIcon: 'file-text-o',
20
     faIcon: 'file-text-o',
21
     hexcolor: '#3f52e3',
21
     hexcolor: '#3f52e3',
22
     creationLabel: 'Write a document',
22
     creationLabel: 'Write a document',
23
-    domContainer: 'appContainer',
23
+    domContainer: 'appFeatureContainer',
24
     apiUrl: 'http://localhost:6543/api/v2',
24
     apiUrl: 'http://localhost:6543/api/v2',
25
     apiHeader: {
25
     apiHeader: {
26
       'Accept': 'application/json',
26
       'Accept': 'application/json',

+ 1 - 1
frontend_app_html-document/src/index.js View File

12
 const appInterface = {
12
 const appInterface = {
13
   name: 'html-document',
13
   name: 'html-document',
14
   isRendered: false,
14
   isRendered: false,
15
-  renderAppFull: data => {
15
+  renderAppFeature: data => {
16
     return ReactDOM.render(
16
     return ReactDOM.render(
17
       <HtmlDocument data={data} />
17
       <HtmlDocument data={data} />
18
       , document.getElementById(data.config.domContainer)
18
       , document.getElementById(data.config.domContainer)

+ 1 - 1
frontend_app_thread/package.json View File

53
       "btoa",
53
       "btoa",
54
       "wysiwyg",
54
       "wysiwyg",
55
       "tinymce",
55
       "tinymce",
56
-      "GLOBAL_renderAppFull",
56
+      "GLOBAL_renderAppFeature",
57
       "GLOBAL_unmountApp",
57
       "GLOBAL_unmountApp",
58
       "GLOBAL_dispatchEvent"
58
       "GLOBAL_dispatchEvent"
59
     ],
59
     ],

+ 1 - 1
frontend_app_thread/src/container/PopupCreateThread.jsx View File

15
     faIcon: 'file-text-o',
15
     faIcon: 'file-text-o',
16
     hexcolor: '#ad4cf9',
16
     hexcolor: '#ad4cf9',
17
     creationLabel: 'Write a thread',
17
     creationLabel: 'Write a thread',
18
-    domContainer: 'appContainer',
18
+    domContainer: 'appFeatureContainer',
19
     apiUrl: 'http://localhost:3001',
19
     apiUrl: 'http://localhost:3001',
20
     mockApiUrl: 'http://localhost:8071',
20
     mockApiUrl: 'http://localhost:8071',
21
     apiHeader: {
21
     apiHeader: {

+ 1 - 1
frontend_app_thread/src/helper.js View File

12
     faIcon: 'comments-o',
12
     faIcon: 'comments-o',
13
     hexcolor: '#ad4cf9',
13
     hexcolor: '#ad4cf9',
14
     creationLabel: 'Write a thread',
14
     creationLabel: 'Write a thread',
15
-    domContainer: 'appContainer',
15
+    domContainer: 'appFeatureContainer',
16
     apiUrl: 'http://localhost:6543/api/v2',
16
     apiUrl: 'http://localhost:6543/api/v2',
17
     mockApiUrl: 'http://localhost:3001',
17
     mockApiUrl: 'http://localhost:3001',
18
     apiHeader: {
18
     apiHeader: {

+ 1 - 1
frontend_app_thread/src/index.js View File

8
 const appInterface = {
8
 const appInterface = {
9
   name: 'thread',
9
   name: 'thread',
10
   isRendered: false,
10
   isRendered: false,
11
-  renderAppFull: data => {
11
+  renderAppFeature: data => {
12
     return ReactDOM.render(
12
     return ReactDOM.render(
13
       <Thread data={data} />
13
       <Thread data={data} />
14
       , document.getElementById(data.config.domContainer)
14
       , document.getElementById(data.config.domContainer)

frontend/src/component/common/layout/PageContent.jsx → frontend_lib/src/component/Layout/PageContent.jsx View File


frontend/src/component/common/layout/PageTitle.jsx → frontend_lib/src/component/Layout/PageTitle.jsx View File

8
       <div className={classnames(`${props.parentClass}__title`, 'pageTitleGeneric__title d-flex align-items-center')}>
8
       <div className={classnames(`${props.parentClass}__title`, 'pageTitleGeneric__title d-flex align-items-center')}>
9
         <div className='pageTitleGeneric__title__icon mr-3'>
9
         <div className='pageTitleGeneric__title__icon mr-3'>
10
           <i className='fa fa-fw fa-th mr-3' />
10
           <i className='fa fa-fw fa-th mr-3' />
11
-          Liste des Contenus
11
+          {props.title}
12
         </div>
12
         </div>
13
-        {props.title}
13
+        {props.subtitle}
14
       </div>
14
       </div>
15
       {props.children}
15
       {props.children}
16
     </div>
16
     </div>
19
 
19
 
20
 PageTitle.propTypes = {
20
 PageTitle.propTypes = {
21
   title: PropTypes.string.isRequired,
21
   title: PropTypes.string.isRequired,
22
+  subtitle: PropTypes.string,
22
   parentClass: PropTypes.string,
23
   parentClass: PropTypes.string,
23
   customClass: PropTypes.string
24
   customClass: PropTypes.string
24
 }
25
 }

frontend/src/component/common/layout/PageWrapper.jsx → frontend_lib/src/component/Layout/PageWrapper.jsx View File


+ 8 - 0
frontend_lib/src/index.js View File

14
 import libTextAreaApp from './component/Input/TextAreaApp/TextAreaApp.jsx'
14
 import libTextAreaApp from './component/Input/TextAreaApp/TextAreaApp.jsx'
15
 import libBtnSwitch from './component/Input/BtnSwitch/BtnSwitch.jsx'
15
 import libBtnSwitch from './component/Input/BtnSwitch/BtnSwitch.jsx'
16
 
16
 
17
+import libPageWrapper from './component/Layout/PageWrapper.jsx'
18
+import libPageTitle from './component/Layout/PageTitle.jsx'
19
+import libPageContent from './component/Layout/PageContent.jsx'
20
+
17
 import libDelimiter from './component/Delimiter/Delimiter.jsx'
21
 import libDelimiter from './component/Delimiter/Delimiter.jsx'
18
 
22
 
19
 import libCardPopup from './component/CardPopup/CardPopup.jsx'
23
 import libCardPopup from './component/CardPopup/CardPopup.jsx'
40
 export const TextAreaApp = libTextAreaApp
44
 export const TextAreaApp = libTextAreaApp
41
 export const BtnSwitch = libBtnSwitch
45
 export const BtnSwitch = libBtnSwitch
42
 
46
 
47
+export const PageWrapper = libPageWrapper
48
+export const PageTitle = libPageTitle
49
+export const PageContent = libPageContent
50
+
43
 export const Delimiter = libDelimiter
51
 export const Delimiter = libDelimiter
44
 
52
 
45
 export const CardPopup = libCardPopup
53
 export const CardPopup = libCardPopup

+ 10 - 0
install_frontend_dependencies.sh View File

32
 npm link tracim_frontend_lib
32
 npm link tracim_frontend_lib
33
 cd -
33
 cd -
34
 
34
 
35
+# install app Admin Workspace User
36
+
37
+log "cd frontend_app_admin_workspace_user"
38
+cd frontend_app_admin_workspace_user
39
+log "npm i"
40
+npm i
41
+log "npm link tracim_frontend_lib"
42
+npm link tracim_frontend_lib
43
+cd -
44
+
35
 # install Tracim Frontend
45
 # install Tracim Frontend
36
 
46
 
37
 log "cd frontend"
47
 log "cd frontend"