gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-merchant-backoffice] 02/02: making purge instance feature


From: gnunet
Subject: [taler-merchant-backoffice] 02/02: making purge instance feature
Date: Mon, 02 Aug 2021 16:23:05 +0200

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository merchant-backoffice.

commit ee3f5c57b3e226e8ae9e38bb896f9c3579804a8e
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Mon Aug 2 11:22:48 2021 -0300

    making purge instance feature
---
 packages/frontend/src/components/modal/index.tsx   |  9 +++
 packages/frontend/src/hooks/admin.ts               | 12 +++-
 .../admin/list/{Table.tsx => TableActive.tsx}      |  2 +-
 .../admin/list/{Table.tsx => TableDeleted.tsx}     | 68 +++-------------------
 packages/frontend/src/paths/admin/list/View.tsx    | 12 +++-
 packages/frontend/src/paths/admin/list/index.tsx   | 43 +++++++++++++-
 6 files changed, 78 insertions(+), 68 deletions(-)

diff --git a/packages/frontend/src/components/modal/index.tsx 
b/packages/frontend/src/components/modal/index.tsx
index a427215..15157f0 100644
--- a/packages/frontend/src/components/modal/index.tsx
+++ b/packages/frontend/src/components/modal/index.tsx
@@ -124,8 +124,17 @@ interface DeleteModalProps {
 }
 
 export function DeleteModal({ element, onCancel, onConfirm }: 
DeleteModalProps): VNode {
+  return <ConfirmModal description="delete_instance" danger active 
onCancel={onCancel} onConfirm={() => onConfirm(element.id)}>
+    <p>This will deactivate the instance "{element.name}" with id 
<b>{element.id}</b></p>
+    <p>The merchant will not be able to create order or make refunds 
anymore.</p>
+    <p>Please confirm this action</p>
+  </ConfirmModal>
+}
+
+export function PurgeModal({ element, onCancel, onConfirm }: 
DeleteModalProps): VNode {
   return <ConfirmModal description="delete_instance" danger active 
onCancel={onCancel} onConfirm={() => onConfirm(element.id)}>
     <p>This will permanently delete instance "{element.name}" with id 
<b>{element.id}</b></p>
+    <p>The information being deleted also include tax records, make sure you 
have backups.</p>
     <p>Please confirm this action</p>
   </ConfirmModal>
 }
diff --git a/packages/frontend/src/hooks/admin.ts 
b/packages/frontend/src/hooks/admin.ts
index 3c095de..24089b7 100644
--- a/packages/frontend/src/hooks/admin.ts
+++ b/packages/frontend/src/hooks/admin.ts
@@ -40,10 +40,20 @@ export function useAdminAPI(): AdminAPI {
     mutateAll(/@"\/private\/instances"@/);
   };
 
-  return { createInstance, deleteInstance };
+  const purgeInstance = async (id: string): Promise<void> => {
+    await request(`${url}/private/instances/${id}?purge=YES`, {
+      method: 'delete',
+      token,
+    });
+
+    mutateAll(/@"\/private\/instances"@/);
+  };
+
+  return { createInstance, deleteInstance, purgeInstance };
 }
 
 export interface AdminAPI {
   createInstance: (data: 
MerchantBackend.Instances.InstanceConfigurationMessage) => Promise<void>;
   deleteInstance: (id: string) => Promise<void>;
+  purgeInstance: (id: string) => Promise<void>;
 }
diff --git a/packages/frontend/src/paths/admin/list/Table.tsx 
b/packages/frontend/src/paths/admin/list/TableActive.tsx
similarity index 99%
copy from packages/frontend/src/paths/admin/list/Table.tsx
copy to packages/frontend/src/paths/admin/list/TableActive.tsx
index b306c43..d4e586b 100644
--- a/packages/frontend/src/paths/admin/list/Table.tsx
+++ b/packages/frontend/src/paths/admin/list/TableActive.tsx
@@ -134,7 +134,7 @@ function Table({ rowSelection, rowSelectionHandler, 
setInstanceName, instances,
                     <Translate>Edit</Translate>
                   </button>
                   <button class="button is-small is-danger jb-modal" 
type="button" onClick={(): void => onDelete(i)}>
-                    <Translate>Delete</Translate>
+                    <Translate>Disable</Translate>
                   </button>
                 </div>
               </td>
diff --git a/packages/frontend/src/paths/admin/list/Table.tsx 
b/packages/frontend/src/paths/admin/list/TableDeleted.tsx
similarity index 51%
rename from packages/frontend/src/paths/admin/list/Table.tsx
rename to packages/frontend/src/paths/admin/list/TableDeleted.tsx
index b306c43..667ff19 100644
--- a/packages/frontend/src/paths/admin/list/Table.tsx
+++ b/packages/frontend/src/paths/admin/list/TableDeleted.tsx
@@ -26,58 +26,23 @@ import { Translate, useTranslator } from "../../../i18n";
 
 interface Props {
   instances: MerchantBackend.Instances.Instance[];
-  onUpdate: (id: string) => void;
-  onDelete: (id: MerchantBackend.Instances.Instance) => void;
-  onCreate: () => void;
-  selected?: boolean;
-  setInstanceName: (s: string) => void;
+  onPurge: (id: MerchantBackend.Instances.Instance) => void;
 }
 
-export function CardTable({ instances, onCreate, onUpdate, setInstanceName, 
onDelete, selected }: Props): VNode {
-  const [actionQueue, actionQueueHandler] = useState<Actions[]>([]);
-  const [rowSelection, rowSelectionHandler] = useState<string[]>([])
-
-  useEffect(() => {
-    if (actionQueue.length > 0 && !selected && actionQueue[0].type == 
'DELETE') {
-      onDelete(actionQueue[0].element)
-      actionQueueHandler(actionQueue.slice(1))
-    }
-  }, [actionQueue, selected, onDelete])
-
-  useEffect(() => {
-    if (actionQueue.length > 0 && !selected && actionQueue[0].type == 
'UPDATE') {
-      onUpdate(actionQueue[0].element.id)
-      actionQueueHandler(actionQueue.slice(1))
-    }
-  }, [actionQueue, selected, onUpdate])
+export function CardTable({ instances, onPurge }: Props): VNode {
 
   const i18n = useTranslator()
 
   return <div class="card has-table">
     <header class="card-header">
-      <p class="card-header-title"><span class="icon"><i class="mdi 
mdi-desktop-mac" /></span><Translate>Instances</Translate></p>
-
-      <div class="card-header-icon" aria-label="more options">
-
-        <button class={rowSelection.length > 0 ? "button is-danger" : 
"is-hidden"}
-          type="button" onClick={(): void => 
actionQueueHandler(buildActions(instances, rowSelection, 'DELETE'))} >
-          <Translate>Delete</Translate>
-        </button>
-      </div>
-      <div class="card-header-icon" aria-label="more options">
-        <span class="has-tooltip-left" data-tooltip={i18n`add new instance`}>
-          <button class="button is-info" type="button" onClick={onCreate}>
-            <span class="icon is-small" ><i class="mdi mdi-plus mdi-36px" 
/></span>
-          </button>
-        </span>
-      </div>
+      <p class="card-header-title"><span class="icon"><i class="mdi 
mdi-desktop-mac" /></span><Translate>Disabled instances</Translate></p>
 
     </header>
     <div class="card-content">
       <div class="b-table has-pagination">
         <div class="table-wrapper has-mobile-cards">
           {instances.length > 0 ?
-            <Table instances={instances} onUpdate={onUpdate} 
setInstanceName={setInstanceName} onDelete={onDelete} 
rowSelection={rowSelection} rowSelectionHandler={rowSelectionHandler} /> :
+            <Table instances={instances} onPurge={onPurge} /> :
             <EmptyTable />
           }
         </div>
@@ -86,29 +51,21 @@ export function CardTable({ instances, onCreate, onUpdate, 
setInstanceName, onDe
   </div>
 }
 interface TableProps {
-  rowSelection: string[];
   instances: MerchantBackend.Instances.Instance[];
-  onUpdate: (id: string) => void;
-  onDelete: (id: MerchantBackend.Instances.Instance) => void;
-  rowSelectionHandler: StateUpdater<string[]>;
-  setInstanceName: (s:string) => void;
+  onPurge: (id: MerchantBackend.Instances.Instance) => void;
 }
 
 function toggleSelected<T>(id: T): (prev: T[]) => T[] {
   return (prev: T[]): T[] => prev.indexOf(id) == -1 ? [...prev, id] : 
prev.filter(e => e != id)
 }
 
-function Table({ rowSelection, rowSelectionHandler, setInstanceName, 
instances, onUpdate, onDelete }: TableProps): VNode {
+function Table({ instances, onPurge }: TableProps): VNode {
   return (
     <div class="table-container">
       <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
         <thead>
           <tr>
             <th class="is-checkbox-cell">
-              <label class="b-checkbox checkbox">
-                <input type="checkbox" checked={rowSelection.length === 
instances.length} onClick={(): void => rowSelectionHandler(rowSelection.length 
=== instances.length ? [] : instances.map(i => i.id))} />
-                <span class="check" />
-              </label>
             </th>
             <th><Translate>ID</Translate></th>
             <th><Translate>Name</Translate></th>
@@ -119,21 +76,12 @@ function Table({ rowSelection, rowSelectionHandler, 
setInstanceName, instances,
           {instances.map(i => {
             return <tr key={i.id}>
               <td class="is-checkbox-cell">
-                <label class="b-checkbox checkbox">
-                  <input type="checkbox" checked={rowSelection.indexOf(i.id) 
!= -1} onClick={(): void => rowSelectionHandler(toggleSelected(i.id))} />
-                  <span class="check" />
-                </label>
               </td>
-              <td><a href={`#/orders?instance=${i.id}`} onClick={(e) => {
-                setInstanceName(i.id);
-              }}>{i.id}</a></td>
+              <td>{i.id}</td>
               <td >{i.name}</td>
               <td class="is-actions-cell right-sticky">
                 <div class="buttons is-right">
-                  <button class="button is-small is-success jb-modal" 
type="button" onClick={(): void => onUpdate(i.id)}>
-                    <Translate>Edit</Translate>
-                  </button>
-                  <button class="button is-small is-danger jb-modal" 
type="button" onClick={(): void => onDelete(i)}>
+                  <button class="button is-small is-danger jb-modal" 
type="button" onClick={(): void => onPurge(i)}>
                     <Translate>Delete</Translate>
                   </button>
                 </div>
diff --git a/packages/frontend/src/paths/admin/list/View.tsx 
b/packages/frontend/src/paths/admin/list/View.tsx
index 43ab4e7..e7413c1 100644
--- a/packages/frontend/src/paths/admin/list/View.tsx
+++ b/packages/frontend/src/paths/admin/list/View.tsx
@@ -21,23 +21,29 @@
 
 import { h, VNode } from "preact";
 import { MerchantBackend } from "../../../declaration";
-import { CardTable } from './Table';
+import { CardTable as CardTableActive } from './TableActive';
+import { CardTable as CardTableDeleted } from './TableDeleted';
 
 interface Props {
   instances: MerchantBackend.Instances.Instance[];
   onCreate: () => void;
   onUpdate: (id: string) => void;
   onDelete: (id: MerchantBackend.Instances.Instance) => void;
+  onPurge: (id: MerchantBackend.Instances.Instance) => void;
   selected?: boolean;
   setInstanceName: (s:string) => void;
 }
 
-export function View({ instances, onCreate, onDelete, onUpdate, 
setInstanceName, selected }: Props): VNode {
+export function View({ instances, onCreate, onDelete, onPurge, onUpdate, 
setInstanceName, selected }: Props): VNode {
 
   return <div id="app">
 
     <section class="section is-main-section">
-      <CardTable instances={instances} onDelete={onDelete} 
setInstanceName={setInstanceName} onUpdate={onUpdate} selected={selected} 
onCreate={onCreate} />
+      <CardTableActive instances={instances.filter(i => !i.deleted)} 
onDelete={onDelete} setInstanceName={setInstanceName} onUpdate={onUpdate} 
selected={selected} onCreate={onCreate} />
+    </section>
+
+    <section class="section is-main-section">
+      <CardTableDeleted instances={instances.filter(i => i.deleted)} 
onPurge={onPurge} />
     </section>
 
   </div >
diff --git a/packages/frontend/src/paths/admin/list/index.tsx 
b/packages/frontend/src/paths/admin/list/index.tsx
index 0d42e63..8dd5eef 100644
--- a/packages/frontend/src/paths/admin/list/index.tsx
+++ b/packages/frontend/src/paths/admin/list/index.tsx
@@ -22,11 +22,14 @@
 import { Fragment, h, VNode } from 'preact';
 import { useState } from 'preact/hooks';
 import { Loading } from '../../../components/exception/loading';
-import { DeleteModal } from '../../../components/modal';
+import { NotificationCard } from '../../../components/menu';
+import { DeleteModal, PurgeModal } from '../../../components/modal';
 import { MerchantBackend } from '../../../declaration';
 import { useAdminAPI } from "../../../hooks/admin";
 import { HttpError } from '../../../hooks/backend';
 import { useBackendInstances } from '../../../hooks/instance';
+import { useTranslator } from '../../../i18n';
+import { Notification } from '../../../utils/types';
 import { View } from './View';
 
 interface Props {
@@ -42,7 +45,10 @@ interface Props {
 export default function Instances({ onUnauthorized, onLoadError, onNotFound, 
onCreate, onUpdate, setInstanceName }: Props): VNode {
   const result = useBackendInstances()
   const [deleting, setDeleting] = useState<MerchantBackend.Instances.Instance 
| null>(null)
-  const { deleteInstance } = useAdminAPI()
+  const [purging, setPurging] = useState<MerchantBackend.Instances.Instance | 
null>(null)
+  const { deleteInstance, purgeInstance } = useAdminAPI()
+  const [notif, setNotif] = useState<Notification | undefined>(undefined)
+  const i18n = useTranslator()
 
   if (result.clientError && result.isUnauthorized) return onUnauthorized()
   if (result.clientError && result.isNotfound) return onNotFound()
@@ -50,9 +56,11 @@ export default function Instances({ onUnauthorized, 
onLoadError, onNotFound, onC
   if (!result.ok) return onLoadError(result)
 
   return <Fragment>
+    <NotificationCard notification={notif} />
     <View instances={result.data.instances}
       onDelete={setDeleting}
       onCreate={onCreate}
+      onPurge={setPurging}
       onUpdate={onUpdate}
       setInstanceName={setInstanceName}
       selected={!!deleting}
@@ -64,11 +72,40 @@ export default function Instances({ onUnauthorized, 
onLoadError, onNotFound, onC
         try {
           await deleteInstance(deleting.id)
           // pushNotification({ message: 'delete_success', type: 'SUCCESS' })
-        } catch (e) {
+          setNotif({
+            message: i18n`Instance disable`,
+            type: 'SUCCESS'
+          })
+        } catch (error) {
+          setNotif({
+            message: i18n`Failed to disable instance`,
+            type: "ERROR",
+            description: error.message
+          })
           // pushNotification({ message: 'delete_error', type: 'ERROR' })
         }
         setDeleting(null)
       }}
     />}
+    {purging && <PurgeModal
+      element={purging}
+      onCancel={() => setPurging(null)}
+      onConfirm={async (): Promise<void> => {
+        try {
+          await purgeInstance(purging.id)
+          setNotif({
+            message: i18n`Instance deleted`,
+            type: 'SUCCESS'
+          })
+        } catch (error) {
+          setNotif({
+            message: i18n`Failed to delete instance`,
+            type: "ERROR",
+            description: error.message
+          })
+        }
+        setPurging(null)
+      }}
+    />}
   </Fragment>;
 }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]