feat: add edit command
This commit is contained in:
parent
8f3832657b
commit
6a9c69a535
@ -202,6 +202,15 @@ func (db *RemoteDatabase) GetCommands() ([]Command, error) {
|
|||||||
return commands, nil
|
return commands, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *RemoteDatabase) UpdateCommand(command Command) error {
|
||||||
|
queryString := "UPDATE Commands SET protocol = ?, commandNumber = ?, device = ?, commandType = ?, title = ? WHERE id = ?"
|
||||||
|
_, error := db.Connection.Exec(queryString, command.Protocol, command.CommandNumber, command.Device, command.CommandType, command.Title, command.Id)
|
||||||
|
if error != nil {
|
||||||
|
return fmt.Errorf("error updating command %s: %s", command.Id, error)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (db *RemoteDatabase) DeleteCommand(commandId string) error {
|
func (db *RemoteDatabase) DeleteCommand(commandId string) error {
|
||||||
queryString := "DELETE FROM Commands WHERE id = ?"
|
queryString := "DELETE FROM Commands WHERE id = ?"
|
||||||
_, error := db.Connection.Exec(queryString, commandId)
|
_, error := db.Connection.Exec(queryString, commandId)
|
||||||
|
|||||||
@ -49,6 +49,10 @@ func (rm *RemoteManager) GetCommands() ([]d.Command, error) {
|
|||||||
return rm.remoteDatabase.GetCommands()
|
return rm.remoteDatabase.GetCommands()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rm *RemoteManager) UpdateCommand(command d.Command) error {
|
||||||
|
return rm.remoteDatabase.UpdateCommand(command)
|
||||||
|
}
|
||||||
|
|
||||||
func (rm *RemoteManager) SetRemoteDatabase(remoteDatabase *d.RemoteDatabase) {
|
func (rm *RemoteManager) SetRemoteDatabase(remoteDatabase *d.RemoteDatabase) {
|
||||||
rm.remoteDatabase = remoteDatabase
|
rm.remoteDatabase = remoteDatabase
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,7 @@ func (r *RemoteApiHandler) Initialize(authenticator *Authenticator) {
|
|||||||
commandsApi := r.router.Group("/api/commands")
|
commandsApi := r.router.Group("/api/commands")
|
||||||
commandsApi.GET("", r.handleGetCommands)
|
commandsApi.GET("", r.handleGetCommands)
|
||||||
commandsApi.POST("", r.handleCreateCommands)
|
commandsApi.POST("", r.handleCreateCommands)
|
||||||
|
commandsApi.PUT("/:id", r.handleUpdateCommand)
|
||||||
commandsApi.DELETE("/:id", r.handleDeleteCommand)
|
commandsApi.DELETE("/:id", r.handleDeleteCommand)
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -97,6 +98,20 @@ func (r *RemoteApiHandler) handleGetCommands(context echo.Context) error {
|
|||||||
return context.JSON(200, commands)
|
return context.JSON(200, commands)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *RemoteApiHandler) handleUpdateCommand(context echo.Context) error {
|
||||||
|
command := d.Command{}
|
||||||
|
if err := context.Bind(&command); err != nil {
|
||||||
|
SendError(400, context, err.Error())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := r.remoteManager.UpdateCommand(command)
|
||||||
|
if err != nil {
|
||||||
|
SendError(500, context, err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return context.JSON(200, "")
|
||||||
|
}
|
||||||
|
|
||||||
func (r *RemoteApiHandler) handleDeleteCommand(context echo.Context) error {
|
func (r *RemoteApiHandler) handleDeleteCommand(context echo.Context) error {
|
||||||
id := context.Param("id")
|
id := context.Param("id")
|
||||||
err := r.remoteManager.DeleteCommand(id)
|
err := r.remoteManager.DeleteCommand(id)
|
||||||
|
|||||||
199
www/src/modals/edit-command-modal.jsx
Normal file
199
www/src/modals/edit-command-modal.jsx
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
import { createEffect, createMemo, createSignal } from "solid-js";
|
||||||
|
import ValidatedTextInput from "../components/validated-text-input.jsx";
|
||||||
|
import EventEmitter from "../tools/event-emitter.js";
|
||||||
|
import ModalHandler from "./modal-handler.js";
|
||||||
|
import Modal from "./modal.jsx";
|
||||||
|
import RemotesService from "../services/remotes-service.js";
|
||||||
|
import Command from "../data/command.js";
|
||||||
|
|
||||||
|
const eventEmitter = new EventEmitter();
|
||||||
|
const COMMAND_EDITED_EVENT = "success";
|
||||||
|
const MIN_TITLE_LENGTH = 3;
|
||||||
|
|
||||||
|
const [command, setCommand] = createSignal(new Command());
|
||||||
|
|
||||||
|
function EditCommandModal(props) {
|
||||||
|
const [protocol, setProtocol] = createSignal("");
|
||||||
|
const [commandNumber, setCommandNumber] = createSignal("");
|
||||||
|
const [device, setDevice] = createSignal("");
|
||||||
|
const [commandType, setCommandType] = createSignal("");
|
||||||
|
const [title, setTitle] = createSignal("");
|
||||||
|
const [error, setError] = createSignal("");
|
||||||
|
|
||||||
|
const isProtocolValid = createMemo(() => protocol() !== "");
|
||||||
|
const isCommandNumberValid = createMemo(
|
||||||
|
() => commandNumber() !== "" && !isNaN(commandNumber())
|
||||||
|
);
|
||||||
|
const isDeviceValid = createMemo(() => device() !== "" && !isNaN(device()));
|
||||||
|
const isCommandTypeValid = createMemo(() => commandType() !== "");
|
||||||
|
const isTitleValid = createMemo(
|
||||||
|
() => title() === "" || title().length >= MIN_TITLE_LENGTH
|
||||||
|
);
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
setProtocol(command().getProtocol());
|
||||||
|
setCommandNumber(command().getCommandNumber());
|
||||||
|
setDevice(command().getDevice());
|
||||||
|
setCommandType(command().getCommandType());
|
||||||
|
setTitle(command().getTitle());
|
||||||
|
});
|
||||||
|
|
||||||
|
const isFormValid = createMemo(
|
||||||
|
() =>
|
||||||
|
isProtocolValid() &&
|
||||||
|
isCommandNumberValid() &&
|
||||||
|
isDeviceValid() &&
|
||||||
|
isCommandTypeValid() &&
|
||||||
|
isTitleValid()
|
||||||
|
);
|
||||||
|
|
||||||
|
async function handleEditCommand() {
|
||||||
|
try {
|
||||||
|
await RemotesService.updateCommand(
|
||||||
|
new Command({
|
||||||
|
id: command().getId(),
|
||||||
|
protocol: protocol(),
|
||||||
|
commandNumber: parseInt(commandNumber()),
|
||||||
|
device: parseInt(device()),
|
||||||
|
commandType: commandType(),
|
||||||
|
title: title(),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
setError(e.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resetFields();
|
||||||
|
EditCommandModal.Handler.hide();
|
||||||
|
eventEmitter.dispatchEvent(COMMAND_EDITED_EVENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetFields() {
|
||||||
|
setProtocol("");
|
||||||
|
setCommandNumber("");
|
||||||
|
setDevice("");
|
||||||
|
setCommandType("");
|
||||||
|
setTitle("");
|
||||||
|
setError("");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
ref={props.ref}
|
||||||
|
id="editCommandModal"
|
||||||
|
modalTitle="Edit Command"
|
||||||
|
centered={true}
|
||||||
|
>
|
||||||
|
<div class="modal-body" style="overflow-y:inherit !important;">
|
||||||
|
<Show when={error() !== ""}>
|
||||||
|
<div class="alert alert-danger" role="alert">
|
||||||
|
{error()}
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
<div class="mb-3 row">
|
||||||
|
<label for="edit_command_protocol" class="col-form-label col-sm-3">
|
||||||
|
Protocol
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select
|
||||||
|
class="form-select"
|
||||||
|
onChange={(e) => setProtocol(e.target.value)}
|
||||||
|
>
|
||||||
|
{Object.values(Command.PROTOCOLS).map((protocol) => (
|
||||||
|
<option
|
||||||
|
value={protocol}
|
||||||
|
selected={protocol === command().getProtocol()}
|
||||||
|
>
|
||||||
|
{Command.getProtocolString(protocol)}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3 row">
|
||||||
|
<label for="edit_command_number" class="col-form-label col-sm-3">
|
||||||
|
Command Number
|
||||||
|
</label>
|
||||||
|
<ValidatedTextInput
|
||||||
|
class="col-sm-9"
|
||||||
|
id="edit_command_number"
|
||||||
|
valid={isCommandNumberValid()}
|
||||||
|
value={commandNumber()}
|
||||||
|
onInput={(e) => setCommandNumber(e.target.value)}
|
||||||
|
errorText={"Command number must be a number"}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3 row">
|
||||||
|
<label
|
||||||
|
for="edit_command_device_number"
|
||||||
|
class="col-form-label col-sm-3"
|
||||||
|
>
|
||||||
|
Device Number
|
||||||
|
</label>
|
||||||
|
<ValidatedTextInput
|
||||||
|
class="col-sm-9"
|
||||||
|
id="edit_command_device_number"
|
||||||
|
valid={isDeviceValid()}
|
||||||
|
value={device()}
|
||||||
|
onInput={(e) => setDevice(e.target.value)}
|
||||||
|
errorText={"Device number must be a number"}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3 row">
|
||||||
|
<label for="edit_command_protocol" class="col-form-label col-sm-3">
|
||||||
|
Command Type
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select
|
||||||
|
class="form-select"
|
||||||
|
onChange={(e) => setCommandType(e.target.value)}
|
||||||
|
>
|
||||||
|
{Object.values(Command.TYPES).map((commandType) => (
|
||||||
|
<option
|
||||||
|
value={commandType}
|
||||||
|
selected={commandType === command().getCommandType()}
|
||||||
|
>
|
||||||
|
{Command.getTypeString(commandType)}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3 row">
|
||||||
|
<label for="edit_command_title" class="col-form-label col-sm-3">
|
||||||
|
Title
|
||||||
|
</label>
|
||||||
|
<ValidatedTextInput
|
||||||
|
class="col-sm-9"
|
||||||
|
id="edit_command_title"
|
||||||
|
valid={isTitleValid()}
|
||||||
|
value={title()}
|
||||||
|
onInput={(e) => setTitle(e.target.value)}
|
||||||
|
errorText={`Title must be at least ${MIN_TITLE_LENGTH} characters long`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={handleEditCommand}
|
||||||
|
class="btn btn-primary"
|
||||||
|
disabled={!isFormValid()}
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditCommandModal.Handler = new ModalHandler();
|
||||||
|
EditCommandModal.onCommandEdited = (callback) =>
|
||||||
|
eventEmitter.on(COMMAND_EDITED_EVENT, callback);
|
||||||
|
EditCommandModal.setCommand = setCommand;
|
||||||
|
|
||||||
|
export default EditCommandModal;
|
||||||
@ -11,6 +11,7 @@ import DeleteCommandModal from "./delete-command-modal.jsx";
|
|||||||
import CreateRemoteModal from "./create-remote-modal.jsx";
|
import CreateRemoteModal from "./create-remote-modal.jsx";
|
||||||
import DeleteRemoteModal from "./delete-remote-modal.jsx";
|
import DeleteRemoteModal from "./delete-remote-modal.jsx";
|
||||||
import ImportCommandsModal from "./import-commands-modal.jsx";
|
import ImportCommandsModal from "./import-commands-modal.jsx";
|
||||||
|
import EditCommandModal from "./edit-command-modal.jsx";
|
||||||
|
|
||||||
const ModalRegistry = (function () {
|
const ModalRegistry = (function () {
|
||||||
const modals = [
|
const modals = [
|
||||||
@ -68,7 +69,12 @@ const ModalRegistry = (function () {
|
|||||||
id: "importCommandsModal",
|
id: "importCommandsModal",
|
||||||
component: ImportCommandsModal,
|
component: ImportCommandsModal,
|
||||||
ref: null,
|
ref: null,
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
id: "editCommandModal",
|
||||||
|
component: EditCommandModal,
|
||||||
|
ref: null,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
function getModals(props) {
|
function getModals(props) {
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import Command from "../data/command";
|
|
||||||
import Serializer from "../data/serializer";
|
import Serializer from "../data/serializer";
|
||||||
import Net from "../tools/net";
|
import Net from "../tools/net";
|
||||||
import WebRTCService from "./webrtc-service";
|
import WebRTCService from "./webrtc-service";
|
||||||
@ -95,6 +94,20 @@ function RemoteService() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function updateCommand(command) {
|
||||||
|
let commandObject = Serializer.serializeCommand(command);
|
||||||
|
let response = await Net.sendJsonRequest({
|
||||||
|
method: "PUT",
|
||||||
|
url: "/api/commands/" + command.getId(),
|
||||||
|
data: commandObject,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.status !== 200) {
|
||||||
|
let responseData = JSON.parse(response.data);
|
||||||
|
throw new Error(responseData.error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function deleteCommand(commandId) {
|
async function deleteCommand(commandId) {
|
||||||
let response = await Net.sendRequest({
|
let response = await Net.sendRequest({
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
@ -109,7 +122,10 @@ function RemoteService() {
|
|||||||
|
|
||||||
function sendCommand(command) {
|
function sendCommand(command) {
|
||||||
let commandObject = Serializer.serializeCommand(command);
|
let commandObject = Serializer.serializeCommand(command);
|
||||||
WebRTCService.sendDataJson({type: MESSAGE_TYPE_COMMAND, data: commandObject});
|
WebRTCService.sendDataJson({
|
||||||
|
type: MESSAGE_TYPE_COMMAND,
|
||||||
|
data: commandObject,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -120,6 +136,7 @@ function RemoteService() {
|
|||||||
getCommands,
|
getCommands,
|
||||||
createCommand,
|
createCommand,
|
||||||
createCommands,
|
createCommands,
|
||||||
|
updateCommand,
|
||||||
deleteCommand,
|
deleteCommand,
|
||||||
sendCommand,
|
sendCommand,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import RemotesService from "../../services/remotes-service";
|
|||||||
import CreateCommandModal from "../../modals/create-command-modal";
|
import CreateCommandModal from "../../modals/create-command-modal";
|
||||||
import DeleteCommandModal from "../../modals/delete-command-modal";
|
import DeleteCommandModal from "../../modals/delete-command-modal";
|
||||||
import ImportCommandsModal from "../../modals/import-commands-modal";
|
import ImportCommandsModal from "../../modals/import-commands-modal";
|
||||||
|
import EditCommandModal from "../../modals/edit-command-modal";
|
||||||
|
|
||||||
function CommandsList(props) {
|
function CommandsList(props) {
|
||||||
const [commands, { refetch: refetchCommands }] = createResource(
|
const [commands, { refetch: refetchCommands }] = createResource(
|
||||||
@ -17,7 +18,7 @@ function CommandsList(props) {
|
|||||||
CreateCommandModal.onCommandCreated(() => {
|
CreateCommandModal.onCommandCreated(() => {
|
||||||
refetchCommands();
|
refetchCommands();
|
||||||
});
|
});
|
||||||
|
|
||||||
ImportCommandsModal.onCommandsImported(() => {
|
ImportCommandsModal.onCommandsImported(() => {
|
||||||
refetchCommands();
|
refetchCommands();
|
||||||
});
|
});
|
||||||
@ -26,6 +27,10 @@ function CommandsList(props) {
|
|||||||
refetchCommands();
|
refetchCommands();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
EditCommandModal.onCommandEdited(() => {
|
||||||
|
refetchCommands();
|
||||||
|
});
|
||||||
|
|
||||||
function handleNewCommand() {
|
function handleNewCommand() {
|
||||||
refetchCommands();
|
refetchCommands();
|
||||||
CreateCommandModal.Handler.show();
|
CreateCommandModal.Handler.show();
|
||||||
@ -35,11 +40,16 @@ function CommandsList(props) {
|
|||||||
DeleteCommandModal.setCommand(command);
|
DeleteCommandModal.setCommand(command);
|
||||||
DeleteCommandModal.Handler.show();
|
DeleteCommandModal.Handler.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleImportCommands() {
|
function handleImportCommands() {
|
||||||
ImportCommandsModal.Handler.show();
|
ImportCommandsModal.Handler.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleEditCommand(command) {
|
||||||
|
EditCommandModal.setCommand(command);
|
||||||
|
EditCommandModal.Handler.show();
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div class="d-flex flex-row">
|
<div class="d-flex flex-row">
|
||||||
@ -72,7 +82,7 @@ function CommandsList(props) {
|
|||||||
{
|
{
|
||||||
id: "protocol",
|
id: "protocol",
|
||||||
name: "Protocol",
|
name: "Protocol",
|
||||||
width: 10,
|
width: 8,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "type",
|
id: "type",
|
||||||
@ -82,7 +92,7 @@ function CommandsList(props) {
|
|||||||
{
|
{
|
||||||
id: "options",
|
id: "options",
|
||||||
name: "",
|
name: "",
|
||||||
width: 4,
|
width: 6,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
items={(commands() || []).map((command) => ({
|
items={(commands() || []).map((command) => ({
|
||||||
@ -101,6 +111,15 @@ function CommandsList(props) {
|
|||||||
options: {
|
options: {
|
||||||
html: (
|
html: (
|
||||||
<>
|
<>
|
||||||
|
<button
|
||||||
|
class="btn btn-sm btn-outline-secondary me-2"
|
||||||
|
onClick={(event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
handleEditCommand(command);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<i class="bi bi-pencil-fill"></i>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn btn-sm btn-outline-secondary me-2"
|
class="btn btn-sm btn-outline-secondary me-2"
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user