Skip to content

Commit

Permalink
Merge pull request #1254 from rommapp/feature/enable-config-exclusion…
Browse files Browse the repository at this point in the history
…s-from-UI

feat: Enable editable exclusions from webUI
  • Loading branch information
zurdi15 authored Oct 25, 2024
2 parents c6cf605 + 8b11bff commit 373757e
Show file tree
Hide file tree
Showing 11 changed files with 253 additions and 110 deletions.
6 changes: 6 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@
"type": "shell",
"command": "export $(cat .env | grep DB_ROOT_PASSWD | xargs) && docker exec -i mariadb mariadb -u root -p$DB_ROOT_PASSWD < backend/romm_test/setup.sql",
"problemMatcher": []
},
{
"label": "Launch full stack",
"dependsOn": ["Launch frontend", "Launch backend", "Launch worker"],
"problemMatcher": [],
"dependsOrder": "parallel"
}
]
}
24 changes: 14 additions & 10 deletions backend/config/config_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ def update_config_file(self) -> None:
def add_platform_binding(self, fs_slug: str, slug: str) -> None:
platform_bindings = self.config.PLATFORMS_BINDING
if fs_slug in platform_bindings:
log.warn(f"Binding for {fs_slug} already exists")
log.warning(f"Binding for {fs_slug} already exists")
return

platform_bindings[fs_slug] = slug
Expand All @@ -291,7 +291,7 @@ def remove_platform_binding(self, fs_slug: str) -> None:
def add_platform_version(self, fs_slug: str, slug: str) -> None:
platform_versions = self.config.PLATFORMS_VERSIONS
if fs_slug in platform_versions:
log.warn(f"Version for {fs_slug} already exists")
log.warning(f"Version for {fs_slug} already exists")
return

platform_versions[fs_slug] = slug
Expand All @@ -309,21 +309,25 @@ def remove_platform_version(self, fs_slug: str) -> None:
self.config.PLATFORMS_VERSIONS = platform_versions
self.update_config_file()

def add_exclusion(self, config_key: str, exclusion: str):
config_item = self.config.__getattribute__(config_key)
config_item.append(exclusion)
self.config.__setattr__(config_key, config_item)
def add_exclusion(self, exclusion_type: str, exclusion_value: str):
config_item = self.config.__getattribute__(exclusion_type)
if exclusion_value in config_item:
log.warning(f"{exclusion_value} already excluded in {exclusion_type}")
return

config_item.append(exclusion_value)
self.config.__setattr__(exclusion_type, config_item)
self.update_config_file()

def remove_exclusion(self, config_key: str, exclusion: str):
config_item = self.config.__getattribute__(config_key)
def remove_exclusion(self, exclusion_type: str, exclusion_value: str):
config_item = self.config.__getattribute__(exclusion_type)

try:
config_item.remove(exclusion)
config_item.remove(exclusion_value)
except ValueError:
pass

self.config.__setattr__(config_key, config_item)
self.config.__setattr__(exclusion_type, config_item)
self.update_config_file()


Expand Down
51 changes: 35 additions & 16 deletions backend/endpoints/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,25 +116,44 @@ async def delete_platform_version(request: Request, fs_slug: str) -> MessageResp
return {"msg": f"{fs_slug} version removed successfully!"}


# @protected_route(router.post, "/config/exclude", [Scope.PLATFORMS_WRITE])
# async def add_exclusion(request: Request) -> MessageResponse:
# """Add platform binding to the configuration"""
@protected_route(router.post, "/config/exclude", [Scope.PLATFORMS_WRITE])
async def add_exclusion(request: Request) -> MessageResponse:
"""Add platform exclusion to the configuration"""

# data = await request.json()
# exclude = data['exclude']
# exclusion = data['exclusion']
# cm.add_exclusion(exclude, exclusion)
data = await request.json()
exclusion_value = data["exclusion_value"]
exclusion_type = data["exclusion_type"]
try:
cm.add_exclusion(exclusion_type, exclusion_value)
except ConfigNotWritableException as exc:
log.critical(exc.message)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=exc.message
) from exc

# return {"msg": f"Exclusion {exclusion} added to {exclude} successfully!"}
return {
"msg": f"Exclusion {exclusion_value} added to {exclusion_type} successfully!"
}


# @protected_route(router.delete, "/config/exclude", [Scope.PLATFORMS_WRITE])
# async def delete_exclusion(request: Request) -> MessageResponse:
# """Delete platform binding from the configuration"""
@protected_route(
router.delete,
"/config/exclude/{exclusion_type}/{exclusion_value}",
[Scope.PLATFORMS_WRITE],
)
async def delete_exclusion(
request: Request, exclusion_type: str, exclusion_value: str
) -> MessageResponse:
"""Delete platform binding from the configuration"""

# data = await request.json()
# exclude = data['exclude']
# exclusion = data['exclusion']
# cm.remove_exclusion(exclude, exclusion)
try:
cm.remove_exclusion(exclusion_type, exclusion_value)
except ConfigNotWritableException as exc:
log.critical(exc.message)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=exc.message
) from exc

# return {"msg": f"Exclusion {exclusion} removed from {exclude} successfully!"}
return {
"msg": f"Exclusion {exclusion_value} removed from {exclusion_type} successfully!"
}
115 changes: 66 additions & 49 deletions frontend/src/components/Management/Dialog/CreateExclusion.vue
Original file line number Diff line number Diff line change
@@ -1,80 +1,97 @@
<script setup lang="ts">
import RDialog from "@/components/common/RDialog.vue";
import configApi from "@/services/api/config";
import type { Events } from "@/types/emitter";
import type { Emitter } from "mitt";
import storeConfig from "@/stores/config";
import { inject, ref } from "vue";
import { useDisplay } from "vuetify";
// Props
const { mdAndUp, smAndDown } = useDisplay();
const show = ref(false);
const emitter = inject<Emitter<Events>>("emitter");
const excludeToCreate = ref();
const exclusionToCreate = ref();
emitter?.on("showCreateExclusionDialog", ({ exclude }) => {
excludeToCreate.value = exclude;
const configStore = storeConfig();
const exclusionValue = ref();
const exclusionType = ref();
const exclusionIcon = ref();
const exclusionTitle = ref();
emitter?.on("showCreateExclusionDialog", ({ type, icon, title }) => {
exclusionType.value = type;
exclusionIcon.value = icon;
exclusionTitle.value = title;
show.value = true;
});
// Functions
function addExclusion() {
configApi.addExclusion({
exclude: excludeToCreate.value,
exclusion: exclusionToCreate.value,
});
// configStore.addExclusion(exclusion);
closeDialog();
if (configStore.isExclusionType(exclusionType.value)) {
configApi.addExclusion({
exclusionValue: exclusionValue.value,
exclusionType: exclusionType.value,
});
configStore.addExclusion(exclusionType.value, exclusionValue.value);
closeDialog();
} else {
console.error(`Invalid exclusion type '${exclusionType.value}'`);
}
}
function closeDialog() {
show.value = false;
exclusionValue.value = "";
}
</script>
<template>
<!-- TODO: unify refactor dialog -->
<v-dialog v-model="show" max-width="500px" :scrim="true">
<v-card>
<v-toolbar density="compact" class="bg-terciary">
<v-row class="align-center" no-gutters>
<v-col cols="10">
<v-icon icon="mdi-controller" class="ml-5" />
<v-icon icon="mdi-menu-right" class="ml-1 text-romm-gray" />
<v-icon icon="mdi-controller" class="ml-1 text-romm-accent-1" />
</v-col>
<v-col>
<v-btn
class="bg-terciary"
rounded="0"
variant="text"
icon="mdi-close"
block
@click="closeDialog"
/>
</v-col>
</v-row>
</v-toolbar>
<v-divider />

<v-card-text>
<v-row class="pa-2 align-center" no-gutters>
<v-icon icon="mdi-menu-right" class="mx-2 text-romm-gray" />
<r-dialog
@close="closeDialog"
v-model="show"
icon="mdi-cancel"
:width="mdAndUp ? '45vw' : '95vw'"
>
<template #content>
<v-row v-if="smAndDown" no-gutters>
<v-col class="mt-2 py-2 text-center">
<v-icon :icon="exclusionIcon" />
<span class="ml-2">{{ exclusionTitle }}</span>
</v-col>
</v-row>
<v-row class="align-center py-2 px-4" no-gutters>
<v-col v-if="mdAndUp" class="text-center" cols="2">
<div>
<v-icon :icon="exclusionIcon" />
</div>
<div class="mt-2">
<span class="ml-2">{{ exclusionTitle }}</span>
</div>
</v-col>
<v-col>
<v-text-field
v-model="exclusionToCreate"
class="text-romm-accent-1"
label="RomM platform"
color="romm-accent-1"
base-color="romm-accent-1"
v-model="exclusionValue"
class="py-2"
:class="{ 'ml-4': mdAndUp }"
variant="outlined"
required
hide-details
@keyup.enter="addExclusion"
/>
</v-row>
<v-row class="justify-center pa-2" no-gutters>
</v-col>
</v-row>
</template>
<template #append>
<v-row class="justify-center mb-2" no-gutters>
<v-btn-group divided density="compact">
<v-btn class="bg-terciary" @click="closeDialog"> Cancel </v-btn>
<v-btn class="text-romm-green bg-terciary ml-5" @click="addExclusion">
<v-btn
class="bg-terciary text-romm-green"
:disabled="exclusionValue == ''"
:variant="exclusionValue == '' ? 'plain' : 'flat'"
@click="addExclusion"
>
Confirm
</v-btn>
</v-row>
</v-card-text>
</v-card>
</v-dialog>
</v-btn-group>
</v-row>
</template>
</r-dialog>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function addVersionPlatform() {
})
.then(() => {
if (selectedPlatform.value) {
configStore.addPlatformBinding(
configStore.addPlatformVersion(
fsSlugToCreate.value,
selectedPlatform.value.slug,
);
Expand Down
46 changes: 40 additions & 6 deletions frontend/src/components/Management/ExcludedCard.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
<script setup lang="ts">
import configApi from "@/services/api/config";
import storeConfig from "@/stores/config";
import type { Events } from "@/types/emitter";
import type { Emitter } from "mitt";
import { inject } from "vue";
// Props
const emitter = inject<Emitter<Events>>("emitter");
defineProps<{
const props = defineProps<{
set: string[];
editable: boolean;
title: string;
emit: string;
icon?: string;
type: string;
icon: string;
}>();
const configStore = storeConfig();
// Functions
function removeExclusion(exclusionValue: string) {
if (configStore.isExclusionType(props.type)) {
configApi.deleteExclusion({
exclusionValue: exclusionValue,
exclusionType: props.type,
});
configStore.removeExclusion(exclusionValue, props.type);
} else {
console.error(`Invalid exclusion type '${props.type}'`);
}
}
</script>
<template>
<v-card rounded="0" color="terciary">
Expand All @@ -21,8 +37,24 @@ defineProps<{
>
<v-divider />
<v-card-text class="pa-2">
<v-chip v-for="excluded in set" :key="excluded" label class="ma-1">
{{ excluded }}
<v-chip
v-for="exclusionValue in set"
:key="exclusionValue"
label
class="ma-1"
>
<span>{{ exclusionValue }}</span>
<v-slide-x-reverse-transition>
<v-btn
v-if="editable"
rounded="0"
variant="text"
size="x-small"
icon="mdi-delete"
class="text-romm-red ml-1"
@click="removeExclusion(exclusionValue)"
/>
</v-slide-x-reverse-transition>
</v-chip>
<v-expand-transition>
<v-btn
Expand All @@ -33,7 +65,9 @@ defineProps<{
class="text-romm-accent-1 ml-1"
@click="
emitter?.emit('showCreateExclusionDialog', {
exclude: emit,
type: type,
icon: icon,
title: title,
})
"
>
Expand Down
Loading

0 comments on commit 373757e

Please sign in to comment.