22 <div ref =" resizeTarget" class =" ff--immersive-editor-wrapper" :class =" {resizing: isEditorResizing}" >
33 <EditorWrapper
44 :url =" device ?.editor ?.url "
5+ :disable-events =" isEditorResizing "
56 :device =" device "
67 />
78
9+ <DrawerTrigger :is-hidden =" drawer .open " @toggle =" toggleDrawer " />
10+
811 <section
912 class =" tabs-wrapper drawer"
1013 :class =" {'open': drawer.open, resizing: isEditorResizing}"
1619 <resize-bar
1720 @mousedown =" startEditorResize"
1821 />
22+
23+ <div class =" header" >
24+ <div class =" logo" >
25+ <router-link title =" Back to remote instance overview" :to =" { name: 'device-overview', params: {id: device.id} }" >
26+ <ArrowLeftIcon class="ff-btn--icon" />
27+ </router-link >
28+ </div >
29+ <ff-tabs :tabs =" navigation" class =" tabs" />
30+ <div class =" side-actions" >
31+ <button
32+ title =" Close drawer"
33+ type =" button"
34+ class =" close-drawer-button"
35+ aria-label =" Close drawer"
36+ @click =" toggleDrawer"
37+ >
38+ <XIcon class="ff-btn--icon" />
39+ </button >
40+ </div >
41+ </div >
42+
43+ <ff-page :no-padding =" isExpertRoute" >
44+ <router-view
45+ :device =" device"
46+ :instance =" device.instance"
47+ />
48+ </ff-page >
1949 </section >
2050 </div >
2151</template >
2252
2353<script >
2454
55+ import { ArrowLeftIcon , XIcon } from ' @heroicons/vue/solid/index.js'
2556import semver from ' semver'
26- import { mapActions } from ' vuex'
57+ import { mapActions , mapGetters , mapState } from ' vuex'
2758
2859import deviceApi from ' ../../../api/devices.js'
2960import ResizeBar from ' ../../../components/ResizeBar.vue'
61+ import ExpertTabIcon from ' ../../../components/icons/ff-minimal-grey.js'
62+ import DrawerTrigger from ' ../../../components/immersive-editor/DrawerTrigger.vue'
3063import EditorWrapper from ' ../../../components/immersive-editor/RemoteInstanceEditorWrapper.vue'
3164import { useDrawerHelper } from ' ../../../composables/DrawerHelper.js'
3265import { useResizingHelper } from ' ../../../composables/ResizingHelper.js'
66+ import FfPage from ' ../../../layouts/Page.vue'
3367import Alerts from ' ../../../services/alerts.js'
3468
69+ const DRAWER_DEFAULT_WIDTH = 550 // Default drawer width in pixels
70+ const DRAWER_MAX_VIEWPORT_MARGIN = 200 // Space to preserve when drawer is at max width
71+ const DRAWER_MAX_WIDTH_RATIO = 0.9 // Maximum drawer width as percentage of viewport (desktop)
72+ const DRAWER_MIN_WIDTH = 310 // Minimum drawer width in pixels
73+
3574export default {
3675 name: ' DeviceEditor' ,
3776 components: {
77+ XIcon,
78+ ArrowLeftIcon,
79+ FfPage,
80+ DrawerTrigger,
3881 ResizeBar,
3982 EditorWrapper
4083 },
@@ -54,11 +97,13 @@ export default {
5497 startResize: startEditorResize ,
5598 widthStyle: editorWidthStyle ,
5699 bindResizer: bindDrawerResizer ,
57- isResizing: isEditorResizing
100+ isResizing: isEditorResizing ,
101+ setEditorWidth: setDeviceEditorWidth
58102 } = useResizingHelper ()
59103
60104 return {
61105 startEditorResize,
106+ setDeviceEditorWidth,
62107 bindDrawerResizer,
63108 editorWidthStyle,
64109 drawer,
@@ -82,7 +127,64 @@ export default {
82127 }
83128 },
84129 computed: {
85-
130+ ... mapState (' account' , [' features' ]),
131+ ... mapGetters (' account' , [' featuresCheck' ]),
132+ isExpertRoute () {
133+ return this .$route .name === ' device-editor-expert'
134+ },
135+ isDevModeAvailable : function () {
136+ return !! this .features .deviceEditor
137+ },
138+ navigation () {
139+ return [
140+ {
141+ label: ' Expert' ,
142+ to: { name: ' device-editor-expert' , params: { id: this .device .id } },
143+ tag: ' device-expert' ,
144+ icon: ExpertTabIcon,
145+ hidden: ! this .featuresCheck .isExpertAssistantFeatureEnabled
146+ },
147+ {
148+ label: ' Overview' ,
149+ to: { name: ' device-editor-overview' },
150+ tag: ' device-overview'
151+ },
152+ {
153+ label: ' Version History' ,
154+ to: {
155+ name: ' device-editor-version-history' ,
156+ params: { id: this .$route .params .id }
157+ },
158+ tag: ' version-history'
159+ },
160+ {
161+ label: ' Audit Log' ,
162+ to: { name: ' device-editor-audit-log' },
163+ tag: ' device-audit-log'
164+ },
165+ {
166+ label: ' Node-RED Logs' ,
167+ to: { name: ' device-editor-logs' },
168+ tag: ' device-logs'
169+ },
170+ {
171+ label: ' Performance' ,
172+ to: { name: ' device-editor-performance' },
173+ tag: ' device-performance'
174+ },
175+ {
176+ label: ' Settings' ,
177+ to: { name: ' device-editor-settings' },
178+ tag: ' device-settings'
179+ },
180+ {
181+ label: ' Developer Mode' ,
182+ to: { name: ' device-editor-developer-mode' },
183+ tag: ' device-devmode' ,
184+ hidden: ! (this .isDevModeAvailable && this .device .mode === ' developer' )
185+ }
186+ ]
187+ }
86188 },
87189 watch: {
88190 device (device ) {
@@ -96,7 +198,28 @@ export default {
96198 }
97199 },
98200 mounted () {
99- this .loadDevice ().catch (err => err)
201+ this .loadDevice ()
202+ .then (() => {
203+ this .bindDrawer ({
204+ containerEl: this .$el ,
205+ getInstance : () => this .device ,
206+ setEditorWidth: this .setDeviceEditorWidth ,
207+ defaultWidth: DRAWER_DEFAULT_WIDTH
208+ })
209+ })
210+ .then (() => {
211+ this .bindDrawerResizer ({
212+ component: this .$refs .resizeTarget ,
213+ initialWidth: DRAWER_DEFAULT_WIDTH ,
214+ minWidth: DRAWER_MIN_WIDTH ,
215+ maxViewportMarginX: DRAWER_MAX_VIEWPORT_MARGIN ,
216+ maxWidthRatio: DRAWER_MAX_WIDTH_RATIO
217+ })
218+ })
219+ .catch (err => err)
220+ .finally (() => {
221+ this .runInitialTease ()
222+ })
100223 },
101224 methods: {
102225 ... mapActions (' context' , { setContextDevice: ' setDevice' }),
@@ -105,7 +228,6 @@ export default {
105228 this .device = await deviceApi .getDevice (this .$route .params .id )
106229 } catch (err) {
107230 if (err .status === 403 ) {
108- clearTimeout (this .openTunnelTimeout )
109231 return this .$router .push ({ name: ' Home' })
110232 }
111233 } finally {
0 commit comments