mirror of
https://github.com/HangarMC/Hangar.git
synced 2024-11-21 01:21:54 +08:00
fix several issues with channels
Fix ChannelModal to disable the save button if nothing has changed Fix saving with no changes throwing an error
This commit is contained in:
parent
b1020a3907
commit
7f5f36a38f
@ -62,6 +62,7 @@ public class ChannelController extends HangarComponent {
|
||||
this.channelService.checkColor(projectId, color, existingColor);
|
||||
}
|
||||
|
||||
// @el(author: String, slug: String)
|
||||
@Anyone
|
||||
@VisibilityRequired(type = VisibilityRequired.Type.PROJECT, args = "{#author, #slug}")
|
||||
@GetMapping(path = "/{author}/{slug}", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ -75,7 +76,7 @@ public class ChannelController extends HangarComponent {
|
||||
@RateLimit(overdraft = 5, refillTokens = 1, refillSeconds = 15)
|
||||
@PermissionRequired(type = PermissionType.PROJECT, perms = NamedPermission.EDIT_CHANNEL, args = "{#projectId}")
|
||||
@PostMapping(path = "/{projectId}/create", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
public void createChannel(@PathVariable final long projectId, @RequestBody @Valid final ChannelForm channelForm) {
|
||||
public void createChannel(@PathVariable final long projectId, @RequestBody final @Valid ChannelForm channelForm) {
|
||||
final Set<ChannelFlag> flags = channelForm.getFlags();
|
||||
flags.retainAll(flags.stream().filter(ChannelFlag::isEditable).collect(Collectors.toSet()));
|
||||
this.channelService.createProjectChannel(channelForm.getName(), channelForm.getColor(), projectId, flags);
|
||||
@ -86,9 +87,9 @@ public class ChannelController extends HangarComponent {
|
||||
@RateLimit(overdraft = 5, refillTokens = 1, refillSeconds = 15)
|
||||
@PermissionRequired(type = PermissionType.PROJECT, perms = NamedPermission.EDIT_CHANNEL, args = "{#projectId}")
|
||||
@PostMapping(path = "/{projectId}/edit", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
public void editChannel(@PathVariable final long projectId, @RequestBody @Valid final EditChannelForm channelForm) {
|
||||
public void editChannel(@PathVariable final long projectId, @RequestBody final @Valid EditChannelForm channelForm) {
|
||||
final Set<ChannelFlag> flags = channelForm.getFlags();
|
||||
flags.retainAll(flags.stream().filter(ChannelFlag::isEditable).collect(Collectors.toSet()));
|
||||
flags.retainAll(ChannelFlag.EDITABLE);
|
||||
this.channelService.editProjectChannel(channelForm.getId(), channelForm.getName(), channelForm.getColor(), projectId, flags);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
package io.papermc.hangar.model.common;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.jdbi.v3.core.enums.EnumByOrdinal;
|
||||
|
||||
@EnumByOrdinal
|
||||
@ -11,6 +14,9 @@ public enum ChannelFlag {
|
||||
PINNED(true, true),
|
||||
;
|
||||
|
||||
public static final Set<ChannelFlag> EDITABLE = Arrays.stream(values()).filter(ChannelFlag::isEditable).collect(Collectors.toUnmodifiableSet());
|
||||
public static final Set<ChannelFlag> ALWAYS_EDITABLE = Arrays.stream(values()).filter(ChannelFlag::isAlwaysEditable).collect(Collectors.toUnmodifiableSet());
|
||||
|
||||
private final boolean editable;
|
||||
private final boolean alwaysEditable;
|
||||
|
||||
|
@ -10,6 +10,7 @@ import io.papermc.hangar.model.db.projects.ProjectChannelTable;
|
||||
import io.papermc.hangar.model.internal.logs.LogAction;
|
||||
import io.papermc.hangar.model.internal.logs.contexts.ProjectContext;
|
||||
import io.papermc.hangar.model.internal.projects.HangarChannel;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.LongFunction;
|
||||
@ -79,32 +80,35 @@ public class ChannelService extends HangarComponent {
|
||||
}
|
||||
|
||||
if (projectChannelTable.getFlags().contains(ChannelFlag.FROZEN)) {
|
||||
// Allow changing of certain flags
|
||||
boolean updated = false;
|
||||
final String old = formatChannelChange(projectChannelTable);
|
||||
for (final ChannelFlag flag : ChannelFlag.values()) {
|
||||
if (!flag.isAlwaysEditable()) {
|
||||
continue;
|
||||
final Iterator<ChannelFlag> currentIter = projectChannelTable.getFlags().iterator();
|
||||
while (currentIter.hasNext()) {
|
||||
final ChannelFlag existingFlag = currentIter.next();
|
||||
if (existingFlag == ChannelFlag.FROZEN) continue;
|
||||
if (!flags.contains(existingFlag)) {
|
||||
if (!existingFlag.isAlwaysEditable()) {
|
||||
throw new HangarApiException(HttpStatus.BAD_REQUEST, "channel.modal.error.cannotEdit");
|
||||
}
|
||||
|
||||
final boolean added = flags.contains(flag);
|
||||
if (added != projectChannelTable.getFlags().contains(flag)) {
|
||||
updated = true;
|
||||
if (added) {
|
||||
projectChannelTable.getFlags().add(flag);
|
||||
currentIter.remove();
|
||||
} else {
|
||||
projectChannelTable.getFlags().remove(flag);
|
||||
flags.remove(existingFlag);
|
||||
}
|
||||
}
|
||||
for (final ChannelFlag newFlag : flags) { // should be all "new" flags here
|
||||
if (!newFlag.isAlwaysEditable()) {
|
||||
throw new HangarApiException(HttpStatus.BAD_REQUEST, "channel.modal.error.cannotEdit");
|
||||
}
|
||||
projectChannelTable.getFlags().add(newFlag);
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
final String old = formatChannelChange(projectChannelTable);
|
||||
this.projectChannelsDAO.update(projectChannelTable);
|
||||
this.actionLogger.project(LogAction.PROJECT_CHANNEL_EDITED.create(ProjectContext.of(projectId), formatChannelChange(projectChannelTable), old));
|
||||
return;
|
||||
}
|
||||
|
||||
throw new HangarApiException(HttpStatus.BAD_REQUEST, "channel.modal.error.cannotEdit");
|
||||
return;
|
||||
}
|
||||
|
||||
this.validateChannel(name, color, projectId, this.projectChannelsDAO.getProjectChannels(projectId).stream().filter(ch -> ch.getId() != channelId).collect(Collectors.toList()));
|
||||
|
@ -7,7 +7,7 @@ import Button from "~/lib/components/design/Button.vue";
|
||||
import Modal from "~/lib/components/modals/Modal.vue";
|
||||
import { useBackendData } from "~/store/backendData";
|
||||
import InputText from "~/lib/components/ui/InputText.vue";
|
||||
import { required } from "~/lib/composables/useValidationHelpers";
|
||||
import { isSame, required } from "~/lib/composables/useValidationHelpers";
|
||||
import { validChannelName, validChannelColor } from "~/composables/useHangarValidations";
|
||||
import InputCheckbox from "~/lib/components/ui/InputCheckbox.vue";
|
||||
import { ChannelFlag } from "~/types/enums";
|
||||
@ -52,6 +52,10 @@ const swatches = computed<string[][]>(() => {
|
||||
return result;
|
||||
});
|
||||
|
||||
const noChange = computed(() => {
|
||||
return props.channel?.name === name.value && props.channel.color === color.value && isSame(props.channel.flags, flags.value);
|
||||
});
|
||||
|
||||
async function create(close: () => void) {
|
||||
if (!(await v.value.$validate())) return;
|
||||
close();
|
||||
@ -113,7 +117,7 @@ reset();
|
||||
</div>
|
||||
<InputCheckbox v-for="f in possibleFlags" :key="f" v-model="flags" :label="i18n.t(`channel.modal.flags.${f.toLowerCase()}`)" :value="f" />
|
||||
|
||||
<Button class="mt-3" :disabled="v.$invalid" @click="create(on.click)">{{ edit ? i18n.t("general.save") : i18n.t("general.create") }}</Button>
|
||||
<Button class="mt-3" :disabled="noChange || v.$invalid" @click="create(on.click)">{{ edit ? i18n.t("general.save") : i18n.t("general.create") }}</Button>
|
||||
</template>
|
||||
<template #activator="{ on }">
|
||||
<slot name="activator" :on="open(on)"></slot>
|
||||
|
@ -19,7 +19,7 @@ import { AsyncData } from "nuxt/app";
|
||||
import { ComputedRef, Ref } from "vue";
|
||||
import { NuxtApp } from "@nuxt/schema";
|
||||
import { useApi, useInternalApi } from "~/composables/useApi";
|
||||
import { ref, useAsyncData } from "#imports";
|
||||
import { ref, useAsyncData, createError } from "#imports";
|
||||
import { handleRequestError } from "~/composables/useErrorHandling";
|
||||
|
||||
export type NonNullAsyncData<T, E = unknown> = { data: Ref<T> } & Pick<AsyncData<T, E>, "pending" | "refresh" | "execute" | "error">;
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit f12bfd193a1a63b56a85775e3dd65473e864c46e
|
||||
Subproject commit aa36bb66e4fb2802ae674938c8080974bc8cdabf
|
@ -577,6 +577,7 @@
|
||||
"duplicateName": "This project already has a channel with this name",
|
||||
"tooLongName": "Channel name is too long",
|
||||
"cannotDelete": "You cannot delete this channel",
|
||||
"cannotEdit": "You cannot edit this channel",
|
||||
"invalidFlag": "You tried to set an invalid channel flag"
|
||||
},
|
||||
"success": {
|
||||
|
Loading…
Reference in New Issue
Block a user