mysqlsyncr 1.0.15 → 1.0.16
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.
- package/package.json +5 -1
- package/src/apply.js +35 -8
- package/src/socketServer.js +50 -0
- package/ui/dist/spa/assets/{MainLayout-BrvvhLBC.js → MainLayout-CGvO4rsY.js} +1 -1
- package/ui/dist/spa/assets/{axios-CbBgW735.js → axios-CrRsmKCW.js} +1 -1
- package/ui/dist/spa/assets/{index-DbZFTc3Z.css → index-767_aev0.css} +1 -1
- package/ui/dist/spa/assets/index-8ohClfZU.js +30 -0
- package/ui/dist/spa/index.html +2 -2
- package/ui/src/components/FolderBrowser.vue +194 -0
- package/ui/src/pages/MainComponent.vue +35 -1
- package/ui/dist/spa/assets/index-Bgaq8Ay7.js +0 -30
package/ui/dist/spa/index.html
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><title>MySQLsyncr</title><meta charset=utf-8><meta name=description content="A simple ui for the sync features in mysqlsyncr"><meta name=format-detection content="telephone=no"><meta name=msapplication-tap-highlight content=no><meta name=viewport content="user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1,width=device-width"><link rel=icon type=image/png sizes=128x128 href=/icons/favicon-128x128.png><link rel=icon type=image/png sizes=96x96 href=/icons/favicon-96x96.png><link rel=icon type=image/png sizes=32x32 href=/icons/favicon-32x32.png><link rel=icon type=image/png sizes=16x16 href=/icons/favicon-16x16.png><link rel=icon type=image/ico href=/favicon.ico> <script type="module" crossorigin src="/assets/index-
|
|
2
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
1
|
+
<!DOCTYPE html><html><head><title>MySQLsyncr</title><meta charset=utf-8><meta name=description content="A simple ui for the sync features in mysqlsyncr"><meta name=format-detection content="telephone=no"><meta name=msapplication-tap-highlight content=no><meta name=viewport content="user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1,width=device-width"><link rel=icon type=image/png sizes=128x128 href=/icons/favicon-128x128.png><link rel=icon type=image/png sizes=96x96 href=/icons/favicon-96x96.png><link rel=icon type=image/png sizes=32x32 href=/icons/favicon-32x32.png><link rel=icon type=image/png sizes=16x16 href=/icons/favicon-16x16.png><link rel=icon type=image/ico href=/favicon.ico> <script type="module" crossorigin src="/assets/index-8ohClfZU.js"></script>
|
|
2
|
+
<link rel="stylesheet" crossorigin href="/assets/index-767_aev0.css">
|
|
3
3
|
</head><body><div id=q-app></div></body></html>
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<q-dialog v-model="isOpen" persistent>
|
|
3
|
+
<q-card class="folder-browser-card">
|
|
4
|
+
<q-card-section class="header-section row items-center justify-between">
|
|
5
|
+
<div class="text-h6">Select Folder</div>
|
|
6
|
+
<q-btn icon="close" flat round dense v-close-popup />
|
|
7
|
+
</q-card-section>
|
|
8
|
+
|
|
9
|
+
<q-card-section>
|
|
10
|
+
<div class="path-section">
|
|
11
|
+
<div class="text-subtitle2 q-mb-sm">Current Path:</div>
|
|
12
|
+
<q-input
|
|
13
|
+
v-model="currentPath"
|
|
14
|
+
dense
|
|
15
|
+
readonly
|
|
16
|
+
filled
|
|
17
|
+
class="current-path-input"
|
|
18
|
+
bg-color="grey-2"
|
|
19
|
+
>
|
|
20
|
+
<template v-slot:prepend>
|
|
21
|
+
<q-icon name="folder" color="primary" />
|
|
22
|
+
</template>
|
|
23
|
+
</q-input>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<q-list bordered separator class="directory-list">
|
|
27
|
+
<q-item
|
|
28
|
+
v-for="item in sortedItems"
|
|
29
|
+
:key="item.path"
|
|
30
|
+
clickable
|
|
31
|
+
v-ripple
|
|
32
|
+
@click="item.isDirectory ? navigateToFolder(item.path) : null"
|
|
33
|
+
class="directory-item"
|
|
34
|
+
>
|
|
35
|
+
<q-item-section avatar>
|
|
36
|
+
<q-icon
|
|
37
|
+
:name="getItemIcon(item)"
|
|
38
|
+
:color="getItemColor(item)"
|
|
39
|
+
size="sm"
|
|
40
|
+
/>
|
|
41
|
+
</q-item-section>
|
|
42
|
+
<q-item-section>
|
|
43
|
+
{{ item.name }}
|
|
44
|
+
</q-item-section>
|
|
45
|
+
<q-item-section side v-if="item.isDirectory">
|
|
46
|
+
<q-icon name="chevron_right" color="grey-6" size="xs" />
|
|
47
|
+
</q-item-section>
|
|
48
|
+
</q-item>
|
|
49
|
+
</q-list>
|
|
50
|
+
</q-card-section>
|
|
51
|
+
|
|
52
|
+
<q-card-actions align="right" class="action-buttons">
|
|
53
|
+
<q-btn
|
|
54
|
+
flat
|
|
55
|
+
label="Cancel"
|
|
56
|
+
color="grey-7"
|
|
57
|
+
v-close-popup
|
|
58
|
+
class="q-px-md"
|
|
59
|
+
/>
|
|
60
|
+
<q-btn
|
|
61
|
+
unelevated
|
|
62
|
+
label="Select"
|
|
63
|
+
color="primary"
|
|
64
|
+
@click="selectCurrentFolder"
|
|
65
|
+
class="q-px-md q-ml-sm"
|
|
66
|
+
/>
|
|
67
|
+
</q-card-actions>
|
|
68
|
+
</q-card>
|
|
69
|
+
</q-dialog>
|
|
70
|
+
</template>
|
|
71
|
+
|
|
72
|
+
<script>
|
|
73
|
+
import axios from 'axios';
|
|
74
|
+
|
|
75
|
+
export default {
|
|
76
|
+
name: 'FolderBrowser',
|
|
77
|
+
props: {
|
|
78
|
+
modelValue: {
|
|
79
|
+
type: Boolean,
|
|
80
|
+
required: true
|
|
81
|
+
},
|
|
82
|
+
initialPath: {
|
|
83
|
+
type: String,
|
|
84
|
+
default: ''
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
data() {
|
|
88
|
+
return {
|
|
89
|
+
currentPath: '',
|
|
90
|
+
items: []
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
computed: {
|
|
94
|
+
isOpen: {
|
|
95
|
+
get() {
|
|
96
|
+
return this.modelValue
|
|
97
|
+
},
|
|
98
|
+
set(value) {
|
|
99
|
+
this.$emit('update:modelValue', value)
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
sortedItems() {
|
|
103
|
+
return this.items;
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
methods: {
|
|
107
|
+
async navigateToFolder(folderPath) {
|
|
108
|
+
await this.loadFolderContents(folderPath);
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
async loadFolderContents(path) {
|
|
112
|
+
try {
|
|
113
|
+
const response = await axios.post('http://localhost:3000/api/browse-folders', {
|
|
114
|
+
currentPath: path
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (response.data) {
|
|
118
|
+
this.currentPath = response.data.currentPath;
|
|
119
|
+
this.items = response.data.items || [];
|
|
120
|
+
}
|
|
121
|
+
} catch (error) {
|
|
122
|
+
console.error('Error loading folder contents:', error);
|
|
123
|
+
this.$q.notify({
|
|
124
|
+
type: 'negative',
|
|
125
|
+
message: 'Error loading folder contents'
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
selectCurrentFolder() {
|
|
131
|
+
this.$emit('folder-selected', this.currentPath);
|
|
132
|
+
this.isOpen = false;
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
getItemIcon(item) {
|
|
136
|
+
if (item.isParent) return 'reply';
|
|
137
|
+
if (item.isDirectory) return 'folder';
|
|
138
|
+
return 'insert_drive_file';
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
getItemColor(item) {
|
|
142
|
+
if (item.isParent) return 'grey-7';
|
|
143
|
+
if (item.isDirectory) return 'primary';
|
|
144
|
+
return 'grey-6';
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
async mounted() {
|
|
148
|
+
await this.loadFolderContents(this.initialPath || process.cwd());
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
</script>
|
|
152
|
+
|
|
153
|
+
<style scoped>
|
|
154
|
+
.folder-browser-card {
|
|
155
|
+
min-width: 450px;
|
|
156
|
+
max-width: 700px;
|
|
157
|
+
border-radius: 8px;
|
|
158
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.header-section {
|
|
162
|
+
background-color: #f5f5f5;
|
|
163
|
+
border-bottom: 1px solid #e0e0e0;
|
|
164
|
+
padding: 12px 20px;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.path-section {
|
|
168
|
+
margin-bottom: 20px;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.current-path-input {
|
|
172
|
+
font-family: monospace;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.directory-list {
|
|
176
|
+
max-height: 400px;
|
|
177
|
+
overflow-y: auto;
|
|
178
|
+
border-radius: 4px;
|
|
179
|
+
border: 1px solid #e0e0e0;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.directory-item {
|
|
183
|
+
transition: background-color 0.2s;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.directory-item:hover {
|
|
187
|
+
background-color: #f0f4f8;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.action-buttons {
|
|
191
|
+
padding: 16px;
|
|
192
|
+
border-top: 1px solid #e0e0e0;
|
|
193
|
+
}
|
|
194
|
+
</style>
|
|
@@ -200,7 +200,6 @@
|
|
|
200
200
|
<q-input
|
|
201
201
|
v-model="dbFolder"
|
|
202
202
|
label="Database Folder"
|
|
203
|
-
|
|
204
203
|
default="db-dump"
|
|
205
204
|
filled
|
|
206
205
|
class="q-mb-md"
|
|
@@ -209,6 +208,16 @@
|
|
|
209
208
|
<template v-slot:prepend>
|
|
210
209
|
<q-icon name="folder" />
|
|
211
210
|
</template>
|
|
211
|
+
<template v-slot:append>
|
|
212
|
+
<q-btn
|
|
213
|
+
flat
|
|
214
|
+
dense
|
|
215
|
+
icon="folder_open"
|
|
216
|
+
@click="showFolderBrowser = true"
|
|
217
|
+
>
|
|
218
|
+
<q-tooltip>Browse</q-tooltip>
|
|
219
|
+
</q-btn>
|
|
220
|
+
</template>
|
|
212
221
|
</q-input>
|
|
213
222
|
</div>
|
|
214
223
|
</div>
|
|
@@ -374,13 +383,24 @@
|
|
|
374
383
|
</q-card-actions>
|
|
375
384
|
</q-card>
|
|
376
385
|
</q-dialog>
|
|
386
|
+
|
|
387
|
+
<FolderBrowser v-if="showFolderBrowser"
|
|
388
|
+
v-model="showFolderBrowser"
|
|
389
|
+
:initial-path="dbFolder"
|
|
390
|
+
@folder-selected="onFolderSelected"
|
|
391
|
+
/>
|
|
377
392
|
</q-page>
|
|
378
393
|
</template>
|
|
379
394
|
|
|
380
395
|
<script>
|
|
381
396
|
import axios from 'axios'
|
|
397
|
+
import FolderBrowser from '../components/FolderBrowser.vue'
|
|
398
|
+
|
|
382
399
|
|
|
383
400
|
export default {
|
|
401
|
+
components: {
|
|
402
|
+
FolderBrowser
|
|
403
|
+
},
|
|
384
404
|
data() {
|
|
385
405
|
return {
|
|
386
406
|
isDbSetup: false,
|
|
@@ -407,6 +427,7 @@ export default {
|
|
|
407
427
|
selectedIssues: [],
|
|
408
428
|
selectedNode: null,
|
|
409
429
|
isNodeFixing: {}, // Tracks loading state for each node
|
|
430
|
+
showFolderBrowser: false,
|
|
410
431
|
}
|
|
411
432
|
},
|
|
412
433
|
methods: {
|
|
@@ -989,6 +1010,19 @@ export default {
|
|
|
989
1010
|
this.isApplying = false
|
|
990
1011
|
}
|
|
991
1012
|
},
|
|
1013
|
+
onFolderSelected(path) {
|
|
1014
|
+
this.dbFolder = path;
|
|
1015
|
+
// If you want to save the setting immediately
|
|
1016
|
+
const dbConfig = {
|
|
1017
|
+
host: this.host,
|
|
1018
|
+
port: this.port,
|
|
1019
|
+
user: this.user,
|
|
1020
|
+
password: this.password,
|
|
1021
|
+
database: this.database,
|
|
1022
|
+
output: this.dbFolder,
|
|
1023
|
+
}
|
|
1024
|
+
localStorage.setItem('dbConfig', JSON.stringify(dbConfig));
|
|
1025
|
+
},
|
|
992
1026
|
},
|
|
993
1027
|
mounted() {
|
|
994
1028
|
const dbConfig = localStorage.getItem('dbConfig')
|