Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Delete Profile Modal by separating it from Profiles.vue #1325

Merged
merged 4 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions src/components/profiles-modals/DeleteProfileModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator';
import { ModalCard } from "../all";
import R2Error from "../../model/errors/R2Error";

@Component({
components: {ModalCard}
})
export default class DeleteProfileModal extends Vue {
get isOpen(): boolean {
return this.$store.state.modals.isDeleteProfileModalOpen;
}

get profileList(): string[] {
return this.$store.state.profiles.profileList;
}

closeDeleteProfileModal() {
this.$store.commit('closeDeleteProfileModal');
}

async removeProfile() {
try {
await this.$store.dispatch('profiles/removeSelectedProfile');
} catch (e) {
const err = R2Error.fromThrownValue(e, 'Error whilst deleting profile');
this.$store.commit('error/handleError', err);
}
this.closeDeleteProfileModal();
}
}

</script>
<template>
<ModalCard v-if="isOpen" :is-active="isOpen" @close-modal="closeDeleteProfileModal">

<template v-slot:header>
<p class="modal-card-title">Delete profile</p>
</template>
<template v-slot:body>
<p>This will remove all mods, and their config files, installed within this profile.</p>
<p>If this was an accident, click either the darkened area, or the cross inside located in the top right.</p>
<p>Are you sure you'd like to delete this profile?</p>
</template>
<template v-slot:footer>
<button
class="button is-danger"
@click="removeProfile()"
>Delete profile</button>
</template>

</ModalCard>
</template>
94 changes: 26 additions & 68 deletions src/pages/Profiles.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<template>
<div>
<DeleteProfileModal />
<!-- Create modal -->
<div :class="['modal', {'is-active':(addingProfile !== false || renamingProfile !== false)}]">
<div class="modal-background" @click="closeNewProfileModal()"></div>
Expand Down Expand Up @@ -119,30 +120,6 @@
</div>
<button class="modal-close is-large" aria-label="close" @click="showCodeModal = false;"></button>
</div>
<!-- Delete modal -->
<div :class="['modal', {'is-active':(removingProfile !== false)}]">
<div class="modal-background" @click="closeRemoveProfileModal()"></div>
<div class="modal-content">
<div class="card">
<header class="card-header">
<p class="card-header-title">Delete profile</p>
</header>
<div class="card-content">
<p>This will remove all mods, and their config files, installed within this profile.</p>
<p>If this was an accident, click either the darkened area, or the cross inside located in the top right.</p>
<p>Are you sure you'd like to delete this profile?</p>
</div>
<div class="card-footer">
<button
id="modal-delete-profile"
class="button is-danger"
@click="removeProfileAfterConfirmation()"
>Delete profile</button>
</div>
</div>
</div>
<button class="modal-close is-large" aria-label="close" @click="closeRemoveProfileModal()"></button>
</div>
<!-- Import modal -->
<div :class="['modal', {'is-active':(importingProfile !== false)}]">
<div class="modal-background"></div>
Expand Down Expand Up @@ -218,7 +195,7 @@
<a id="import-profile" class="button" @click="showImportUpdateSelectionModal = true; importUpdateSelection = null;">Import / Update</a>
</div>
<div class="level-item">
<a id="delete-profile" class="button is-danger" @click="removeProfile()">Delete</a>
<a class="button is-danger" @click="openDeleteProfileModal()">Delete</a>
</div>
</nav>
</div>
Expand Down Expand Up @@ -262,26 +239,25 @@ import InteractionProvider from '../providers/ror2/system/InteractionProvider';
import ManagerInformation from '../_managerinf/ManagerInformation';
import GameDirectoryResolverProvider from '../providers/ror2/game/GameDirectoryResolverProvider';
import { ProfileImportExport } from '../r2mm/mods/ProfileImportExport';
import DeleteProfileModal from "../components/profiles-modals/DeleteProfileModal.vue";

let fs: FsProvider;

@Component({
components: {
hero: Hero,
'progress-bar': Progress
}
'progress-bar': Progress,
DeleteProfileModal,
},
})
export default class Profiles extends Vue {
@Ref() readonly profileCodeInput: HTMLInputElement | undefined;
@Ref() readonly profileNameInput: HTMLInputElement | undefined;

private profileList: string[] = ['Default'];

private addingProfile: boolean = false;
private newProfileName: string = '';
private addingProfileType: string = 'Create';

private removingProfile: boolean = false;
private importingProfile: boolean = false;
private percentageImported: number = 0;

Expand All @@ -304,6 +280,10 @@ export default class Profiles extends Vue {
return this.$store.getters['profile/activeProfileName'];
}

get profileList(): string[] {
return this.$store.state.profiles.profileList;
}

async setSelectedProfile(profileName: string, prewarmCache = true) {
try {
await this.$store.dispatch('profile/updateActiveProfile', profileName);
Expand Down Expand Up @@ -382,7 +362,7 @@ export default class Profiles extends Vue {
if (safeName === '') {
return;
}
this.profileList.push(safeName);
this.$store.commit('profiles/setProfileList', [...this.profileList, safeName].sort());
await this.setSelectedProfile(safeName);
this.addingProfile = false;
document.dispatchEvent(new CustomEvent("created-profile", {detail: safeName}));
Expand All @@ -399,36 +379,8 @@ export default class Profiles extends Vue {
this.renamingProfile = false;
}

removeProfile() {
this.removingProfile = true;
}

async removeProfileAfterConfirmation() {
try {
await FileUtils.emptyDirectory(this.activeProfile.getPathOfProfile());
await fs.rmdir(this.activeProfile.getPathOfProfile());
} catch (e) {
const err = R2Error.fromThrownValue(e, 'Error whilst deleting profile');
this.$store.commit('error/handleError', err);
}
if (
this.activeProfile
.getProfileName()
.toLowerCase() !== 'default'
) {
for (let profileIteration = 0; profileIteration < this.profileList.length; profileIteration++) {
if (this.profileList[profileIteration] === this.activeProfile.getProfileName()) {
this.profileList.splice(profileIteration, 1);
break;
}
}
}
await this.setSelectedProfile('Default');
anttimaki marked this conversation as resolved.
Show resolved Hide resolved
this.closeRemoveProfileModal();
}

closeRemoveProfileModal() {
this.removingProfile = false;
openDeleteProfileModal() {
this.$store.commit('openDeleteProfileModal');
}

makeProfileNameSafe(nameToSanitize: string): string {
Expand Down Expand Up @@ -652,15 +604,21 @@ export default class Profiles extends Vue {
}

async updateProfileList() {
this.profileList = ["Default"];
const profilesDirectory: string = this.activeProfile.getDirectory();
await fs.readdir(profilesDirectory).then(dirContents => {
dirContents.forEach(async (file: string) => {
anttimaki marked this conversation as resolved.
Show resolved Hide resolved
if ((await fs.stat(path.join(profilesDirectory, file))).isDirectory() && file.toLowerCase() !== 'default' && file.toLowerCase() !== "_profile_update") {
this.profileList = [...this.profileList, file].sort();
}

try {
const profilesDirectoryContents = await fs.readdir(profilesDirectory);
let promises = profilesDirectoryContents.map(async function(file) {
return ((await fs.stat(path.join(profilesDirectory, file))).isDirectory() && file.toLowerCase() !== 'default' && file.toLowerCase() !== "_profile_update")
? file : undefined;
});
}).catch(() => { /* Do nothing */ });
anttimaki marked this conversation as resolved.
Show resolved Hide resolved
Promise.all(promises).then((profileList) => {
this.$store.commit('profiles/setProfileList', ["Default", ...profileList.filter(file => file)].sort());
})
} catch (e) {
const err = R2Error.fromThrownValue(e, 'Error whilst updating ProfileList');
this.$store.commit('error/handleError', err);
}
}

async created() {
Expand Down
2 changes: 2 additions & 0 deletions src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import ErrorModule from './modules/ErrorModule';
import ModalsModule from './modules/ModalsModule';
import ModFilterModule from './modules/ModFilterModule';
import ProfileModule from './modules/ProfileModule';
import { ProfilesModule } from './modules/ProfilesModule';
import { TsModsModule } from './modules/TsModsModule';
import { FolderMigration } from '../migrations/FolderMigration';
import Game from '../model/game/Game';
Expand Down Expand Up @@ -104,6 +105,7 @@ export const store = {
modals: ModalsModule,
modFilters: ModFilterModule,
profile: ProfileModule,
profiles: ProfilesModule,
tsMods: TsModsModule,
},

Expand Down
10 changes: 10 additions & 0 deletions src/store/modules/ModalsModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ interface State {
downloadModModalMod: ThunderstoreMod | null;
isAssociatedModsModOpen: boolean;
isCategoryFilterModalOpen: boolean;
isDeleteProfileModalOpen: boolean;
isDisableModModalOpen: boolean;
isDownloadModModalOpen: boolean;
isGameRunningModalOpen: boolean;
Expand All @@ -21,6 +22,7 @@ export default {
downloadModModalMod: null,
isAssociatedModsModOpen: false,
isCategoryFilterModalOpen: false,
isDeleteProfileModalOpen: false,
isDisableModModalOpen: false,
isDownloadModModalOpen: false,
isGameRunningModalOpen: false,
Expand All @@ -38,6 +40,10 @@ export default {
state.isCategoryFilterModalOpen = false;
},

closeDeleteProfileModal: function(state: State): void {
state.isDeleteProfileModalOpen = false;
},

closeDisableModModal: function(state: State): void {
state.isDisableModModalOpen = false;
state.disableModModalMod = null;
Expand Down Expand Up @@ -66,6 +72,10 @@ export default {
state.isCategoryFilterModalOpen = true;
},

openDeleteProfileModal: function(state: State): void {
state.isDeleteProfileModalOpen = true;
},

openDisableModModal: function(state: State, mod: ManifestV2): void {
state.disableModModalMod = mod;
state.isDisableModModalOpen = true;
Expand Down
52 changes: 52 additions & 0 deletions src/store/modules/ProfilesModule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import FileUtils from "../../utils/FileUtils";
import R2Error from "../../model/errors/R2Error";
import { ActionTree } from "vuex";
import { State as RootState } from "../../store";
import Profile from "../../model/Profile";
import FsProvider from "../../providers/generic/file/FsProvider";

interface State {
profileList: string[];
}

/**
* State for Profiles, i.e. list for profiles in a single game/community.
*/
export const ProfilesModule = {
namespaced: true,

state: (): State => ({
profileList: ['Default'],
}),
mutations: {
setProfileList(state: State, profileList: string[]) {
state.profileList = profileList;
},
},
actions: <ActionTree<State, RootState>>{
async removeSelectedProfile({rootGetters, state, dispatch}) {
const activeProfile: Profile = rootGetters['profile/activeProfile'];
const path = activeProfile.getPathOfProfile();
const profileName = activeProfile.getProfileName();

try {
anttimaki marked this conversation as resolved.
Show resolved Hide resolved
await FileUtils.emptyDirectory(path);
await FsProvider.instance.rmdir(path);
} catch (e) {
throw R2Error.fromThrownValue(e, 'Error whilst deleting profile from disk');
}

state.profileList = state.profileList.filter((p: string) => p !== profileName ||p === 'Default')
await dispatch('setSelectedProfile', { profileName: 'Default', prewarmCache: true });
},

async setSelectedProfile({rootGetters, state, dispatch}, params: { profileName: string, prewarmCache: boolean }) {
await dispatch('profile/updateActiveProfile', params.profileName, { root: true });

if (params.prewarmCache) {
await dispatch('profile/updateModListFromFile', null, { root: true });
await dispatch('tsMods/prewarmCache', null, { root: true });
}
},
},
}
Loading