0.1.6 - DEV - 4

This commit is contained in:
Elvanos 2021-04-27 17:13:46 +02:00
parent 5687f047f0
commit 14834a6a54
10 changed files with 348 additions and 29 deletions

View file

@ -83,6 +83,12 @@
@trigger-dialog-close="licenseDialogClose"
/>
<!-- Repair project dialog -->
<repairProjectDialog
:dialog-trigger="repairProjectDialogTrigger"
@trigger-dialog-close="repairProjectDialogClose"
/>
<q-btn-group
flat
class="AppControl__buttons"
@ -237,6 +243,35 @@
<q-separator dark />
<q-item clickable>
<q-item-section>Advanced project tools</q-item-section>
<q-item-section avatar>
<q-icon name="keyboard_arrow_right" />
</q-item-section>
<q-menu anchor="top end" self="top start">
<q-list class="bg-gunmetal text-accent">
<q-item
v-close-popup
clickable
active
active-class="bg-gunmetal-light text-cultured"
class="noHigh"
@click="repairProjectAssignUID"
:disable="!projectExists"
>
<q-item-section>Repair legacy project</q-item-section>
<q-item-section avatar>
<q-icon name="mdi-folder-open-outline" />
</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-item>
<q-separator dark />
<q-item
v-close-popup
clickable
@ -424,6 +459,7 @@ import keybindCheatsheetDialog from "src/components/dialogs/KeybindCheatsheet.vu
import importProjectCheckDialog from "src/components/dialogs/ImportProjectCheck.vue"
import mergeProjectCheckDialog from "src/components/dialogs/MergeProjectCheck.vue"
import newProjectCheckDialog from "src/components/dialogs/NewProjectCheck.vue"
import repairProjectDialog from "src/components/dialogs/RepairProject.vue"
import aboutAppDialog from "src/components/dialogs/AboutApp.vue"
import changeLogDialog from "src/components/dialogs/ChangeLog.vue"
import programSettingsDialog from "src/components/dialogs/ProgramSettings.vue"
@ -453,7 +489,8 @@ import appLogo from "src/assets/appLogo.png"
newDocumentDialog,
existingDocumentDialog,
tipsTricksTriviaDialog,
licenseDialog
licenseDialog,
repairProjectDialog
}
})
export default class AppControl extends BaseClass {
@ -726,6 +763,19 @@ export default class AppControl extends BaseClass {
licenseAssignUID () {
this.licenseDialogTrigger = this.generateUID()
}
/****************************************************************/
// Repair project dialog
/****************************************************************/
repairProjectDialogTrigger: string | false = false
repairProjectDialogClose () {
this.repairProjectDialogTrigger = false
}
repairProjectAssignUID () {
this.repairProjectDialogTrigger = this.generateUID()
}
}
</script>

View file

@ -314,7 +314,7 @@
Prevent auto-scrolling
<q-icon name="mdi-help-circle" size="16px" class="q-ml-md">
<q-tooltip :delay="500">
Determines if the documents will recall their scroll distances and auto-scroll on switching ot not.
Determines if the documents will recall their scroll distances and auto-scroll on switching or not.
</q-tooltip>
</q-icon>
</div>

View file

@ -0,0 +1,259 @@
<template>
<q-dialog
v-model="dialogModel"
@hide="triggerDialogClose"
no-route-dismiss
:persistent="repairOngoing || repairFinished"
>
<q-card v-if="!repairOngoing && !repairFinished" dark class="documentCloseDialog">
<q-card-section class="row justify-center">
<h6 class="text-center q-my-sm">Repair legacy project</h6>
</q-card-section>
<q-card-section class="row justify-center q-mx-xl">
<div>
If you are working with project created (or added via Merge) before version 0.1.6, this process might significantly improve your performance.
<br>
<br>
However, before proceeding, please export your current project first to prevent a <span class="text-bold text-secondary">POSSIBLE CORRUPTION</span> of your current project data!
</div>
</q-card-section>
<q-card-actions align="around" class="q-mx-xl q-mt-lg q-mb-md">
<q-btn
flat
label="Cancel"
color="accent"
v-close-popup />
<q-btn
flat
label="Export project"
color="primary"
@click="commenceExport"
/>
<q-btn
flat
label="Repair project"
color="primary"
v-close-popup
@click="repairProject" />
</q-card-actions>
</q-card>
<q-card v-if="repairOngoing && !repairFinished" dark class="documentCloseDialog">
<q-card-section class="row justify-center">
<h6 class="text-center q-my-sm">Repairing...</h6>
</q-card-section>
<q-card-section class="row justify-center q-mx-xl">
<div>
<b>Processing document types: <span class="text-primary">{{processedBlueprints}}/{{blueprintCount}}</span></b>
</div>
</q-card-section>
<q-card-section class="row justify-center q-mx-xl">
<div>
<b><span class="text-primary">{{currectDocumentType}}</span></b>
</div>
</q-card-section>
<q-card-section class="row justify-center q-mx-xl q-mb-lg">
<q-linear-progress stripe round dark size="20px" :value="progressCounter" color="primary" class="q-mt-sm">
<div class="absolute-full flex flex-center">
<q-badge text-color="accent" color="dark" :label="`${processedDocument}/${documentCount}`" />
</div>
</q-linear-progress>
</q-card-section>
</q-card>
<q-card v-if="!repairOngoing && repairFinished" dark class="documentCloseDialog">
<q-card-section class="row justify-center">
<h6 class="text-center q-my-sm">Project succesfully repaired!</h6>
</q-card-section>
<q-card-actions align="around" class="q-mx-xl q-mt-lg q-mb-md">
<q-btn
flat
label="Reload Fantasia Archive"
color="primary"
v-close-popup
@click="reloadFA" />
</q-card-actions>
</q-card>
</q-dialog>
</template>
<script lang="ts">
import { remote } from "electron"
import { Component, Watch } from "vue-property-decorator"
import DialogBase from "src/components/dialogs/_DialogBase"
import { retrieveCurrentProjectName, exportProject } from "src/scripts/projectManagement/projectManagent"
import { Loading, QSpinnerGears } from "quasar"
import { I_ShortenedDocument } from "src/interfaces/I_OpenedDocument"
import { I_Blueprint } from "src/interfaces/I_Blueprint"
@Component({
components: { }
})
export default class RepairProjectDialog extends DialogBase {
/**
* React to dialog opening request
*/
@Watch("dialogTrigger")
checkForOpenedProject (val: string|false) {
if (val) {
this.openDialog()
}
}
/**
* Open the the dialog if project is present on the window
*/
openDialog () {
if (this.SGET_getDialogsState) {
return
}
this.repairOngoing = false
this.repairFinished = false
this.SSET_setDialogState(true)
this.dialogModel = true
}
processedBlueprints = 0
blueprintCount = 0
processedDocument = 0
documentCount = 0
currectDocumentType = ""
get progressCounter () {
return (this.processedDocument / this.documentCount)
}
repairFinished = false
repairOngoing = false
/**
* Repair a new project
*/
async repairProject () {
this.repairOngoing = true
this.processedBlueprints = 0
this.blueprintCount = this.SGET_allBlueprints.length
for (const blueprint of this.SGET_allBlueprints) {
this.processedBlueprints++
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
const dbRows = await window.FA_dbs[blueprint._id].allDocs({ include_docs: true })
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
// eslint-disable-next-line
const dbDocuments = dbRows.rows.map((d:any) => d.doc)
this.documentCount = dbDocuments.length
this.processedDocument = 0
this.currectDocumentType = blueprint.namePlural
await this.sleep(800)
for (let document of dbDocuments) {
document = await this.remapDocument(document, blueprint)
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
await window.FA_dbs[blueprint._id].put(document)
}
await this.sleep(600)
}
this.repairOngoing = false
this.repairFinished = true
}
async remapDocument (document: I_ShortenedDocument, blueprint: I_Blueprint) {
const allSingleToNoneFields = blueprint.extraFields.filter(e => e.type === "singleToNoneRelationship")
const allSingleToSingleFields = blueprint.extraFields.filter(e => e.type === "singleToSingleRelationship")
const allSingleToManyFields = blueprint.extraFields.filter(e => e.type === "singleToManyRelationship")
const allManyToNoneFields = blueprint.extraFields.filter(e => e.type === "manyToNoneRelationship")
const allManyToSingleFields = blueprint.extraFields.filter(e => e.type === "manyToSingleRelationship")
const allManyToManyFields = blueprint.extraFields.filter(e => e.type === "manyToManyRelationship")
for (const field of document.extraFields) {
// Single field remap
if (allSingleToNoneFields.find(e => e.id === field.id) ||
allSingleToSingleFields.find(e => e.id === field.id) ||
allSingleToManyFields.find(e => e.id === field.id)) {
if (field.value && field.value.value) {
const blueprintField = blueprint.extraFields.find(e => e.id === field.id)
field.value.value = {
_id: field.value.value._id,
id: field.value.value._id,
type: field.value.value.type,
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
url: `/project/display-content/${field.value.value.type}/${field.value.value._id}`,
pairedField: (blueprintField?.relationshipSettings?.connectedField) || ""
}
}
}
// Many field remap
if (allManyToNoneFields.find(e => e.id === field.id) ||
allManyToSingleFields.find(e => e.id === field.id) ||
allManyToManyFields.find(e => e.id === field.id)) {
if (field.value && field.value.value) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
for (const [i, subValue] of field.value.value.entries()) {
const blueprintField = blueprint.extraFields.find(e => e.id === field.id)
field.value.value[i] = {
_id: subValue._id,
id: subValue._id,
type: subValue.type,
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
url: `/project/display-content/${subValue.type}/${subValue._id}`,
pairedField: (blueprintField?.relationshipSettings?.connectedField) || ""
}
}
}
}
}
this.processedDocument++
await this.sleep(25)
return document
}
reloadFA () {
remote.getCurrentWindow().reload()
}
/**
* Export the current project
*/
async commenceExport () {
const projectName = await retrieveCurrentProjectName()
const setup = {
message: "<h4>Exporting current project...</h4>",
spinnerColor: "primary",
messageColor: "cultured",
spinnerSize: 120,
backgroundColor: "dark",
// @ts-ignore
spinner: QSpinnerGears
}
exportProject(projectName, Loading, setup, this.$q)
}
}
</script>
<style lang="scss" scoped>
.documentCloseDialog {
min-width: 600px;
}
</style>

View file

@ -479,10 +479,11 @@ export default class Field_MultiRelationship extends FieldBase {
* Also reload the local object list
*/
@Watch("inputDataValue", { deep: true, immediate: true })
reactToInputChanges () {
this.localInput = (this.inputDataValue?.value) ? this.inputDataValue.value : []
reactToInputChanges (val : I_RelationshipPair) {
const localCopy: I_RelationshipPair = extend(true, {}, val)
this.localInput = (localCopy?.value) ? localCopy.value : []
const notes = (!this.inputDataValue?.addedValues) ? [] : this.inputDataValue.addedValues
const notes = (!localCopy?.addedValues) ? [] : localCopy.addedValues
this.inputNotes = notes.filter(single => this.localInput.find(e => single.pairedId === e._id))
this.checkNotes()
@ -615,30 +616,41 @@ export default class Field_MultiRelationship extends FieldBase {
// Do a quick check on formatting of the current input (if something is wrong with it, set it as empty array)
this.localInput = (Array.isArray(this.localInput)) ? this.localInput : []
this.localInput.forEach((s, index) => {
const toRemoveIndexList: number[] = []
for (const [index] of this.localInput.entries()) {
// Proceed only if the local input is properly set up
if (s._id) {
if (this.localInput[index]._id) {
// If the matched object doesn't exist in the object, assume it has been deleted or newer existed and silently emit a signal input which auto-updates the document
if (!allDbObjects.docs.find(e => e._id === s._id)) {
// @ts-ignore
this.localInput.splice(index, 1)
if (!allDbObjects.docs.find(e => e._id === this.localInput[index]._id)) {
allDbObjects.docs.forEach(e => {
if (e._id === this.localInput[index]._id) {
console.log(extend(true, {}, this.localInput[index]))
console.log(extend(true, {}, e))
}
})
toRemoveIndexList.push(index)
}
// If the object does exist, make sure we have the newest available name by reasigning the label if it is different. Then trigger a silent update
else {
const matchedFieldContent = allDbObjects.docs.find(e => e._id === s._id)
if (matchedFieldContent && (
this.localInput[index].label !== matchedFieldContent.label ||
this.localInput[index]?.isDead !== matchedFieldContent.extraFields.find(e => e.id === "deadSwitch")?.value)
) {
const matchedFieldContent = allDbObjects.docs.find(e => e._id === this.localInput[index]._id)
if (matchedFieldContent) {
this.localInput[index].label = matchedFieldContent.label
this.localInput[index].isDead = matchedFieldContent.extraFields.find(e => e.id === "deadSwitch")?.value
}
}
}
})
}
this.allTypeDocuments = allDbObjects.docs
if (toRemoveIndexList.length > 0) {
toRemoveIndexList.forEach((e, i) => {
this.localInput.splice(i, 1)
})
this.signalInput(true)
}
}
}
@ -692,7 +704,7 @@ export default class Field_MultiRelationship extends FieldBase {
* Signals the input change to the document body parent component
*/
@Emit()
signalInput () {
signalInput (isSilent = false) {
this.checkNotes()
this.inputNotes = this.inputNotes.filter(single => this.localInput.find(e => single.pairedId === e._id))
@ -706,7 +718,8 @@ export default class Field_MultiRelationship extends FieldBase {
pairedField: (this.inputDataBluePrint?.relationshipSettings?.connectedField) || ""
}
}),
addedValues: this.inputNotes
addedValues: this.inputNotes,
isSilent: isSilent
}
}

View file

@ -578,7 +578,6 @@ export default class Field_SingleRelationship extends FieldBase {
])]
}
})
// Proceed only if the local input is properly set up
if (this.localInput._id) {
// If the matched object doesn't exist in the object, assume it has been deleted or never existed

View file

@ -7,19 +7,18 @@
### Known issues
- POSSIBLY FIXED: When creating a brand new project, Fantasia Archive sometimes doesn't load the default categories in the left hierarchical tree. A temporary workaround before the issue is fixed is restarting the program - the project stays intact, can be normally edited and no data loss occurs.
- POSSIBLY FIXED: Some users report that dialog (popups) don't function the very first time you start FA. This is solved by restarting the application. The bug doesn't seem to appear again once FA has been started at least once before.
- Overusing Tags currently causes app crashes on some PCs. If you suffer from this issue, reduce the number of tags in your project below 10.
### Bugfixes & Optimizations
- Massive overhaul of how data is being handles across the app!
- **Massive overhaul of how data is being handles across the app!**
- Fixed buttons for moving list items up and down also showing outside of edit mode
- Fixed `Resume project` button working in instances where it shouldnt
- Fixed a visual bug in the top document control bar
- Added a check against invalid characters in new project name to prevent issues while exporting on different OSs
- Hopefully finally fixed the new project creation bugs that have been plaguing the app for last 3 releases
- Fixed app starting in mutliple windows when ran multiple times.
- FIxed more typos across the app
### New features

View file

@ -632,8 +632,7 @@ export default class PageDocumentDisplay extends BaseClass {
this.localDataCopy = extend(true, {}, this.currentData)
const dataPass = { doc: this.localDataCopy, treeAction: false }
// @ts-ignore
if (inputData.skipSave) {
this.currentData.extraFields[indexToUpdate].value.skipSave = false
if (inputData.isSilent) {
dataPass.doc.hasEdits = false
}

View file

@ -169,8 +169,6 @@ export const addFieldToDocument = async (targetDocumentID: string, fieldID: stri
targetDocument.extraFields.push(newField)
console.log(newField)
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
await window.FA_dbs[currentBlueprint._id].put(targetDocument)
}

View file

@ -47,6 +47,7 @@ export const createNewProject = async (projectName: string, vueRouter: any, quas
message: `New project succesfully created`
})
vueInstance.SSET_resetDocuments()
vueInstance.SSET_resetAllDocuments()
/* eslint-enable */
await ProjectDB.close()

View file

@ -14,6 +14,7 @@ const mutation: MutationTree<AllDocumentsStateInterface> = {
doc: I_ShortenedDocument,
}) {
const timestamp = uid()
const isCategory = input.doc.extraFields.find(e => e.id === "categorySwitch")?.value
// Docs
const toAddIndexDocs = state.docs.docs.findIndex(doc => doc.type === input.doc.type && doc._id === input.doc._id)
@ -24,7 +25,7 @@ const mutation: MutationTree<AllDocumentsStateInterface> = {
// Docs, no cat
const toAddIndexDocsWithoutCategory = state.docsWithoutCategories.docs.findIndex(doc => doc.type === input.doc.type && doc._id === input.doc._id)
if (toAddIndexDocsWithoutCategory < 0) {
if (toAddIndexDocsWithoutCategory < 0 && !isCategory) {
state.docsWithoutCategories.docs.push(input.doc)
state.docsWithoutCategories.timestamp = timestamp
}
@ -40,7 +41,7 @@ const mutation: MutationTree<AllDocumentsStateInterface> = {
// Docs each cat, no cat
const typeIndexWithoutCats = state.docbyTypeWithoutCategories.findIndex(type => type.id === input.doc.type)
const toAddTypeIndexDocsWithoutCats = state.docbyTypeWithoutCategories[typeIndexWithoutCats].docs.findIndex(doc => doc._id === input.doc._id)
if (toAddTypeIndexDocsWithoutCats < 0) {
if (toAddTypeIndexDocsWithoutCats < 0 && !isCategory) {
state.docbyTypeWithoutCategories[typeIndexWithoutCats].docs.push(input.doc)
state.docbyTypeWithoutCategories[typeIndex].timestamp = timestamp
}