Skip to content

Commit

Permalink
✨ feature/#29 - Auto sync (#31)
Browse files Browse the repository at this point in the history
- Add auto sync delay in settings
- Add server conflict check
  • Loading branch information
loicngr authored Feb 23, 2024
1 parent 9693dfb commit 6a8381d
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 5 deletions.
71 changes: 69 additions & 2 deletions src/components/ListNotesView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@
</add-button>

<reload-button
:last-reload="lastReload"
@click="getFileContent()"
>
<template #tooltip>
Expand Down Expand Up @@ -227,8 +228,12 @@ import { useI18n } from 'vue-i18n'
import { keyBy } from 'lodash'
import DialogColorPicker from 'components/DialogColorPicker.vue'
import { useSortable } from '@vueuse/integrations/useSortable'
import { useSettingsStore } from 'stores/settings'
import { storeToRefs } from 'pinia'
import { useIntervalFn } from '@vueuse/core'
const mainStore = useMainStore()
const settingsStore = useSettingsStore()
const $q = useQuasar()
const {
t,
Expand Down Expand Up @@ -280,10 +285,28 @@ const editor = reactive({
const listRef = ref<InstanceType<typeof HTMLElement> | null>(null)
const popup = ref<boolean>(false)
const notes = ref<Item[]>([])
const lastReload = ref<string | undefined>(undefined)
const baseNotes = ref<Item[]>([])
const file = ref<{ items: Item[] }>({
items: [],
})
const {
autoSyncInterval,
} = storeToRefs(settingsStore)
const {
resume,
} = useIntervalFn(
() => {
void getFileContent()
},
autoSyncInterval.value,
{
immediate: false,
},
)
const popupEditStyle = ref({
height: '80vh',
minHeight: '1200px',
Expand Down Expand Up @@ -418,7 +441,18 @@ function createNewText () {
}
}
async function getFileContent () {
function hasConflict (_newNotes: Item[]) {
const newNotes = cloneDeep(_newNotes)
const currentNotes = cloneDeep(baseNotes.value)
if (currentNotes.length === 0) {
return false
}
return !isEqual(newNotes, currentNotes)
}
async function getFileContent (checkConflict = true) {
Loading.show()
try {
Expand All @@ -436,8 +470,21 @@ async function getFileContent () {
return
}
if (checkConflict && hasConflict(JSON.parse(textFileContent).items ?? [])) {
// TODO (https://github.com/loicngr/kdrive-notes/issues/30)
Notify.create({
message: t('conflictDetected'),
type: 'negative',
})
Loading.hide()
return
}
file.value = JSON.parse(textFileContent)
baseNotes.value = cloneDeep(file.value.items ?? [])
lastReload.value = (new Date()).toString()
} catch (e) {
console.error(e)
}
Expand Down Expand Up @@ -482,6 +529,24 @@ function onSave () {
const base = keyBy(cloneDeep(baseNotes.value), 'id')
const dateNow = new Date()
let serverFileContent = await API.getFileContent() as string
serverFileContent = serverFileContent.trim()
if (hasConflict(JSON.parse(serverFileContent).items ?? [])) {
Notify.create({
message: t('conflictDetected'),
type: 'warning',
})
Loading.hide()
await dialogConfirm(t('confirmConflictServer'))
.catch(() => {
throw new Error('Skip save')
})
Loading.show()
}
actual.forEach((i) => {
if (
typeof base[i.id] !== 'undefined' &&
Expand All @@ -496,7 +561,7 @@ function onSave () {
}))
if (status) {
await getFileContent()
await getFileContent(false)
}
Loading.hide()
Expand All @@ -513,6 +578,8 @@ function openColorDialog (item: Item) {
async function main () {
await getFileContent()
resume()
}
await main()
Expand Down
18 changes: 18 additions & 0 deletions src/components/ReloadButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,30 @@
class="absolute"
style="bottom: -5px; left: -2px;"
/>

<q-badge
v-if="typeof lastReload !== 'undefined'"
:label="dateTimeShortFormat(lastReload)"
color="white"
text-color="primary"
class="absolute"
style="top: -20px; left: -15px; font-size: 9px;"
/>
</template>
</q-btn>
</template>

<script setup lang="ts">
import { dateTimeShortFormat } from 'src/utils/date'
withDefaults(
defineProps<{
lastReload?: string
}>(),
{
lastReload: undefined,
},
)
</script>

<style scoped>
Expand Down
42 changes: 40 additions & 2 deletions src/components/SettingsView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,32 @@
</q-icon>
</template>
</hidden-input>

<q-input
v-model.number="autoSync"
type="number"
:label="`${$t('autoSyncInterval')} *`"
:rules="[$rules.required, $rules.validAutoSyncDuration]"
lazy-rules
class="col-12 col-md-6 error-white"
input-class="text-white"
filled
label-color="white"
color="white"
step="1"
:suffix="$t('minutes').toLowerCase()"
>
<template #append>
<q-icon
name="fa fa-circle-info"
color="white"
>
<q-tooltip>
{{ $t('autoSyncIntervalInfo') }}
</q-tooltip>
</q-icon>
</template>
</q-input>
</q-form>
</q-card-section>
</q-card>
Expand Down Expand Up @@ -176,6 +202,7 @@

<script setup lang="ts">
import {
DEFAULT_AUTO_SYNC,
type DEFAULT_WEBDAV_STATE,
useSettingsStore,
} from 'stores/settings'
Expand All @@ -185,8 +212,10 @@ import {
ref,
} from 'vue'
import {
Notify, openURL,
QForm, useQuasar,
Notify,
openURL,
QForm,
useQuasar,
} from 'quasar'
import { storeToRefs } from 'pinia'
import cloneDeep from 'lodash/fp/cloneDeep'
Expand All @@ -205,10 +234,12 @@ const {
const {
webdav,
language: storeLanguage,
autoSync: storeAutoSync,
} = storeToRefs(settingsStore)
const webDAV = ref<typeof DEFAULT_WEBDAV_STATE>(cloneDeep(webdav.value))
const language = ref<string>(cloneDeep(storeLanguage.value))
const autoSync = ref<number>(cloneDeep(storeAutoSync.value))
const formRef = ref<InstanceType<typeof QForm> | null>(null)
Expand Down Expand Up @@ -239,6 +270,12 @@ async function onSubmit () {
webdav.value = cloneDeep(webDAV.value)
storeLanguage.value = cloneDeep(language.value)
if (autoSync.value < DEFAULT_AUTO_SYNC) {
autoSync.value = cloneDeep(DEFAULT_AUTO_SYNC)
}
storeAutoSync.value = cloneDeep(autoSync.value)
void nextTick(() => {
Notify.create({
message: t('settingsSave'),
Expand Down Expand Up @@ -274,6 +311,7 @@ function testGooglePlayConsole () {
onBeforeMount(async () => {
webDAV.value = cloneDeep(webdav.value)
language.value = cloneDeep(storeLanguage.value)
autoSync.value = cloneDeep(storeAutoSync.value)
})
</script>

Expand Down
9 changes: 9 additions & 0 deletions src/i18n/en-US/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ export default {
save: 'Save',
reset: 'Reset',
confirmSave: 'Do you want save',
confirmConflictServer: 'Do you want to overwrite the server version with your own?',
notingToSave: 'No changes',
options: 'Options',
selectNewFileType: 'Select new file type',
filename: 'Filename',
fileEmptyOrInvalid: 'File is empty, or format is invalid',
conflictDetected: 'Conflict with server notes detected',

createNewFile: 'Create a new file',
text: 'Text',
Expand All @@ -30,6 +32,7 @@ export default {

notValid: 'Not valid',
notValidID: 'Not valid kDrive ID',
notValidAutoSyncDuration: 'Delay too short',
notValidEmail: 'Not valid email',
required: 'Required',
tooSmall: 'Too small',
Expand All @@ -39,6 +42,8 @@ export default {
content: 'Content',
id: 'ID',
add: 'Add',
milliseconds: 'Milliseconds',
minutes: 'Minutes',
reload: 'Reload',
notes: 'Notes',
delete: 'Delete',
Expand All @@ -48,6 +53,10 @@ export default {
password: 'Password',
email: 'Email',
folder: 'Folder',
autoSyncInterval: 'Time delay auto sync',
autoSyncIntervalInfo: `You can set the time interval between automatic synchronization of your notes`,
autoSync: 'Auto sync',
duration: 'Duration',
infomaniakConnectViaWebDAV: 'Infomaniak connect to kDrive via WebDAV',
needSupport: `Support`,
gotToPage: 'Go to {name} page',
Expand Down
9 changes: 9 additions & 0 deletions src/i18n/fr-FR/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ export default {
save: 'Sauvegarder',
reset: 'Réinitialiser',
confirmSave: 'Voulez-vous sauvegarder',
confirmConflictServer: 'Voulez-vous remplacer la version du serveur par la vôtre ?',
notingToSave: 'Aucun changement',
options: 'Options',
selectNewFileType: 'Sélectionner le type du fichier',
filename: 'Nom du fichier',
fileEmptyOrInvalid: `Le fichier est vide ou le format n'est pas valide`,
conflictDetected: `Conflit avec les notes du serveur détecté`,

createNewFile: 'Créer un nouveau fichier',
text: 'Text',
Expand All @@ -30,6 +32,7 @@ export default {

notValid: 'Non valide',
notValidID: 'ID kDrive non valide',
notValidAutoSyncDuration: 'Délai trop court',
notValidEmail: 'Email non valide',
required: 'Requis',
tooSmall: 'Trop petit',
Expand All @@ -39,6 +42,8 @@ export default {
content: 'Contenu',
id: 'ID',
add: 'Ajouter',
milliseconds: 'Millisecondes',
minutes: 'Minutes',
reload: 'Recharger',
notes: 'Notes',
delete: 'Supprimer',
Expand All @@ -48,6 +53,10 @@ export default {
password: 'Mot de passe',
email: 'Email',
folder: 'Dossier',
autoSyncInterval: 'Délai sync. automatique',
autoSyncIntervalInfo: `Vous pouvez définir l'intervalle de temps entre la synchronisation automatique de vos notes`,
autoSync: 'Synchronisation automatique',
duration: 'Durée',
infomaniakConnectViaWebDAV: 'Infomaniak se connecte à kDrive via WebDAV',
needSupport: `Aide`,
gotToPage: 'Aller à la page {name}',
Expand Down
9 changes: 9 additions & 0 deletions src/stores/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ export const DEFAULT_WEBDAV_STATE: {
customServer: undefined,
}

export const DEFAULT_AUTO_SYNC: number = 5

export interface State {
webdav: typeof DEFAULT_WEBDAV_STATE
language: string,
autoSync: number,
}

export const useSettingsStore = defineStore({
Expand All @@ -27,9 +30,14 @@ export const useSettingsStore = defineStore({
state: (): State => ({
webdav: cloneDeep(DEFAULT_WEBDAV_STATE),
language: 'en-US',
autoSync: cloneDeep(DEFAULT_AUTO_SYNC),
}),

getters: {
autoSyncInterval (): number {
return this.autoSync * 60 * 1000
},

isWebDAVValid (): boolean {
const webDAV = this.webdav ?? {}

Expand All @@ -53,6 +61,7 @@ export const useSettingsStore = defineStore({
paths: [
'webdav',
'language',
'autoSync',
],
},
],
Expand Down
4 changes: 4 additions & 0 deletions src/utils/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,7 @@ export function dateFormat (d: string) {
export function dateTimeFormat (d: string) {
return formatDate(parseIso(d), 'YYYY/MM/DD HH:mm:ss')
}

export function dateTimeShortFormat (d: string) {
return formatDate(parseIso(d), 'YYYY/MM/DD HH:mm')
}
Loading

0 comments on commit 6a8381d

Please sign in to comment.