mysqlsyncr 1.0.12 → 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.
@@ -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-C4-Ja7SU.js"></script>
2
- <link rel="stylesheet" crossorigin href="/assets/index-DbZFTc3Z.css">
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>
@@ -124,6 +124,7 @@
124
124
  <q-input
125
125
  v-model="host"
126
126
  label="Database Host"
127
+ default="127.0.0.1"
127
128
  filled
128
129
  class="q-mb-md"
129
130
  required
@@ -138,6 +139,7 @@
138
139
  <q-input
139
140
  v-model="port"
140
141
  label="Database Port"
142
+ default="3306"
141
143
  type="number"
142
144
  filled
143
145
  class="q-mb-md"
@@ -153,6 +155,7 @@
153
155
  <q-input
154
156
  v-model="user"
155
157
  label="Database User"
158
+ default="root"
156
159
  filled
157
160
  class="q-mb-md"
158
161
  required
@@ -197,6 +200,7 @@
197
200
  <q-input
198
201
  v-model="dbFolder"
199
202
  label="Database Folder"
203
+ default="db-dump"
200
204
  filled
201
205
  class="q-mb-md"
202
206
  required
@@ -204,6 +208,16 @@
204
208
  <template v-slot:prepend>
205
209
  <q-icon name="folder" />
206
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>
207
221
  </q-input>
208
222
  </div>
209
223
  </div>
@@ -369,13 +383,24 @@
369
383
  </q-card-actions>
370
384
  </q-card>
371
385
  </q-dialog>
386
+
387
+ <FolderBrowser v-if="showFolderBrowser"
388
+ v-model="showFolderBrowser"
389
+ :initial-path="dbFolder"
390
+ @folder-selected="onFolderSelected"
391
+ />
372
392
  </q-page>
373
393
  </template>
374
394
 
375
395
  <script>
376
396
  import axios from 'axios'
397
+ import FolderBrowser from '../components/FolderBrowser.vue'
398
+
377
399
 
378
400
  export default {
401
+ components: {
402
+ FolderBrowser
403
+ },
379
404
  data() {
380
405
  return {
381
406
  isDbSetup: false,
@@ -402,6 +427,7 @@ export default {
402
427
  selectedIssues: [],
403
428
  selectedNode: null,
404
429
  isNodeFixing: {}, // Tracks loading state for each node
430
+ showFolderBrowser: false,
405
431
  }
406
432
  },
407
433
  methods: {
@@ -423,7 +449,8 @@ export default {
423
449
  localStorage.setItem('dbConfig', JSON.stringify(dbConfig))
424
450
  this.isDbSetup = true
425
451
  this.closeSettings()
426
- this.refreshDifferences()
452
+ this.getDatabasesFromExistingDumps()
453
+ this.fetchAllDifferences()
427
454
  },
428
455
  async refreshDifferences() {
429
456
  if (!this.isDbSetup) return
@@ -983,6 +1010,19 @@ export default {
983
1010
  this.isApplying = false
984
1011
  }
985
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
+ },
986
1026
  },
987
1027
  mounted() {
988
1028
  const dbConfig = localStorage.getItem('dbConfig')