From 1b4a88392ed46766a8d4832c0cd42eec90e199e7 Mon Sep 17 00:00:00 2001 From: Philipp Date: Tue, 29 Nov 2022 23:14:11 +0100 Subject: [PATCH] Edit external actions (#2391) * Initial action editing * Set previous values in form when editing * Show previous values when editing an action * Fix typo --- web/pages/admin/actions.tsx | 142 ++++++++++++++++++++++++++---------- 1 file changed, 102 insertions(+), 40 deletions(-) diff --git a/web/pages/admin/actions.tsx b/web/pages/admin/actions.tsx index 55cee711d..eccdeef7c 100644 --- a/web/pages/admin/actions.tsx +++ b/web/pages/admin/actions.tsx @@ -1,7 +1,9 @@ -import { DeleteOutlined } from '@ant-design/icons'; -import { Button, Checkbox, Input, Modal, Space, Table, Typography } from 'antd'; +import { DeleteOutlined, EditOutlined } from '@ant-design/icons'; +import { Button, Checkbox, Form, Input, Modal, Space, Table, Typography } from 'antd'; +import _ from 'lodash'; import React, { useContext, useEffect, useState } from 'react'; import { FormStatusIndicator } from '../../components/config/FormStatusIndicator'; +import { ExternalAction } from '../../interfaces/external-action'; import { API_EXTERNAL_ACTIONS, postConfigUpdateToAPI, @@ -16,12 +18,21 @@ let resetTimer = null; interface Props { onCancel: () => void; - onOk: any; // todo: make better type + onOk: ( + oldAction: ExternalAction | null, + actionUrl: string, + actionTitle: string, + actionDescription: string, + actionIcon: string, + actionColor: string, + openExternally: boolean, + ) => void; open: boolean; + action: ExternalAction | null; } -const NewActionModal = (props: Props) => { - const { onOk, onCancel, open } = props; +const ActionModal = (props: Props) => { + const { onOk, onCancel, open, action } = props; const [actionUrl, setActionUrl] = useState(''); const [actionTitle, setActionTitle] = useState(''); @@ -30,8 +41,25 @@ const NewActionModal = (props: Props) => { const [actionColor, setActionColor] = useState(''); const [openExternally, setOpenExternally] = useState(false); + useEffect(() => { + setActionUrl(action?.url || ''); + setActionTitle(action?.title || ''); + setActionDescription(action?.description || ''); + setActionIcon(action?.icon || ''); + setActionColor(action?.color || ''); + setOpenExternally(action?.openExternally || false); + }, [action]); + function save() { - onOk(actionUrl, actionTitle, actionDescription, actionIcon, actionColor, openExternally); + onOk( + action, + actionUrl, + actionTitle, + actionDescription, + actionIcon, + actionColor, + openExternally, + ); setActionUrl(''); setActionTitle(''); setActionDescription(''); @@ -63,13 +91,14 @@ const NewActionModal = (props: Props) => { return ( -
+
Add the URL for the external action you want to present.{' '} Only HTTPS urls are supported.

@@ -81,54 +110,57 @@ const NewActionModal = (props: Props) => { Read more about external actions.

-

+ setActionUrl(input.currentTarget.value.trim())} type="url" pattern={DEFAULT_TEXTFIELD_URL_PATTERN} /> -

-

+ + setActionTitle(input.currentTarget.value)} /> -

-

+ + setActionDescription(input.currentTarget.value)} /> -

-

+ + setActionIcon(input.currentTarget.value)} /> -

-

- setActionColor(input.currentTarget.value)} - /> + +

+ + setActionColor(input.currentTarget.value)} + /> + Optional background color of the action button. -

- - Open in a new tab instead of within your page. - -
+
+ + + Open in a new tab instead of within your page. + + +
); }; @@ -137,9 +169,10 @@ const Actions = () => { const serverStatusData = useContext(ServerStatusContext); const { serverConfig, setFieldInConfigState } = serverStatusData || {}; const { externalActions } = serverConfig; - const [actions, setActions] = useState([]); + const [actions, setActions] = useState(null); const [isModalOpen, setIsModalOpen] = useState(false); const [submitStatus, setSubmitStatus] = useState(null); + const [editAction, setEditAction] = useState(null); const resetStates = () => { setSubmitStatus(null); @@ -182,6 +215,7 @@ const Actions = () => { } async function handleSave( + oldAction: ExternalAction | null, url: string, title: string, description: string, @@ -191,26 +225,43 @@ const Actions = () => { ) { try { const actionsData = [...actions]; - const updatedActions = actionsData.concat({ + + const newAction: ExternalAction = { url, title, description, icon, color, openExternally, - }); - setActions(updatedActions); - await save(updatedActions); + }; + + // Replace old action if edited or append the new action + const index = oldAction ? actions.findIndex(item => _.isEqual(item, oldAction)) : -1; + if (index >= 0) { + actionsData[index] = newAction; + } else { + actionsData.push(newAction); + } + + setActions(actionsData); + await save(actionsData); } catch (error) { console.error(error); } } + async function handleEdit(action: ExternalAction) { + setEditAction(action); + setIsModalOpen(true); + } + const showCreateModal = () => { + setEditAction(null); setIsModalOpen(true); }; const handleModalSaveButton = ( + oldAction: ExternalAction | null, actionUrl: string, actionTitle: string, actionDescription: string, @@ -219,7 +270,16 @@ const Actions = () => { openExternally: boolean, ) => { setIsModalOpen(false); - handleSave(actionUrl, actionTitle, actionDescription, actionIcon, actionColor, openExternally); + handleSave( + oldAction, + actionUrl, + actionTitle, + actionDescription, + actionIcon, + actionColor, + openExternally, + ); + setEditAction(null); }; const handleModalCancelButton = () => { @@ -229,10 +289,11 @@ const Actions = () => { const columns = [ { title: '', - key: 'delete', + key: 'delete-edit', render: (text, record) => ( -