Skip to content

Commit

Permalink
Add agent delete
Browse files Browse the repository at this point in the history
  • Loading branch information
Laica-Lunasys committed May 2, 2021
1 parent 5e717d8 commit fef9dcd
Show file tree
Hide file tree
Showing 9 changed files with 171 additions and 3 deletions.
72 changes: 69 additions & 3 deletions frontend/dash-home/src/components/agent/AgentEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as React from 'react';
import { Button, Modal, Form } from 'react-bootstrap';
import { useTranslation } from 'react-i18next';
import { Redirect } from 'react-router-dom';
import { Agent, AgentResult, updateAgent, addAgent } from '../../remote-go/Agents';
import { Agent, AgentResult, updateAgent, addAgent, deleteAgent } from '../../remote-go/Agents';
import { FAILED, PENDING, SUCCESS } from '../../remote-go/Status';
import { P } from '../atoms/Core';
import { NotifyError } from '../atoms/Notify';
Expand All @@ -22,7 +22,7 @@ const initial: Agent = {
label: "",
}

export type ActionType = 'ADD' | 'EDIT';
export type ActionType = 'ADD' | 'EDIT' | 'DELETE';

export const AgentEditor: React.FC<Props> = props => {
console.log(props.agent)
Expand All @@ -37,16 +37,82 @@ export const AgentEditor: React.FC<Props> = props => {

const [postResult, setPostResult] = React.useState<AgentResult | undefined>(undefined);

const handleDelete = () => {
if (props.agent) {
deleteAgent(props.agent?.id, setPostResult)
}
}

const handleSubmit = (event: any) => {
if (props.agent) {
updateAgent(props.agent?.id, agent, setPostResult)
if (props.action === 'EDIT') {
updateAgent(props.agent?.id, agent, setPostResult)
}
} else if (props.action === 'ADD') {
addAgent(agent, setPostResult)
}
event.preventDefault();
event.stopPropagation();
}

if (props.action === 'DELETE') {
// Return Error dialog when try default agent...
if (props.agent?.default) {
return (
<Modal show={props.show} onHide={props.handleClose && props.handleClose} centered>
<Modal.Header closeButton>
<Modal.Title>{t("agent.delete.title")}</Modal.Title>
</Modal.Header>
<Modal.Body>
<P>{t("agent.delete.error.defaultAgent")}</P>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={props.handleClose && props.handleClose}>{t("button.close")}</Button>
</Modal.Footer>
</Modal>
)
}

// Confirm
if (postResult?.status !== SUCCESS) {
return (
<Modal show={props.show} onHide={props.handleClose && props.handleClose} centered>
<Modal.Header closeButton>
<Modal.Title>{t("agent.delete.title")}</Modal.Title>
</Modal.Header>
<Modal.Body>
<P>{t("agent.delete.question")}</P>
<P>{t("agent.delete.confirm")}</P>
<div>
{postResult && postResult.status === FAILED && <NotifyError title="Failed send request" message={`${postResult.error!.response?.data.error ? postResult.error!.response.data.error : postResult.error!}`} />}
</div>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={props.handleClose && props.handleClose}>{t("button.cancel")}</Button>
<Button variant="danger" onClick={() => handleDelete()}>{t("button.delete")}</Button>
</Modal.Footer>
</Modal>
)
}

// Success
if (postResult?.status === SUCCESS) {
return (
<Modal show={props.show} onHide={props.handleClose && props.handleClose} centered>
<Modal.Header closeButton>
<Modal.Title>{t("agent.delete.title")}</Modal.Title>
</Modal.Header>
<Modal.Body>
<P>{t("agent.delete.success")}</P>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={props.handleClose && props.handleClose}>{t("button.close")}</Button>
</Modal.Footer>
</Modal>
)
}
}

return (
<Modal show={props.show} onHide={props.handleClose && props.handleClose}>
<Form onSubmit={handleSubmit}>
Expand Down
14 changes: 14 additions & 0 deletions frontend/dash-home/src/components/agent/AgentMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const AgentMenu: React.FC<Props> = props => {

const [create, setCreate] = React.useState<boolean>(false);
const [edit, setEdit] = React.useState<Agent | null>(null);
const [remove, setRemove] = React.useState<Agent | null>(null);

if (agentsResult === undefined || !agentsResult.agents) {
return (
Expand Down Expand Up @@ -95,6 +96,10 @@ const AgentMenu: React.FC<Props> = props => {
<FontAwesomeIcon icon={["fas", "edit"]} />
<span style={{ paddingLeft: "0.5rem" }}>{t("button.edit")}</span>
</Button>
<Button variant="danger" onClick={() => { setRemove(agent) }}>
<FontAwesomeIcon icon={["fas", "trash"]} />
<span style={{ paddingLeft: "0.5rem" }}>{t("button.delete")}</span>
</Button>
<AgentEditor
key={agent.id}
agent={agent}
Expand All @@ -104,6 +109,15 @@ const AgentMenu: React.FC<Props> = props => {
fetch();
setEdit(null);
}} />
<AgentEditor
key={agent.id}
agent={agent}
show={remove?.id === agent.id}
action={'DELETE'}
handleClose={() => {
fetch();
setRemove(null);
}} />
</td>
</tr>
)
Expand Down
9 changes: 9 additions & 0 deletions frontend/dash-home/src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@
"edit": {
"title": "Edit Agent"
},
"delete": {
"title": "Delete Agent",
"question": "Are you sure you want to delete this item?",
"confirm": "This operation cannot be undone!",
"success": "Removed.",
"error": {
"defaultAgent": "The default agent cannot be deleted."
}
},
"chooser": "Select Agent...",
"useDefault": "Use Default"
},
Expand Down
9 changes: 9 additions & 0 deletions frontend/dash-home/src/locales/ja/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@
"edit": {
"title": "エージェントを編集"
},
"delete": {
"title": "エージェントを削除",
"question": "削除してもよろしいですか?",
"confirm": "この操作を元に戻すことはできません!",
"success": "削除しました。",
"error": {
"defaultAgent": "デフォルトのエージェントは削除できません。"
}
},
"chooser": "エージェントを選択...",
"useDefault": "デフォルトを使用"
},
Expand Down
19 changes: 19 additions & 0 deletions frontend/dash-home/src/remote-go/Agents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,25 @@ export function addAgent(payload: Agent, setResult: React.Dispatch<React.SetStat
});
}

export function deleteAgent(id: string, setResult: React.Dispatch<React.SetStateAction<AgentResult | undefined>>) {
setResult({
status: PENDING,
})

axios.delete(`${API_ADDRESS}/api/v1/agents/${id}`)
.then(() => setResult({
status: SUCCESS,
}))
.catch((error: AxiosError<ErrorResponse>) => {
console.error(`*** Agents > Delete error:`);
console.error(error);
setResult({
status: FAILED,
error: error,
});
});
}

export function updateAgent(id: string, payload: Agent, setResult: React.Dispatch<React.SetStateAction<AgentResult | undefined>>) {
setResult({
status: PENDING,
Expand Down
6 changes: 6 additions & 0 deletions pkg/agent/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,9 @@ var ErrDefaultAgentRequired = &status.Error{
Error: errors.New("default agent required"),
Code: "ERR_DEFAULT_AGENT_REQUIRED",
}

// ErrRemoveDefaultAgent - When try remove default agent
var ErrRemoveDefaultAgent = &status.Error{
Error: errors.New("can't delete default agent"),
Code: "ERR_REMOVE_DEFAULT_AGENT",
}
23 changes: 23 additions & 0 deletions pkg/agent/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,29 @@ func (s *Storage) Add(address string, isDefault bool, label string) (*Agent, err
return newAgent, s.save()
}

// Remove - Remove agent
func (s *Storage) Remove(id string) error {
// Get By ID
if agent := s.GetByID(id); agent == nil {
return ErrNotFound.Error
} else if agent.Default {
return ErrRemoveDefaultAgent.Error
}

targetPos := -1
for i := range s.Agents {
if s.Agents[i].ID == id {
targetPos = i
}
}

s.Agents = append(s.Agents[:targetPos], s.Agents[targetPos+1:]...)
newAgents := make([]*Agent, len(s.Agents))
copy(newAgents, s.Agents)

return s.save()
}

// Update - Update agent settings
func (s *Storage) Update(id string, entry *Agent) (*Agent, error) {
oldEntry := s.GetByID(id)
Expand Down
21 changes: 21 additions & 0 deletions pkg/server/agents.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,27 @@ func (h *httpServer) getAgentByID(c *gin.Context) {
c.JSON(http.StatusOK, r)
}

// Delete Agent By ID
// @Summary Delete agent by ID
// @Router /api/v1/agents/:id [delete]
// @tags agent
// @Success 200
func (h *httpServer) deleteAgentByID(c *gin.Context) {
id := c.Param("id")
r := h.agent.Storage.GetByID(id)
if r == nil {
c.JSON(http.StatusNotFound, agent.ErrNotFound)
return
}

if err := h.agent.Storage.Remove(id); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

c.JSON(http.StatusOK, nil)
}

// Add Agent
// @Summary Add Agent entry
// @Router /api/v1/agents [post]
Expand Down
1 change: 1 addition & 0 deletions pkg/server/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ func NewHTTPServer(subset *Subset) *gin.Engine {
apiGroup.POST("agents", h.postAgent)
apiGroup.GET("agents/:id", h.getAgentByID)
apiGroup.PATCH("agents/:id", h.patchAgentByID)
apiGroup.DELETE("agents/:id", h.deleteAgentByID)

// Room
apiGroup.GET("room", h.getRoom)
Expand Down

0 comments on commit fef9dcd

Please sign in to comment.