@things-factory/menu-ui 8.0.0-alpha.8 → 8.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/client/apptools/{favorite-tool.js → favorite-tool.ts} +24 -30
  2. package/client/{bootstrap.js → bootstrap.ts} +1 -1
  3. package/client/components/{child-menus-selector.js → child-menus-selector.ts} +51 -57
  4. package/client/components/{role-select-popup.js → role-select-popup.ts} +38 -48
  5. package/client/pages/{menu-list-page.js → menu-list-page.ts} +47 -37
  6. package/client/pages/{menu-management-detail.js → menu-management-detail.ts} +74 -65
  7. package/client/pages/{menu-management.js → menu-management.ts} +33 -41
  8. package/client/pages/{role-menus-management.js → role-menus-management.ts} +56 -62
  9. package/client/viewparts/menu-bar.ts +110 -0
  10. package/client/viewparts/menu-tile-list.ts +216 -0
  11. package/client/viewparts/{menu-tree-bar.js → menu-tree-bar.ts} +133 -139
  12. package/dist-client/apptools/favorite-tool.d.ts +28 -0
  13. package/dist-client/apptools/favorite-tool.js +139 -0
  14. package/dist-client/apptools/favorite-tool.js.map +1 -0
  15. package/dist-client/bootstrap.d.ts +4 -0
  16. package/dist-client/bootstrap.js +52 -0
  17. package/dist-client/bootstrap.js.map +1 -0
  18. package/dist-client/components/child-menus-selector.d.ts +1 -0
  19. package/dist-client/components/child-menus-selector.js +146 -0
  20. package/dist-client/components/child-menus-selector.js.map +1 -0
  21. package/dist-client/components/role-select-popup.d.ts +1 -0
  22. package/dist-client/components/role-select-popup.js +180 -0
  23. package/dist-client/components/role-select-popup.js.map +1 -0
  24. package/dist-client/index.d.ts +0 -0
  25. package/dist-client/index.js +2 -0
  26. package/dist-client/index.js.map +1 -0
  27. package/dist-client/pages/menu-list-page.d.ts +2 -0
  28. package/dist-client/pages/menu-list-page.js +204 -0
  29. package/dist-client/pages/menu-list-page.js.map +1 -0
  30. package/dist-client/pages/menu-management-detail.d.ts +2 -0
  31. package/dist-client/pages/menu-management-detail.js +376 -0
  32. package/dist-client/pages/menu-management-detail.js.map +1 -0
  33. package/dist-client/pages/menu-management.d.ts +3 -0
  34. package/dist-client/pages/menu-management.js +280 -0
  35. package/dist-client/pages/menu-management.js.map +1 -0
  36. package/dist-client/pages/role-menus-management.d.ts +4 -0
  37. package/dist-client/pages/role-menus-management.js +215 -0
  38. package/dist-client/pages/role-menus-management.js.map +1 -0
  39. package/dist-client/route.d.ts +1 -0
  40. package/dist-client/route.js +14 -0
  41. package/dist-client/route.js.map +1 -0
  42. package/dist-client/themes/menu-theme.css +31 -0
  43. package/dist-client/tsconfig.tsbuildinfo +1 -0
  44. package/dist-client/viewparts/menu-bar.d.ts +12 -0
  45. package/dist-client/viewparts/menu-bar.js +108 -0
  46. package/dist-client/viewparts/menu-bar.js.map +1 -0
  47. package/dist-client/viewparts/menu-tile-list.d.ts +13 -0
  48. package/dist-client/viewparts/menu-tile-list.js +234 -0
  49. package/dist-client/viewparts/menu-tile-list.js.map +1 -0
  50. package/dist-client/viewparts/menu-tree-bar.d.ts +28 -0
  51. package/dist-client/viewparts/menu-tree-bar.js +307 -0
  52. package/dist-client/viewparts/menu-tree-bar.js.map +1 -0
  53. package/dist-server/tsconfig.tsbuildinfo +1 -1
  54. package/package.json +21 -18
  55. package/things-factory.config.js +5 -14
  56. package/client/viewparts/menu-bar.js +0 -114
  57. package/client/viewparts/menu-tile-list.js +0 -222
  58. /package/client/{index.js → index.ts} +0 -0
  59. /package/client/{route.js → route.ts} +0 -0
@@ -4,45 +4,46 @@ import './menu-management-detail'
4
4
 
5
5
  import gql from 'graphql-tag'
6
6
  import { css, html } from 'lit'
7
+ import { customElement, property, query } from 'lit/decorators.js'
7
8
 
8
9
  import { openPopup } from '@operato/layout'
9
10
  import { i18next, localize } from '@operato/i18n'
10
- import { client, PageView } from '@things-factory/shell'
11
- import { CommonButtonStyles, ScrollbarStyles } from '@things-factory/styles'
12
- import { gqlBuilder, isMobileDevice } from '@things-factory/utils'
11
+ import { CommonButtonStyles, ScrollbarStyles } from '@operato/styles'
12
+ import { isMobileDevice } from '@operato/utils'
13
+ import { client, PageView } from '@things-factory/shell/client'
14
+ import { gqlBuilder } from '@things-factory/utils/src'
13
15
 
14
16
  import { OxPrompt } from '@operato/popup/ox-prompt.js'
17
+ import { DataGrist, FetchOption } from '@operato/data-grist'
15
18
 
19
+ @customElement('menu-management')
16
20
  class MenuManagement extends localize(i18next)(PageView) {
17
- static get properties() {
18
- return {
19
- searchFields: Array,
20
- config: Object,
21
- data: Object
22
- }
23
- }
21
+ static styles = [
22
+ ScrollbarStyles,
23
+ css`
24
+ :host {
25
+ display: flex;
26
+ flex-direction: column;
27
+ overflow: hidden;
28
+ }
24
29
 
25
- static get styles() {
26
- return [
27
- ScrollbarStyles,
28
- css`
29
- :host {
30
- display: flex;
31
- flex-direction: column;
32
- overflow: hidden;
33
- }
30
+ search-form {
31
+ overflow: visible;
32
+ }
34
33
 
35
- search-form {
36
- overflow: visible;
37
- }
34
+ ox-grist {
35
+ overflow-y: auto;
36
+ flex: 1;
37
+ }
38
+ `
39
+ ]
38
40
 
39
- ox-grist {
40
- overflow-y: auto;
41
- flex: 1;
42
- }
43
- `
44
- ]
45
- }
41
+ @property({ type: Array }) searchFields: any[] = []
42
+ @property({ type: Object }) config: any
43
+ @property({ type: Object }) data: any
44
+
45
+ @query('ox-grist') dataGrist!: DataGrist
46
+ @query('search-form') searchForm!: HTMLFormElement
46
47
 
47
48
  render() {
48
49
  return html`
@@ -74,14 +75,6 @@ class MenuManagement extends localize(i18next)(PageView) {
74
75
  }
75
76
  }
76
77
 
77
- get searchForm() {
78
- return this.shadowRoot.querySelector('search-form')
79
- }
80
-
81
- get dataGrist() {
82
- return this.shadowRoot.querySelector('ox-grist')
83
- }
84
-
85
78
  pageUpdated(_changes, _lifecycle) {
86
79
  if (this.active) {
87
80
  this.dataGrist.fetch()
@@ -172,7 +165,7 @@ class MenuManagement extends localize(i18next)(PageView) {
172
165
  }
173
166
  }
174
167
 
175
- async fetchHandler({ page, limit, sorters = [{ name: 'rank' }, { name: 'name' }] }) {
168
+ async fetchHandler({ page, limit, sorters = [{ name: 'rank' }, { name: 'name' }] }: FetchOption) {
176
169
  const response = await client.query({
177
170
  query: gql`
178
171
  query {
@@ -267,11 +260,12 @@ class MenuManagement extends localize(i18next)(PageView) {
267
260
 
268
261
  if (patches && patches.length) {
269
262
  patches = patches.map(menu => {
270
- let patchField = menu.id ? { id: menu.id } : {}
263
+ let patchField: any = menu.id ? { id: menu.id } : {}
271
264
  const dirtyFields = menu.__dirtyfields__
272
265
  for (let key in dirtyFields) {
273
266
  patchField[key] = dirtyFields[key].after
274
267
  }
268
+
275
269
  patchField.cuFlag = menu.__dirty__
276
270
  patchField.menuType = 'MENU'
277
271
 
@@ -290,5 +284,3 @@ class MenuManagement extends localize(i18next)(PageView) {
290
284
  })
291
285
  }
292
286
  }
293
-
294
- customElements.define('menu-management', MenuManagement)
@@ -5,73 +5,69 @@ import '../components/child-menus-selector'
5
5
 
6
6
  import gql from 'graphql-tag'
7
7
  import { css, html } from 'lit'
8
+ import { customElement, property } from 'lit/decorators.js'
8
9
 
9
10
  import { openPopup } from '@operato/layout'
10
11
  import { i18next, localize } from '@operato/i18n'
11
- import { client, PageView } from '@things-factory/shell'
12
+ import { client, PageView } from '@things-factory/shell/client'
12
13
 
14
+ @customElement('role-menus-management')
13
15
  class RoleMenusManagement extends localize(i18next)(PageView) {
14
- static get styles() {
15
- return [
16
- css`
17
- :host {
18
- display: flex;
19
- flex-direction: column;
20
- background-color: var(--md-sys-color-background);
21
- padding: var(--spacing-large);
22
- overflow: auto;
23
- }
24
- [input-container] {
25
- display: flex;
26
- background-color: var(--md-sys-color-surface);
27
- margin: var(--spacing-large) 0;
28
- padding: var(--spacing-large);
29
- border-radius: var(--border-radius);
30
- box-shadow: var(--box-shadow);
31
- clear: both;
32
- gap: 10px;
33
- }
34
- mwc-buton {
35
- margin: auto;
36
- }
37
- h2 {
38
- margin: var(--title-margin);
39
- font: var(--title-font);
40
- color: var(--title-text-color);
41
- }
42
- [subtitle] {
43
- padding: var(--subtitle-padding);
44
- font: var(--subtitle-font);
45
- color: var(--subtitle-text-color);
46
- }
16
+ static styles = [
17
+ css`
18
+ :host {
19
+ display: flex;
20
+ flex-direction: column;
21
+ background-color: var(--md-sys-color-background);
22
+ padding: var(--spacing-large);
23
+ overflow: auto;
24
+ }
25
+ [input-container] {
26
+ display: flex;
27
+ background-color: var(--md-sys-color-surface);
28
+ margin: var(--spacing-large) 0;
29
+ padding: var(--spacing-large);
30
+ border-radius: var(--border-radius);
31
+ box-shadow: var(--box-shadow);
32
+ clear: both;
33
+ gap: 10px;
34
+ }
35
+ mwc-buton {
36
+ margin: auto;
37
+ }
38
+ h2 {
39
+ margin: var(--title-margin);
40
+ font: var(--title-font);
41
+ color: var(--title-text-color);
42
+ }
43
+ [subtitle] {
44
+ padding: var(--subtitle-padding);
45
+ font: var(--subtitle-font);
46
+ color: var(--subtitle-text-color);
47
+ }
48
+ input {
49
+ border: var(--border-dim-color);
50
+ border-radius: var(--border-radius);
51
+ padding: var(--input-padding);
52
+ min-width: 250px;
53
+ font: var(--input-font);
54
+ }
55
+ label {
56
+ display: flex;
57
+ }
58
+ @media screen and (max-width: 480px) {
47
59
  input {
48
- border: var(--border-dim-color);
49
- border-radius: var(--border-radius);
50
- padding: var(--input-padding);
51
- min-width: 250px;
52
- font: var(--input-font);
53
- }
54
- label {
55
- display: flex;
56
- }
57
- @media screen and (max-width: 480px) {
58
- input {
59
- min-width: 0;
60
- }
60
+ min-width: 0;
61
61
  }
62
- `
63
- ]
64
- }
62
+ }
63
+ `
64
+ ]
65
65
 
66
- static get properties() {
67
- return {
68
- selectedRole: Object,
69
- parentMenus: Array,
70
- roleMenus: Array,
71
- menuSet: Object,
72
- targetRole: Object
73
- }
74
- }
66
+ @property({ type: Object }) selectedRole: any
67
+ @property({ type: Array }) parentMenus: any[] = []
68
+ @property({ type: Array }) roleMenus: any
69
+ @property({ type: Object }) menuSet: any
70
+ @property({ type: Object }) targetRole: any
75
71
 
76
72
  get context() {
77
73
  return {
@@ -114,7 +110,7 @@ class RoleMenusManagement extends localize(i18next)(PageView) {
114
110
  }
115
111
 
116
112
  get roleInput() {
117
- return this.shadowRoot.querySelector('input')
113
+ return this.renderRoot.querySelector('input') as HTMLInputElement
118
114
  }
119
115
 
120
116
  async pageUpdated(changes) {
@@ -211,5 +207,3 @@ class RoleMenusManagement extends localize(i18next)(PageView) {
211
207
  document.dispatchEvent(new CustomEvent('notify', { detail: { message, option: { timer: 1000 } } }))
212
208
  }
213
209
  }
214
-
215
- window.customElements.define('role-menus-management', RoleMenusManagement)
@@ -0,0 +1,110 @@
1
+ import '@material/web/icon/icon.js'
2
+
3
+ import { css, html, LitElement } from 'lit'
4
+ import { customElement, property } from 'lit/decorators.js'
5
+
6
+ import ScrollBooster from 'scrollbooster'
7
+
8
+ @customElement('menu-bar')
9
+ export default class MenuBar extends LitElement {
10
+ static styles = [
11
+ css`
12
+ :host {
13
+ background-color: var(--menu-bar-background-color, #242d30);
14
+
15
+ overflow-x: hidden;
16
+ }
17
+
18
+ ul {
19
+ display: flex;
20
+ list-style: none;
21
+ margin: 0;
22
+ padding: 0;
23
+ white-space: nowrap;
24
+ }
25
+
26
+ li {
27
+ display: inline-block;
28
+ padding: 0px 3px;
29
+
30
+ border-bottom: var(--menu-bar-line);
31
+ }
32
+
33
+ li[active] {
34
+ border-color: var(--menu-bar-active-line-color, red);
35
+ }
36
+
37
+ li a {
38
+ display: block;
39
+ padding: 5px 4px 1px 4px;
40
+ text-decoration: none;
41
+ font: var(--menu-bar-textbutton);
42
+ color: rgba(255, 255, 255, 0.8);
43
+ }
44
+
45
+ li[active] a {
46
+ font: var(--menu-bar-textbutton-active);
47
+ color: rgba(255, 255, 255, 1);
48
+ }
49
+ `
50
+ ]
51
+
52
+ @property({ type: Array }) menus: any[] = []
53
+ @property({ type: String }) menuId?: string
54
+
55
+ private __sb: any
56
+
57
+ render() {
58
+ var topmenus = this.menus || []
59
+
60
+ return html`
61
+ <ul>
62
+ <li ?active=${!this.menuId}>
63
+ <a href="menu-list"><md-icon>star</md-icon></a>
64
+ </li>
65
+
66
+ ${topmenus.map(
67
+ (menu, idx) => html`
68
+ <li ?active=${this.menuId === String(idx)}>
69
+ <a href=${`${menu.routing || 'menu-list'}/${idx}`}>${menu.name}</a>
70
+ </li>
71
+ `
72
+ )}
73
+ </ul>
74
+ `
75
+ }
76
+
77
+ _onWheelEvent(e) {
78
+ var delta = Math.max(-1, Math.min(1, e.wheelDelta || -e.detail))
79
+ this.scrollLeft -= delta * 40
80
+
81
+ e.preventDefault()
82
+ }
83
+
84
+ updated(change) {
85
+ if (change.has('menus')) {
86
+ /* menus가 바뀔 때마다, contents의 폭이 달라지므로, 다시 폭을 계산해준다. */
87
+ this.__sb && this.__sb.updateMetrics()
88
+ }
89
+
90
+ if (change.has('menuId')) {
91
+ var active = this.renderRoot.querySelector('li[active]')
92
+ active && active.scrollIntoView()
93
+ }
94
+ }
95
+
96
+ firstUpdated() {
97
+ var scrollTarget = this.renderRoot.querySelector('ul')
98
+
99
+ scrollTarget?.addEventListener('mousewheel', this._onWheelEvent.bind(this), false)
100
+
101
+ this.__sb = new ScrollBooster({
102
+ viewport: this,
103
+ content: scrollTarget,
104
+ mode: 'x',
105
+ onUpdate: data => {
106
+ this.scrollLeft = data.position.x
107
+ }
108
+ })
109
+ }
110
+ }
@@ -0,0 +1,216 @@
1
+ import '@material/web/icon/icon.js'
2
+ import '@operato/oops'
3
+
4
+ import { css, html, LitElement } from 'lit'
5
+ import { customElement, property } from 'lit/decorators.js'
6
+
7
+ @customElement('menu-tile-list')
8
+ export default class MenuTileList extends LitElement {
9
+ static styles = [
10
+ css`
11
+ :host {
12
+ display: block;
13
+ box-sizing: border-box;
14
+
15
+ position: relative;
16
+ }
17
+
18
+ ul {
19
+ display: grid;
20
+ grid-template-columns: 1fr 1fr;
21
+ grid-auto-rows: 110px;
22
+ list-style: none;
23
+ padding: 0;
24
+ margin: 0;
25
+ }
26
+
27
+ ul > li {
28
+ margin: var(--menu-tile-list-item-margin);
29
+ padding: 10px;
30
+
31
+ position: relative;
32
+ }
33
+
34
+ md-icon {
35
+ cursor: pointer;
36
+ position: absolute;
37
+ right: 8px;
38
+ top: 8px;
39
+
40
+ color: var(--menu-tile-list-favorite-color);
41
+ font-size: 1em;
42
+ }
43
+
44
+ md-icon[selected] {
45
+ color: white;
46
+ text-shadow: 1px 1px 1px var(--menu-tile-list-favorite-color);
47
+ }
48
+
49
+ li.text a {
50
+ color: #fff;
51
+ text-decoration: none;
52
+
53
+ font-size: 1.4em;
54
+ line-height: 1.3;
55
+ word-wrap: break-word;
56
+ word-break: keep-all;
57
+
58
+ margin: 0px;
59
+ display: block;
60
+ width: 100%;
61
+ height: 100%;
62
+ }
63
+
64
+ li.text:nth-child(7n + 1) {
65
+ background-color: #4397de;
66
+ }
67
+
68
+ li.text:nth-child(7n + 2) {
69
+ background-color: #33b8d0;
70
+ }
71
+
72
+ li.text:nth-child(7n + 3) {
73
+ background-color: #4ab75f;
74
+ }
75
+
76
+ li.text:nth-child(7n + 4) {
77
+ background-color: #93796f;
78
+ }
79
+
80
+ li.text:nth-child(7n + 5) {
81
+ background-color: #f1ac42;
82
+ }
83
+
84
+ li.text:nth-child(7n + 6) {
85
+ background-color: #ea6361;
86
+ }
87
+
88
+ li.text:nth-child(7n + 7) {
89
+ background-color: #7386c3;
90
+ }
91
+
92
+ ox-oops-note {
93
+ display: block;
94
+ position: absolute;
95
+ left: 50%;
96
+ top: 50%;
97
+ transform: translate(-50%, -50%);
98
+ }
99
+
100
+ ox-oops-spinner {
101
+ display: none;
102
+ position: absolute;
103
+ left: 50%;
104
+ top: 50%;
105
+ transform: translate(-50%, -50%);
106
+ }
107
+
108
+ ox-oops-spinner[show] {
109
+ display: block;
110
+ }
111
+
112
+ @media (min-width: 600px) {
113
+ ul {
114
+ grid-template-columns: 1fr 1fr 1fr;
115
+ grid-auto-rows: 120px;
116
+ }
117
+ }
118
+ @media (min-width: 1200px) {
119
+ ul {
120
+ grid-template-columns: 1fr 1fr 1fr 1fr;
121
+ grid-auto-rows: 130px;
122
+ }
123
+ }
124
+ @media (min-width: 1800px) {
125
+ ul {
126
+ grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
127
+ grid-auto-rows: 140px;
128
+ }
129
+ }
130
+ @media (min-width: 2400px) {
131
+ ul {
132
+ grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
133
+ grid-auto-rows: 150px;
134
+ }
135
+ }
136
+ `
137
+ ]
138
+
139
+ @property({ type: String }) menuId?: string
140
+ @property({ type: Array }) menus: any[] = []
141
+ @property({ type: Object }) routingTypes: any
142
+ @property({ type: Array }) favorites: any[] = []
143
+ @property({ type: Boolean }) showSpinner: boolean = false
144
+
145
+ render() {
146
+ var topmenus = this.menus || []
147
+ var menuId = this.menuId
148
+
149
+ if (!menuId) {
150
+ /* favorite menus */
151
+ var submenus = topmenus.reduce((allmenu, topmenu) => {
152
+ let menus = (topmenu && topmenu.children) || []
153
+ menus.forEach(menu => {
154
+ if (this.favorites.includes(this._getFullRouting(menu))) {
155
+ allmenu.push(menu)
156
+ }
157
+ })
158
+ return allmenu
159
+ }, [])
160
+ } else {
161
+ var menu = topmenus[menuId]
162
+ var submenus = (menu && menu.children) || []
163
+ }
164
+
165
+ return html`
166
+ <ul>
167
+ ${submenus.map(subMenu => {
168
+ const routing = this._getFullRouting(subMenu)
169
+
170
+ return html`
171
+ <li
172
+ class="${subMenu.class} text"
173
+ style="grid-row: span ${subMenu.routingType.toUpperCase() === 'STATIC' ? 1 : 2}"
174
+ >
175
+ <a href=${routing}>${subMenu.name}</a>
176
+
177
+ <md-icon ?selected=${(this.favorites || []).includes(routing)}
178
+ >${(this.favorites || ([] as any[])).includes(routing) ? 'star' : 'star_border'}</md-icon
179
+ >
180
+ </li>
181
+ `
182
+ })}
183
+ </ul>
184
+
185
+ ${submenus.length == 0 && !this.showSpinner
186
+ ? typeof menuId == 'number'
187
+ ? html`
188
+ <ox-oops-note
189
+ icon="apps"
190
+ title="No Menu Found"
191
+ description="Seems like you are not authorised to view this menu"
192
+ ></ox-oops-note>
193
+ `
194
+ : html`
195
+ <ox-oops-note
196
+ icon="star_border"
197
+ title="No Favourite Found"
198
+ description="Click ☆ icon to add new favourite menu"
199
+ ></ox-oops-note>
200
+ `
201
+ : html``}
202
+
203
+ <ox-oops-spinner ?show=${this.showSpinner}></ox-oops-spinner>
204
+ `
205
+ }
206
+
207
+ _getFullRouting(menu): string {
208
+ var { routingType, titleField, name, resourceUrl } = menu
209
+ if (routingType.toUpperCase() === 'STATIC') {
210
+ return resourceUrl
211
+ }
212
+
213
+ var { page } = this.routingTypes[routingType]
214
+ return titleField ? `${page}/${menu[titleField]}` : `${page}/${name}`
215
+ }
216
+ }