bfg-common 1.5.24 → 1.5.26

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.
@@ -0,0 +1,229 @@
1
+ <template>
2
+ <Teleport to="body">
3
+ <div
4
+ id="signpost"
5
+ :class="['signpost', signpostClass]"
6
+ :data-id="`${props.testId}-signpost`"
7
+ :style="signpostStyles"
8
+ @click.stop
9
+ @mouseenter="hovered = true"
10
+ @mouseleave="hovered = false"
11
+ >
12
+ <div class="signpost-wrap">
13
+ <div class="popover-pointer" />
14
+ <div class="signpost-content-header">
15
+ <button
16
+ :id="`${props.testId}-close-icon`"
17
+ :data-id="`${props.testId}-close-icon`"
18
+ class="signpost-action close"
19
+ @click="hide"
20
+ >
21
+ <atoms-the-icon class="close-icon" name="close" />
22
+ </button>
23
+ </div>
24
+ <div class="signpost-content-body">
25
+ <slot />
26
+ </div>
27
+ </div>
28
+ </div>
29
+ </Teleport>
30
+ </template>
31
+
32
+ <script setup lang="ts">
33
+ import type { UI_I_ElPosition } from '~/components/atoms/tooltip/lib/models/interfaces'
34
+ const props = withDefaults(
35
+ defineProps<{
36
+ elemId: string
37
+ testId?: string
38
+ }>(),
39
+ { testId: 'ui-signpost' }
40
+ )
41
+ const emits = defineEmits<{
42
+ (event: 'hide'): void
43
+ }>()
44
+ const hide = (): void => {
45
+ emits('hide')
46
+ }
47
+
48
+ const signpostStyles = ref<UI_I_ElPosition | null>(null)
49
+ watch(
50
+ () => props.elemId,
51
+ (newValue: string) => {
52
+ const element =
53
+ (document.getElementById(newValue) as HTMLDivElement) || null
54
+ const { width, x, y } = element.getBoundingClientRect()
55
+
56
+ signpostStyles.value = {
57
+ top: `${y}px`,
58
+ left: `${x + width / 2}px`,
59
+ }
60
+ setTimeout(() => {
61
+ setSignpostPosition()
62
+ }, 0)
63
+ },
64
+ { immediate: true }
65
+ )
66
+ const signpostClass = ref<string[]>([])
67
+ const setSignpostPosition = (): void => {
68
+ const signpost =
69
+ (document.getElementById('signpost') as HTMLDivElement) || null
70
+ const signpostRect = (signpost?.getBoundingClientRect() as DOMRect) || null
71
+
72
+ type PositionX = 'right' | 'left'
73
+ let positionX: PositionX = 'right'
74
+
75
+ type PositionY = 'top' | 'middle'
76
+ let positionY: PositionY = 'middle'
77
+
78
+ const isOutRight = signpostRect.left + signpostRect.width > window.innerWidth
79
+ const isOutTop = signpostRect.top < 0
80
+
81
+ if (isOutTop) {
82
+ positionY = 'top'
83
+ }
84
+ if (isOutRight) {
85
+ positionX = 'left'
86
+ }
87
+
88
+ signpostClass.value.push(positionY)
89
+ signpostClass.value.push(positionX)
90
+ signpostClass.value.push('show')
91
+ }
92
+
93
+ const hovered = ref<boolean>(false)
94
+ const windowClick = (): void => {
95
+ hide()
96
+ }
97
+ const windowScroll = (): void => {
98
+ if (hovered.value) {
99
+ return
100
+ }
101
+ hide()
102
+ }
103
+ onMounted(() => {
104
+ setTimeout(() => {
105
+ window.addEventListener('click', windowClick)
106
+ window.addEventListener('scroll', windowScroll, true)
107
+ })
108
+ })
109
+ onUnmounted(() => {
110
+ window.removeEventListener('click', windowClick)
111
+ window.removeEventListener('scroll', windowScroll, true)
112
+ })
113
+ </script>
114
+
115
+ <style scoped lang="scss">
116
+ .signpost {
117
+ opacity: 0;
118
+ position: fixed;
119
+ cursor: default;
120
+ transform: translateY(calc(-50% + 14px)) translateX(20px);
121
+ z-index: var(--z-popover);
122
+
123
+ &.show {
124
+ opacity: 1;
125
+ }
126
+ &.left {
127
+ transform: translateY(calc(-50% + 14px)) translateX(calc(-100% - 20px));
128
+
129
+ .signpost-wrap {
130
+ .popover-pointer {
131
+ left: 100%;
132
+ border-right: unset;
133
+ border-left: 12px solid var(--signpost-border-color);
134
+
135
+ &::before {
136
+ border-right: unset;
137
+ border-left: 12px solid var(--signpost-bgcolor);
138
+ left: unset;
139
+ right: 2px;
140
+ }
141
+ }
142
+ }
143
+ }
144
+ &.top {
145
+ transform: translateY(calc(0% + 10px)) translateX(20px);
146
+
147
+ &.left {
148
+ transform: translateY(calc(0% + 10px)) translateX(calc(-100% - 20px));
149
+
150
+ .popover-pointer {
151
+ top: 5px;
152
+ }
153
+ }
154
+
155
+ .signpost-wrap {
156
+ .popover-pointer {
157
+ top: 5px;
158
+ }
159
+ }
160
+ }
161
+
162
+ .signpost-wrap {
163
+ border-radius: 3px;
164
+ border: 1px solid var(--signpost-border-color);
165
+ background-color: var(--signpost-bgcolor);
166
+ position: relative;
167
+
168
+ .popover-pointer {
169
+ border-bottom: 12px solid transparent;
170
+ top: 50%;
171
+ transform: translateY(-50%);
172
+ border-right: 12px solid var(--signpost-border-color);
173
+ left: -12px;
174
+ height: 0;
175
+ width: 0;
176
+ position: absolute;
177
+
178
+ &::before {
179
+ border-bottom: 12px solid transparent;
180
+ top: 1px;
181
+ border-right: 12px solid var(--signpost-bgcolor);
182
+ left: 2px;
183
+ content: '';
184
+ height: 0;
185
+ width: 0;
186
+ position: absolute;
187
+ }
188
+ }
189
+
190
+ .signpost-content-header {
191
+ display: flex;
192
+ justify-content: flex-end;
193
+ position: absolute;
194
+ width: 100%;
195
+ background-color: inherit;
196
+ top: 0;
197
+
198
+ button {
199
+ line-height: 24px;
200
+
201
+ .close-icon {
202
+ width: 16px;
203
+ height: 16px;
204
+ }
205
+ }
206
+ }
207
+
208
+ .signpost-content-body {
209
+ padding: 24px;
210
+ max-height: 480px;
211
+ overflow-y: auto;
212
+ text-transform: none;
213
+ }
214
+ }
215
+ }
216
+ </style>
217
+
218
+ <style>
219
+ :root {
220
+ --signpost-bgcolor: #fff;
221
+ --signpost-border-color: #b3b3b3;
222
+ --signpost-color: #acbac3;
223
+ }
224
+ :root.dark-theme {
225
+ --signpost-bgcolor: #21333b;
226
+ --signpost-border-color: #000;
227
+ --signpost-color: #acbac3;
228
+ }
229
+ </style>
@@ -1,5 +1,9 @@
1
1
  <template>
2
- <common-graph-new v-if="isNewView" :chart-options="chartOptions" />
2
+ <common-graph-graph-new
3
+ v-if="isNewView"
4
+ :chart-options="chartOptions"
5
+ @select-item="onSelectNewViewExportItem"
6
+ />
3
7
  <common-graph-old v-else :chart-options="chartOptions" />
4
8
  </template>
5
9
 
@@ -36,6 +40,28 @@ const exportChart = (type: string): void => {
36
40
  })
37
41
  } else if (type === 'csv') {
38
42
  localChart.downloadCSV()
43
+ } else if (type === 'print') {
44
+ localChart.print()
45
+ }
46
+ }
47
+
48
+ const onSelectNewViewExportItem = (value: string): void => {
49
+ switch (value) {
50
+ case 'downloadPNG':
51
+ exportChart('png')
52
+ break
53
+ case 'downloadJPEG':
54
+ exportChart('jpeg')
55
+ break
56
+ case 'downloadSVG':
57
+ exportChart('svg')
58
+ break
59
+ case 'downloadCSV':
60
+ exportChart('csv')
61
+ break
62
+ case 'printChart':
63
+ exportChart('print')
64
+ break
39
65
  }
40
66
  }
41
67
 
@@ -91,14 +117,4 @@ watch(
91
117
  )
92
118
  </script>
93
119
 
94
- <style scoped lang="scss">
95
- .graph-content {
96
- width: 100%;
97
- //height: inherit;
98
- height: 100%;
99
-
100
- .graph-block {
101
- height: 100%;
102
- }
103
- }
104
- </style>
120
+ <style scoped lang="scss"></style>
@@ -0,0 +1,104 @@
1
+ <template>
2
+ <common-graph-new v-if="isNewView" :chart-options="chartOptions" />
3
+ <common-graph-old v-else :chart-options="chartOptions" />
4
+ </template>
5
+
6
+ <script setup lang="ts">
7
+ import type {
8
+ I_LineGraph,
9
+ I_DiskGraph,
10
+ } from 'bfg-nuxt-3-graph/graph/lib/models/interfaces'
11
+
12
+ const props = defineProps<{
13
+ chart?: any
14
+ data: I_LineGraph | I_DiskGraph
15
+ update: number
16
+ exportType?: string
17
+ selectedRow?: number[]
18
+ }>()
19
+
20
+ const { $store }: any = useNuxtApp()
21
+ const isNewView = computed<boolean>(() => $store.getters['main/getIsNewView'])
22
+
23
+ let localChart: any = null
24
+ const exportChart = (type: string): void => {
25
+ if (type === 'png') {
26
+ localChart.exportChart({
27
+ type: 'image/png',
28
+ })
29
+ } else if (type === 'jpeg') {
30
+ localChart.exportChart({
31
+ type: 'image/jpeg',
32
+ })
33
+ } else if (type === 'svg') {
34
+ localChart.exportChart({
35
+ type: 'image/svg+xml',
36
+ })
37
+ } else if (type === 'csv') {
38
+ localChart.downloadCSV()
39
+ }
40
+ }
41
+
42
+ const chartOptions = ref<I_LineGraph | I_DiskGraph | null>(null)
43
+ const initGraph = (): void => {
44
+ if (!props.data) return
45
+ setTimeout(() => {
46
+ chartOptions.value = props.data
47
+ }, 500)
48
+ }
49
+
50
+ watch(
51
+ () => props.update,
52
+ (newValue) => {
53
+ newValue && initGraph()
54
+ },
55
+ { immediate: true }
56
+ )
57
+
58
+ watch(
59
+ () => props.exportType,
60
+ (newValue) => {
61
+ if (!newValue) return
62
+
63
+ exportChart(newValue)
64
+ }
65
+ )
66
+
67
+ watch(
68
+ () => props.chart,
69
+ (newValue) => {
70
+ if (newValue.series) localChart = newValue
71
+ },
72
+ { deep: true }
73
+ )
74
+
75
+ const updateSeriesStrokeWidth = (data: number[]): void => {
76
+ if (!localChart) return
77
+
78
+ const newChartOptions = chartOptions.value
79
+ newChartOptions.series.forEach((_: any, key: number) => {
80
+ newChartOptions.series[key].lineWidth = 1.5
81
+
82
+ if (data.includes(key)) newChartOptions.series[key].lineWidth = 3
83
+ })
84
+
85
+ chartOptions.value = newChartOptions
86
+ }
87
+
88
+ watch(
89
+ () => props.selectedRow,
90
+ (newValue) => newValue && updateSeriesStrokeWidth(newValue)
91
+ )
92
+ </script>
93
+
94
+ <style scoped lang="scss">
95
+ .graph-content {
96
+ width: 100%;
97
+ //height: inherit;
98
+ height: 100%;
99
+
100
+ .graph-block {
101
+ height: 100%;
102
+ }
103
+ }
104
+ </style>
@@ -0,0 +1,194 @@
1
+ <template>
2
+ <div
3
+ ref="chartContainer"
4
+ :class="[
5
+ 'graph-content',
6
+ { 'header-in-block': props.isHeaderInBlock },
7
+ { 'full-screen': isFullscreen },
8
+ ]"
9
+ >
10
+ <template v-if="props.chartOptions">
11
+ <client-only>
12
+ <div class="metric-header">
13
+ <span class="chart-title">{{ props.chartOptions.title.text }}</span>
14
+ <div class="chart-export-dropdown-container">
15
+ <ui-button
16
+ :test-id="`button-metric-${uniqueId}`"
17
+ is-without-sizes
18
+ is-without-height
19
+ variant="text"
20
+ :class="['metric-export-button', { active: isShowDropdown }]"
21
+ @click="isShowDropdown = !isShowDropdown"
22
+ >
23
+ <ui-icon name="burger" width="20" height="20" />
24
+ </ui-button>
25
+ <ui-dropdown
26
+ :test-id="`metric-${uniqueId}-dropdown`"
27
+ :show="isShowDropdown"
28
+ :items="dropdownItems"
29
+ :elem-id="`button-metric-${uniqueId}`"
30
+ left
31
+ width="max-content"
32
+ @select="onSelect($event, key)"
33
+ @hide="isShowDropdown = false"
34
+ />
35
+ </div>
36
+ </div>
37
+ <highchart
38
+ :options="props.chartOptions"
39
+ :modules="['exporting', 'export-data']"
40
+ class="graph-block"
41
+ />
42
+ </client-only>
43
+ </template>
44
+ </div>
45
+ </template>
46
+
47
+ <script setup lang="ts">
48
+ import { useFullscreen } from '@vueuse/core'
49
+ import type { UI_I_Dropdown } from '~/node_modules/bfg-uikit/components/ui/dropdown/models/interfaces'
50
+ import type { UI_I_Localization } from '~/lib/models/interfaces'
51
+ import { E_ChartExportIconByKey } from '~/components/common/graph/graphNew/lib/models/enums'
52
+
53
+ const props = withDefaults(
54
+ defineProps<{
55
+ chartOptions: any
56
+ isHeaderInBlock?: boolean
57
+ }>(),
58
+ {
59
+ isHeaderInBlock: true,
60
+ }
61
+ )
62
+ const emits = defineEmits<{
63
+ (event: 'select-item', value: string): void
64
+ }>()
65
+
66
+ const localization = computed<UI_I_Localization>(() => useLocal())
67
+
68
+ const uniqueId = ref<number>(useUniqueId())
69
+
70
+ const chartContainer = ref<any>(null)
71
+ const { isFullscreen, toggle } = useFullscreen(chartContainer)
72
+
73
+ const isShowDropdown = ref<boolean>(false)
74
+ const dropdownItems = computed<UI_I_Dropdown[]>(() => {
75
+ const result = []
76
+
77
+ const exportItems = props.chartOptions?.exporting?.menuItemDefinitions
78
+ for (const key in exportItems) {
79
+ if (!exportItems[key].isHide)
80
+ result.push({
81
+ text: exportItems[key].text,
82
+ value: key,
83
+ iconName: E_ChartExportIconByKey[key],
84
+ divider: key === 'printChart',
85
+ })
86
+ }
87
+
88
+ if (isFullscreen.value) {
89
+ result.map((item) => {
90
+ if (item.value === 'viewFullscreen') {
91
+ item.text = localization.value.common.exitFullscreen
92
+ item.iconName = 'exit-full-screen'
93
+ }
94
+
95
+ return item
96
+ })
97
+ }
98
+
99
+ return result
100
+ })
101
+
102
+ const onSelect = (value: string): void => {
103
+ switch (value) {
104
+ case 'viewFullscreen':
105
+ toggle()
106
+ break
107
+ default:
108
+ emits('select-item', value)
109
+ }
110
+ }
111
+ </script>
112
+
113
+ <style>
114
+ :root {
115
+ --chart-block-title-color: #4d5d69;
116
+ --chart-block-header-bg-color: #ffffff;
117
+ --chart-block-export-button-color: #4d5d69;
118
+ --chart-block-export-button-hover-color: #213444;
119
+ --chart-block-export-button-active-color: #008fd6;
120
+ }
121
+ :root.dark-theme {
122
+ --chart-block-title-color: #e9eaec;
123
+ --chart-block-header-bg-color: #334453;
124
+ --chart-block-export-button-color: #e9eaec;
125
+ --chart-block-export-button-hover-color: #ffffff;
126
+ --chart-block-export-button-active-color: #2ba2de;
127
+ }
128
+ </style>
129
+ <style scoped lang="scss">
130
+ .graph-content {
131
+ display: flex;
132
+ flex-direction: column;
133
+ width: 100%;
134
+ height: 100%;
135
+ box-shadow: 0 1px 4px 0 #00000014;
136
+ border-radius: 8px;
137
+
138
+ &.full-screen {
139
+ .metric-header {
140
+ border-radius: 0;
141
+
142
+ .chart-title {
143
+ font-size: 22px;
144
+ }
145
+ .metric-export-button {
146
+ svg {
147
+ width: 24px;
148
+ height: 24px;
149
+ }
150
+ }
151
+ }
152
+ .graph-block {
153
+ border-radius: 0;
154
+ }
155
+ }
156
+ .metric-header {
157
+ display: grid;
158
+ align-items: center;
159
+ grid-template-columns: max-content max-content;
160
+ justify-content: space-between;
161
+ padding: 16px;
162
+ background-color: var(--chart-block-header-bg-color);
163
+ border-radius: 8px 8px 0px 0px;
164
+
165
+ .chart-title {
166
+ color: var(--chart-block-title-color);
167
+ font-family: Inter;
168
+ font-size: 16px;
169
+ font-weight: 500;
170
+ }
171
+ .chart-export-dropdown-container {
172
+ position: relative;
173
+
174
+ .metric-export-button {
175
+ color: var(--chart-block-export-button-color);
176
+
177
+ &:hover {
178
+ color: var(--chart-block-export-button-hover-color);
179
+ }
180
+ &.active {
181
+ color: var(--chart-block-export-button-active-color);
182
+ }
183
+ }
184
+ }
185
+ }
186
+
187
+ .graph-block {
188
+ height: 100%;
189
+ overflow: hidden;
190
+ border-radius: 0px 0px 8px 8px;
191
+ background-color: var(--chart-block-header-bg-color);
192
+ }
193
+ }
194
+ </style>
@@ -0,0 +1,9 @@
1
+ export enum E_ChartExportIconByKey {
2
+ 'openNewWindow' = 'new-tab',
3
+ 'printChart' = 'print',
4
+ 'viewFullscreen' = 'view-full-screen',
5
+ 'downloadPNG' = 'download-2',
6
+ 'downloadJPEG' = 'download-2',
7
+ 'downloadSVG' = 'download-2',
8
+ 'downloadCSV' = 'download-2',
9
+ }
@@ -5,7 +5,7 @@
5
5
  </template>
6
6
  <div v-else class="services-table">
7
7
  <div class="services-table__title">
8
- <h1>{{ localization.common.services }}</h1>
8
+ <h1>{{ localization.inventoryConfigure.services }}</h1>
9
9
  <span>({{ props.services.length }})</span>
10
10
  </div>
11
11
 
@@ -2,7 +2,7 @@
2
2
  <div class="clr-col-md-6 clr-col-sm-12">
3
3
  <div class="entity-status">
4
4
  <common-pages-home-card
5
- :title="localization.common.services"
5
+ :title="localization.inventoryConfigure.services"
6
6
  :count="props.services.length"
7
7
  icon-name="icon-content-libraries"
8
8
  class="most-alerts"
@@ -103,9 +103,9 @@ onUnmounted(() => {
103
103
  margin-bottom: 22px;
104
104
  }
105
105
 
106
- :deep(.data-table-header) {
107
- z-index: var(--z-sticky) !important; // TODO надо удалить потом (clr style)
108
- }
106
+ //:deep(.data-table-header) {
107
+ // z-index: var(--z-sticky) !important; // TODO надо удалить потом (clr style)
108
+ //}
109
109
  }
110
110
 
111
111
  :deep(.table-container) {
@@ -115,7 +115,7 @@ const props = defineProps<{
115
115
  overflow: hidden;
116
116
  flex: 1;
117
117
  box-shadow: var(--second-panel-box-shadow);
118
- z-index: calc(var(--z-default) + 1);
118
+ //z-index: calc(var(--z-default) + 1);
119
119
  }
120
120
  }
121
121
  </style>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bfg-common",
3
3
  "private": false,
4
- "version": "1.5.24",
4
+ "version": "1.5.26",
5
5
  "scripts": {
6
6
  "build": "nuxt build",
7
7
  "dev": "nuxt dev --port=3002",
@@ -34,8 +34,8 @@
34
34
  "@nuxtjs/eslint-config-typescript": "^12.0.0",
35
35
  "@vueuse/components": "^10.1.2",
36
36
  "date-fns": "^2.29.3",
37
- "bfg-nuxt-3-graph": "1.0.21",
38
- "bfg-uikit": "1.0.378",
37
+ "bfg-nuxt-3-graph": "1.0.22",
38
+ "bfg-uikit": "1.0.379",
39
39
  "html2canvas": "^1.4.1",
40
40
  "prettier-eslint": "^15.0.1"
41
41
  }
package/package.json~ ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "bfg-common",
3
+ "private": false,
4
+ "version": "1.5.25",
5
+ "scripts": {
6
+ "build": "nuxt build",
7
+ "dev": "nuxt dev --port=3002",
8
+ "generate": "nuxt generate",
9
+ "preview": "nuxt preview",
10
+ "postinstall": "nuxt prepare",
11
+ "minify": "node minify.js",
12
+ "prepublishOnly": "node minify.js"
13
+ },
14
+ "devDependencies": {
15
+ "@novnc/novnc": "1.4.0",
16
+ "@vueuse/core": "10.1.2",
17
+ "@vueuse/nuxt": "10.1.2",
18
+ "eslint-config-prettier": "^8.5.0",
19
+ "nuxt": "3.11.2",
20
+ "prettier": "2.7.1",
21
+ "sass": "^1.54.9",
22
+ "sass-loader": "^10.3.1",
23
+ "terser": "^5.22.0",
24
+ "vite-plugin-eslint": "^1.8.1",
25
+ "xterm": "^5.1.0",
26
+ "xterm-addon-attach": "^0.8.0",
27
+ "xterm-addon-fit": "^0.7.0",
28
+ "xterm-addon-serialize": "^0.9.0",
29
+ "xterm-addon-unicode11": "^0.5.0",
30
+ "xterm-addon-web-links": "^0.8.0",
31
+ "eslint-plugin-myrules": "file:./eslint"
32
+ },
33
+ "dependencies": {
34
+ "@nuxtjs/eslint-config-typescript": "^12.0.0",
35
+ "@vueuse/components": "^10.1.2",
36
+ "date-fns": "^2.29.3",
37
+ "bfg-nuxt-3-graph": "1.0.22",
38
+ "bfg-uikit": "1.0.379",
39
+ "html2canvas": "^1.4.1",
40
+ "prettier-eslint": "^15.0.1"
41
+ }
42
+ }