gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant-backoffice] branch master updated: simple login, but int


From: gnunet
Subject: [taler-merchant-backoffice] branch master updated: simple login, but integrated with merchant backend for create update and delete
Date: Wed, 10 Feb 2021 20:02:18 +0100

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

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

The following commit(s) were added to refs/heads/master by this push:
     new df19187  simple login, but integrated with merchant backend for create 
update and delete
df19187 is described below

commit df1918755c0af900c6c447f1d4e0ef27174fb26e
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Wed Feb 10 16:02:06 2021 -0300

    simple login, but integrated with merchant backend for create update and 
delete
---
 .gitignore                                   |   1 +
 .storybook/main.js                           |   4 +-
 .storybook/preview.js                        |   1 +
 package.json                                 |  11 +-
 src/components/hooks/backend.ts              |  63 +++++++--
 src/components/navbar/index.tsx              |   2 +-
 src/declaration.d.ts                         |   7 +-
 src/routes/dashboard/index.tsx               | 120 ++++++++--------
 src/routes/instances/ConfirmModal.tsx        |  30 ++++
 src/routes/instances/CreateModal.tsx         |  86 ++++++++++++
 src/routes/instances/DeleteAllModal.tsx      |  29 ++++
 src/routes/instances/DeleteModal.tsx         |  16 +++
 src/routes/instances/Table.tsx               | 196 ++++++++++++++++-----------
 src/routes/instances/UpdateModal.stories.tsx |  24 ++++
 src/routes/instances/UpdateModal.tsx         |  76 +++++++++++
 src/routes/instances/View.stories.tsx        |  45 +++---
 src/routes/instances/View.tsx                |  71 +++++-----
 src/routes/instances/index.tsx               |  17 ++-
 src/scss/main.scss                           |  23 ++++
 yarn.lock                                    | 165 ++++++++++++++++++++--
 20 files changed, 768 insertions(+), 219 deletions(-)

diff --git a/.gitignore b/.gitignore
index a62a00c..44a3358 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
 /build
 /node_modules
 /size-plugin.json
+/storybook-static
diff --git a/.storybook/main.js b/.storybook/main.js
index b9dea09..b2695b1 100644
--- a/.storybook/main.js
+++ b/.storybook/main.js
@@ -5,7 +5,7 @@ module.exports = {
   ],
   "addons": [
     "@storybook/preset-scss",
-    "@storybook/addon-links",
-    "@storybook/addon-essentials"
+    // "@storybook/addon-a11y",
+    "@storybook/addon-essentials" //docs, control, actions, viewpot, toolbar, 
background
   ]
 }
\ No newline at end of file
diff --git a/.storybook/preview.js b/.storybook/preview.js
index 15bd64e..ea8be75 100644
--- a/.storybook/preview.js
+++ b/.storybook/preview.js
@@ -1,5 +1,6 @@
 import "../src/scss/main.scss"
 
 export const parameters = {
+  controls: { expanded: true },
   actions: { argTypesRegex: "^on[A-Z].*" },
 }
\ No newline at end of file
diff --git a/package.json b/package.json
index 87f2b37..d518ce6 100644
--- a/package.json
+++ b/package.json
@@ -20,17 +20,24 @@
     ],
     "ignorePatterns": [
       "build/"
-    ]
+    ],
+    "rules": {
+      "@typescript-eslint/camelcase": [
+        "off"
+      ]
+    }
   },
   "dependencies": {
     "axios": "^0.21.1",
     "preact": "^10.3.1",
     "preact-router": "^3.2.1",
-    "swr": "^0.4.1"
+    "swr": "^0.4.1",
+    "yup": "^0.32.8"
   },
   "devDependencies": {
     "@babel/core": "^7.12.13",
     "@babel/plugin-transform-react-jsx-source": "^7.12.13",
+    "@storybook/addon-a11y": "^6.1.17",
     "@storybook/addon-actions": "^6.1.16",
     "@storybook/addon-essentials": "^6.1.16",
     "@storybook/addon-links": "^6.1.16",
diff --git a/src/components/hooks/backend.ts b/src/components/hooks/backend.ts
index ba322f0..5f32692 100644
--- a/src/components/hooks/backend.ts
+++ b/src/components/hooks/backend.ts
@@ -1,4 +1,4 @@
-import useSWR, { mutate } from 'swr';
+import useSWR, { mutate as globalMutate } from 'swr';
 import axios from 'axios'
 import { MerchantBackend } from '../../declaration';
 
@@ -20,13 +20,20 @@ class AuthError extends Error {
 const BACKEND = 'http://localhost:9966'
 const TOKEN_KEY = 'backend-token'
 
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-async function fetcher(url: string): Promise<any> {
+type Methods = 'get' | 'post' | 'patch' | 'delete' | 'put';
+
+async function request(url: string, method?: Methods, data?: object): 
Promise<any> {
   const token = localStorage.getItem(TOKEN_KEY)
   const headers = token ? { Authorization: `Bearer secret-token:${token}` } : 
undefined
 
-  const res = await axios.get(`${BACKEND}/private/${url}`, { headers })
-  if (res.status == 200) return res.data
+  const res = await axios({
+    method: method || 'get',
+    url: `${BACKEND}/private${url}`,
+    responseType: 'json',
+    headers,
+    data
+  })
+  if (res.status == 200 || res.status == 204) return res.data
   if (res.status == 401) throw new AuthError()
 
   const error = new Error('An error occurred while fetching the data.')
@@ -35,13 +42,51 @@ async function fetcher(url: string): Promise<any> {
   throw { info, status, ...error }
 }
 
+async function fetcher(url: string): Promise<any> {
+  return request(url, 'get')
+}
+
 export function updateToken(token: string): void {
   localStorage.setItem(TOKEN_KEY, token)
-  mutate('instances')
+  globalMutate('instances')
+}
+
+interface WithCreate<T> {
+  create: (data: T) => Promise<void>;
+}
+interface WithUpdate<T> {
+  update: (id: string, data: T) => Promise<void>;
+}
+interface WithDelete {
+  delete: (id: string) => Promise<void>;
 }
 
-export function useBackendInstances(): 
HttpResponse<MerchantBackend.Instances.InstancesResponse> {
-  const { data, error } = 
useSWR<MerchantBackend.Instances.InstancesResponse>('instances', fetcher)
+export function useBackendInstances(): 
HttpResponse<MerchantBackend.Instances.InstancesResponse> & 
WithCreate<MerchantBackend.Instances.InstanceConfigurationMessage> {
+  const { data, error, mutate } = 
useSWR<MerchantBackend.Instances.InstancesResponse>('/instances', fetcher)
+
+  const create = async (instance: 
MerchantBackend.Instances.InstanceConfigurationMessage) => {
+    await request('/instances', 'post', instance)
+
+    globalMutate('/instances')
+  }
+
+  return { data, needsAuth: error instanceof AuthError, error, create }
+}
+
+export function useBackendInstance(id: string | null): 
HttpResponse<MerchantBackend.Instances.QueryInstancesResponse> & 
WithUpdate<MerchantBackend.Instances.InstanceReconfigurationMessage> & 
WithDelete {
+  const { data, error } = 
useSWR<MerchantBackend.Instances.QueryInstancesResponse>(id ? 
`/instances/${id}` : null, fetcher)
+
+  const update = async (updateId: string, instance: 
MerchantBackend.Instances.InstanceReconfigurationMessage) => {
+    await request(`/instances/${updateId}`, 'patch', instance)
+
+    globalMutate(`/instances/${updateId}`, null)
+  };
+  const _delete = async (deleteId: string) => {
+    await request(`/instances/${deleteId}`, 'delete')
+
+    globalMutate('/instances')
+    globalMutate(`/instances/${deleteId}`, null)
+  }
 
-  return { data, needsAuth: error instanceof AuthError, error }
+  return { data, needsAuth: error instanceof AuthError, error, update, delete: 
_delete }
 }
diff --git a/src/components/navbar/index.tsx b/src/components/navbar/index.tsx
index 86e981b..00b093d 100644
--- a/src/components/navbar/index.tsx
+++ b/src/components/navbar/index.tsx
@@ -12,7 +12,7 @@ export default function NavigationBar(): VNode {
         </div>
       </div>
       <div class="navbar-brand is-right">
-        <a class="navbar-item is-hidden-desktop jb-navbar-menu-toggle" 
data-target="navbar-menu">
+        <a class="navbar-item is-hidden-desktop jb-navbar-menu-toggle">
           <span class="icon"><i class="mdi mdi-dots-vertical" /></span>
         </a>
       </div>
diff --git a/src/declaration.d.ts b/src/declaration.d.ts
index bd31d17..7b83773 100644
--- a/src/declaration.d.ts
+++ b/src/declaration.d.ts
@@ -1,3 +1,4 @@
+import { number } from "yup/lib/locale";
 
 declare module "*.css" {
     const mapping: Record<string, string>;
@@ -9,7 +10,7 @@ declare module "*.scss" {
 }
 
 type EddsaPublicKey = string;
-// type RelativeTime = Duration;
+type RelativeTime = Duration;
 interface Timestamp {
     // Milliseconds since epoch, or the special
     // value "forever" to represent an event that will
@@ -22,6 +23,10 @@ interface Duration {
     d_ms: number | "forever";
 }
 
+interface WidthId {
+    id: string;
+}
+
 type Amount = string;
 type UUID = string;
 type Integer = number;
diff --git a/src/routes/dashboard/index.tsx b/src/routes/dashboard/index.tsx
index 04b86ae..6a0590d 100644
--- a/src/routes/dashboard/index.tsx
+++ b/src/routes/dashboard/index.tsx
@@ -155,13 +155,13 @@ export default function BulmaIndex({}): VNode {
                     <img 
src="https://avatars.dicebear.com/4.5/api/male/rebecca-bauch.svg"; 
class="is-rounded" />
                   </div>
                 </td>
-                <td data-label="Name">Rebecca Bauch</td>
-                <td data-label="Company">Daugherty-Daniel</td>
-                <td data-label="City">South Cory</td>
-                <td data-label="Progress" class="is-progress-cell">
+                <td>Rebecca Bauch</td>
+                <td>Daugherty-Daniel</td>
+                <td>South Cory</td>
+                <td class="is-progress-cell">
                   <progress max="100" class="progress is-small is-primary" 
value="79">79</progress>
                 </td>
-                <td data-label="Created">
+                <td>
                   <small class="has-text-grey is-abbr-like" title="Oct 25, 
2020">Oct 25, 2020</small>
                 </td>
                 <td class="is-actions-cell">
@@ -169,7 +169,7 @@ export default function BulmaIndex({}): VNode {
                     <button class="button is-small is-primary" type="button">
                       <span class="icon"><i class="mdi mdi-eye" /></span>
                     </button>
-                    <button class="button is-small is-danger jb-modal" 
data-target="sample-modal" type="button">
+                    <button class="button is-small is-danger jb-modal" 
type="button">
                       <span class="icon"><i class="mdi mdi-trash-can" /></span>
                     </button>
                   </div>
@@ -181,13 +181,13 @@ export default function BulmaIndex({}): VNode {
                     <img 
src="https://avatars.dicebear.com/4.5/api/male/felicita-yundt.svg"; 
class="is-rounded" />
                   </div>
                 </td>
-                <td data-label="Name">Felicita Yundt</td>
-                <td data-label="Company">Johns-Weissnat</td>
-                <td data-label="City">East Ariel</td>
-                <td data-label="Progress" class="is-progress-cell">
+                <td>Felicita Yundt</td>
+                <td>Johns-Weissnat</td>
+                <td>East Ariel</td>
+                <td class="is-progress-cell">
                   <progress max="100" class="progress is-small is-primary" 
value="67">67</progress>
                 </td>
-                <td data-label="Created">
+                <td>
                   <small class="has-text-grey is-abbr-like" title="Jan 8, 
2020">Jan 8, 2020</small>
                 </td>
                 <td class="is-actions-cell">
@@ -195,7 +195,7 @@ export default function BulmaIndex({}): VNode {
                     <button class="button is-small is-primary" type="button">
                       <span class="icon"><i class="mdi mdi-eye" /></span>
                     </button>
-                    <button class="button is-small is-danger jb-modal" 
data-target="sample-modal" type="button">
+                    <button class="button is-small is-danger jb-modal" 
type="button">
                       <span class="icon"><i class="mdi mdi-trash-can" /></span>
                     </button>
                   </div>
@@ -207,13 +207,13 @@ export default function BulmaIndex({}): VNode {
                     <img 
src="https://avatars.dicebear.com/4.5/api/male/mr-larry-satterfield-v.svg"; 
class="is-rounded" />
                   </div>
                 </td>
-                <td data-label="Name">Mr. Larry Satterfield V</td>
-                <td data-label="Company">Hyatt Ltd</td>
-                <td data-label="City">Windlerburgh</td>
-                <td data-label="Progress" class="is-progress-cell">
+                <td>Mr. Larry Satterfield V</td>
+                <td>Hyatt Ltd</td>
+                <td>Windlerburgh</td>
+                <td class="is-progress-cell">
                   <progress max="100" class="progress is-small is-primary" 
value="16">16</progress>
                 </td>
-                <td data-label="Created">
+                <td>
                   <small class="has-text-grey is-abbr-like" title="Dec 18, 
2020">Dec 18, 2020</small>
                 </td>
                 <td class="is-actions-cell">
@@ -221,7 +221,7 @@ export default function BulmaIndex({}): VNode {
                     <button class="button is-small is-primary" type="button">
                       <span class="icon"><i class="mdi mdi-eye" /></span>
                     </button>
-                    <button class="button is-small is-danger jb-modal" 
data-target="sample-modal" type="button">
+                    <button class="button is-small is-danger jb-modal" 
type="button">
                       <span class="icon"><i class="mdi mdi-trash-can" /></span>
                     </button>
                   </div>
@@ -233,13 +233,13 @@ export default function BulmaIndex({}): VNode {
                     <img 
src="https://avatars.dicebear.com/4.5/api/male/mr-broderick-kub.svg"; 
class="is-rounded" />
                   </div>
                 </td>
-                <td data-label="Name">Mr. Broderick Kub</td>
-                <td data-label="Company">Kshlerin, Bauch and Ernser</td>
-                <td data-label="City">New Kirstenport</td>
-                <td data-label="Progress" class="is-progress-cell">
+                <td>Mr. Broderick Kub</td>
+                <td>Kshlerin, Bauch and Ernser</td>
+                <td>New Kirstenport</td>
+                <td class="is-progress-cell">
                   <progress max="100" class="progress is-small is-primary" 
value="71">71</progress>
                 </td>
-                <td data-label="Created">
+                <td>
                   <small class="has-text-grey is-abbr-like" title="Sep 13, 
2020">Sep 13, 2020</small>
                 </td>
                 <td class="is-actions-cell">
@@ -247,7 +247,7 @@ export default function BulmaIndex({}): VNode {
                     <button class="button is-small is-primary" type="button">
                       <span class="icon"><i class="mdi mdi-eye" /></span>
                     </button>
-                    <button class="button is-small is-danger jb-modal" 
data-target="sample-modal" type="button">
+                    <button class="button is-small is-danger jb-modal" 
type="button">
                       <span class="icon"><i class="mdi mdi-trash-can" /></span>
                     </button>
                   </div>
@@ -259,13 +259,13 @@ export default function BulmaIndex({}): VNode {
                     <img 
src="https://avatars.dicebear.com/4.5/api/male/barry-weber.svg"; 
class="is-rounded" />
                   </div>
                 </td>
-                <td data-label="Name">Barry Weber</td>
-                <td data-label="Company">Schulist, Mosciski and 
Heidenreich</td>
-                <td data-label="City">East Violettestad</td>
-                <td data-label="Progress" class="is-progress-cell">
+                <td>Barry Weber</td>
+                <td>Schulist, Mosciski and Heidenreich</td>
+                <td>East Violettestad</td>
+                <td class="is-progress-cell">
                   <progress max="100" class="progress is-small is-primary" 
value="80">80</progress>
                 </td>
-                <td data-label="Created">
+                <td>
                   <small class="has-text-grey is-abbr-like" title="Jul 24, 
2020">Jul 24, 2020</small>
                 </td>
                 <td class="is-actions-cell">
@@ -273,7 +273,7 @@ export default function BulmaIndex({}): VNode {
                     <button class="button is-small is-primary" type="button">
                       <span class="icon"><i class="mdi mdi-eye" /></span>
                     </button>
-                    <button class="button is-small is-danger jb-modal" 
data-target="sample-modal" type="button">
+                    <button class="button is-small is-danger jb-modal" 
type="button">
                       <span class="icon"><i class="mdi mdi-trash-can" /></span>
                     </button>
                   </div>
@@ -285,13 +285,13 @@ export default function BulmaIndex({}): VNode {
                     <img 
src="https://avatars.dicebear.com/4.5/api/male/bert-kautzer-md.svg"; 
class="is-rounded" />
                   </div>
                 </td>
-                <td data-label="Name">Bert Kautzer MD</td>
-                <td data-label="Company">Gerhold and Sons</td>
-                <td data-label="City">Mayeport</td>
-                <td data-label="Progress" class="is-progress-cell">
+                <td>Bert Kautzer MD</td>
+                <td>Gerhold and Sons</td>
+                <td>Mayeport</td>
+                <td class="is-progress-cell">
                   <progress max="100" class="progress is-small is-primary" 
value="62">62</progress>
                 </td>
-                <td data-label="Created">
+                <td>
                   <small class="has-text-grey is-abbr-like" title="Mar 30, 
2020">Mar 30, 2020</small>
                 </td>
                 <td class="is-actions-cell">
@@ -299,7 +299,7 @@ export default function BulmaIndex({}): VNode {
                     <button class="button is-small is-primary" type="button">
                       <span class="icon"><i class="mdi mdi-eye" /></span>
                     </button>
-                    <button class="button is-small is-danger jb-modal" 
data-target="sample-modal" type="button">
+                    <button class="button is-small is-danger jb-modal" 
type="button">
                       <span class="icon"><i class="mdi mdi-trash-can" /></span>
                     </button>
                   </div>
@@ -311,13 +311,13 @@ export default function BulmaIndex({}): VNode {
                     <img 
src="https://avatars.dicebear.com/4.5/api/male/lonzo-steuber.svg"; 
class="is-rounded" />
                   </div>
                 </td>
-                <td data-label="Name">Lonzo Steuber</td>
-                <td data-label="Company">Skiles Ltd</td>
-                <td data-label="City">Marilouville</td>
-                <td data-label="Progress" class="is-progress-cell">
+                <td>Lonzo Steuber</td>
+                <td>Skiles Ltd</td>
+                <td>Marilouville</td>
+                <td class="is-progress-cell">
                   <progress max="100" class="progress is-small is-primary" 
value="17">17</progress>
                 </td>
-                <td data-label="Created">
+                <td>
                   <small class="has-text-grey is-abbr-like" title="Feb 12, 
2020">Feb 12, 2020</small>
                 </td>
                 <td class="is-actions-cell">
@@ -325,7 +325,7 @@ export default function BulmaIndex({}): VNode {
                     <button class="button is-small is-primary" type="button">
                       <span class="icon"><i class="mdi mdi-eye" /></span>
                     </button>
-                    <button class="button is-small is-danger jb-modal" 
data-target="sample-modal" type="button">
+                    <button class="button is-small is-danger jb-modal" 
type="button">
                       <span class="icon"><i class="mdi mdi-trash-can" /></span>
                     </button>
                   </div>
@@ -337,13 +337,13 @@ export default function BulmaIndex({}): VNode {
                     <img 
src="https://avatars.dicebear.com/4.5/api/male/jonathon-hahn.svg"; 
class="is-rounded" />
                   </div>
                 </td>
-                <td data-label="Name">Jonathon Hahn</td>
-                <td data-label="Company">Flatley Ltd</td>
-                <td data-label="City">Billiemouth</td>
-                <td data-label="Progress" class="is-progress-cell">
+                <td>Jonathon Hahn</td>
+                <td>Flatley Ltd</td>
+                <td>Billiemouth</td>
+                <td class="is-progress-cell">
                   <progress max="100" class="progress is-small is-primary" 
value="74">74</progress>
                 </td>
-                <td data-label="Created">
+                <td>
                   <small class="has-text-grey is-abbr-like" title="Dec 30, 
2020">Dec 30, 2020</small>
                 </td>
                 <td class="is-actions-cell">
@@ -351,7 +351,7 @@ export default function BulmaIndex({}): VNode {
                     <button class="button is-small is-primary" type="button">
                       <span class="icon"><i class="mdi mdi-eye" /></span>
                     </button>
-                    <button class="button is-small is-danger jb-modal" 
data-target="sample-modal" type="button">
+                    <button class="button is-small is-danger jb-modal" 
type="button">
                       <span class="icon"><i class="mdi mdi-trash-can" /></span>
                     </button>
                   </div>
@@ -363,13 +363,13 @@ export default function BulmaIndex({}): VNode {
                     <img 
src="https://avatars.dicebear.com/4.5/api/male/ryley-wuckert.svg"; 
class="is-rounded" />
                   </div>
                 </td>
-                <td data-label="Name">Ryley Wuckert</td>
-                <td data-label="Company">Heller-Little</td>
-                <td data-label="City">Emeraldtown</td>
-                <td data-label="Progress" class="is-progress-cell">
+                <td>Ryley Wuckert</td>
+                <td>Heller-Little</td>
+                <td>Emeraldtown</td>
+                <td class="is-progress-cell">
                   <progress max="100" class="progress is-small is-primary" 
value="54">54</progress>
                 </td>
-                <td data-label="Created">
+                <td>
                   <small class="has-text-grey is-abbr-like" title="Jun 28, 
2020">Jun 28, 2020</small>
                 </td>
                 <td class="is-actions-cell">
@@ -377,7 +377,7 @@ export default function BulmaIndex({}): VNode {
                     <button class="button is-small is-primary" type="button">
                       <span class="icon"><i class="mdi mdi-eye" /></span>
                     </button>
-                    <button class="button is-small is-danger jb-modal" 
data-target="sample-modal" type="button">
+                    <button class="button is-small is-danger jb-modal" 
type="button">
                       <span class="icon"><i class="mdi mdi-trash-can" /></span>
                     </button>
                   </div>
@@ -389,13 +389,13 @@ export default function BulmaIndex({}): VNode {
                     <img 
src="https://avatars.dicebear.com/4.5/api/male/sienna-hayes.svg"; 
class="is-rounded" />
                   </div>
                 </td>
-                <td data-label="Name">Sienna Hayes</td>
-                <td data-label="Company">Conn, Jerde and Douglas</td>
-                <td data-label="City">Jonathanfort</td>
-                <td data-label="Progress" class="is-progress-cell">
+                <td>Sienna Hayes</td>
+                <td>Conn, Jerde and Douglas</td>
+                <td>Jonathanfort</td>
+                <td class="is-progress-cell">
                   <progress max="100" class="progress is-small is-primary" 
value="55">55</progress>
                 </td>
-                <td data-label="Created">
+                <td>
                   <small class="has-text-grey is-abbr-like" title="Mar 7, 
2020">Mar 7, 2020</small>
                 </td>
                 <td class="is-actions-cell">
@@ -403,7 +403,7 @@ export default function BulmaIndex({}): VNode {
                     <button class="button is-small is-primary" type="button">
                       <span class="icon"><i class="mdi mdi-eye" /></span>
                     </button>
-                    <button class="button is-small is-danger jb-modal" 
data-target="sample-modal" type="button">
+                    <button class="button is-small is-danger jb-modal" 
type="button">
                       <span class="icon"><i class="mdi mdi-trash-can" /></span>
                     </button>
                   </div>
diff --git a/src/routes/instances/ConfirmModal.tsx 
b/src/routes/instances/ConfirmModal.tsx
new file mode 100644
index 0000000..a074a60
--- /dev/null
+++ b/src/routes/instances/ConfirmModal.tsx
@@ -0,0 +1,30 @@
+import { h, VNode } from "preact";
+
+interface Props {
+  active?: boolean;
+  description?: string;
+  onCancel?: () => void;
+  onConfirm?: () => void;
+  children?: VNode[];
+  danger?: boolean;
+}
+
+export default function ConfirmModal({ active, description, onCancel, 
onConfirm, children, danger }: Props): VNode {
+  return <div class={active ? "modal is-active is-clipped" : "modal"}>
+    <div class="modal-background jb-modal-close" onClick={onCancel} />
+    <div class="modal-card">
+      <header class="modal-card-head">
+        <p class="modal-card-title">Confirm action: {description}</p>
+        <button class="delete jb-modal-close" aria-label="close" 
onClick={onCancel} />
+      </header>
+      <section class="modal-card-body">
+        {children}
+      </section>
+      <footer class="modal-card-foot">
+        <button class="button jb-modal-close" onClick={onCancel} 
>Cancel</button>
+        <button class={danger ? "button is-danger jb-modal-close" : "button 
is-info jb-modal-close"} onClick={onConfirm} >Confirm</button>
+      </footer>
+    </div>
+    <button class="modal-close is-large jb-modal-close" aria-label="close" 
onClick={onCancel} />
+  </div>
+}
\ No newline at end of file
diff --git a/src/routes/instances/CreateModal.tsx 
b/src/routes/instances/CreateModal.tsx
new file mode 100644
index 0000000..d22ae7d
--- /dev/null
+++ b/src/routes/instances/CreateModal.tsx
@@ -0,0 +1,86 @@
+import { h, VNode } from "preact";
+import { useState } from "preact/hooks";
+import { Duration, MerchantBackend } from "../../declaration";
+import * as yup from 'yup';
+import ConfirmModal from "./ConfirmModal";
+
+function stringToArray(this: yup.AnySchema, current: any, original: string): 
string[] {
+  if (this.isType(current)) return current;
+  return original.split(',').filter(s => s.length > 0)
+}
+function numberToDuration(this: yup.AnySchema, current: any, original: 
string): Duration {
+  if (this.isType(current)) return current;
+  console.log('numberToDuration', current, original)
+  const d_ms = parseInt(original, 10)
+  return { d_ms }
+}
+/*
+validations
+  * delays size
+  * payto-uri format
+  * currency
+*/
+
+const schema = yup.object().shape({
+  id: yup.string().required().label("Id"),
+  name: yup.string().required().label("Name"),
+  payto_uris: yup.array().of(yup.string())
+    .min(1).label("Payment Method")
+    .meta({ placeholder: 'comma separated values' })
+    .transform(stringToArray),
+  default_max_deposit_fee: yup.string().required().label("Max Deposit Fee"),
+  default_max_wire_fee: yup.string().required().label("Max Wire"),
+  default_wire_fee_amortization: yup.number().required().label("WireFee 
Amortization"),
+  // default_pay_delay: yup.number().required().label("Pay 
delay").transform(numberToDuration),
+  // default_wire_transfer_delay: yup.number().required().label("Wire transfer 
Delay").transform(numberToDuration),
+});
+
+interface Props {
+  active: boolean;
+  onCancel: () => void;
+  onConfirm: (i: MerchantBackend.Instances.InstanceConfigurationMessage) => 
void;
+}
+
+interface KeyValue {
+  [key: string]: string;
+}
+
+export default function CreateModal({ active, onCancel, onConfirm }: Props): 
VNode {
+  const [value, valueHandler] = useState((active || {}) as any)
+  const [errors, setErrors] = useState<KeyValue>({})
+
+  const submit = (): void => {
+    try {
+      schema.validateSync(value, { abortEarly: false })
+      onConfirm({ ...schema.cast(value), address: {}, jurisdiction: {}, 
default_wire_transfer_delay: { d_ms: 6000 }, default_pay_delay: { d_ms: 3000 } 
} as MerchantBackend.Instances.InstanceConfigurationMessage);
+    } catch (err) {
+      const errors = err.inner as yup.ValidationError[]
+      const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ 
...prev, [cur.path]: cur.message }), {})
+      setErrors(pathMessages)
+    }
+  }
+
+  return <ConfirmModal description="update instance" active={active} 
onConfirm={submit} onCancel={onCancel}>
+    {Object.keys(schema.fields).map(f => {
+
+      const info = schema.fields[f].describe()
+
+      // Just text field for now
+      return <div class="field is-horizontal">
+        <div class="field-label is-normal">
+          <label class="label">{info.label}</label>
+        </div>
+        <div class="field-body">
+          <div class="field">
+            <p class="control is-expanded has-icons-left">
+              <input class="input" type="text" 
placeholder={info?.meta?.placeholder} readonly={info?.meta?.readonly} name={f} 
value={value[f]} onChange={e => valueHandler(prev => ({ ...prev, [f]: 
e.currentTarget.value }))} />
+            </p>
+            {errors[f] ? <p class="help is-danger">{errors[f]}</p> : null}
+          </div>
+        </div>
+      </div>
+
+    })}
+
+  </ConfirmModal>
+}
\ No newline at end of file
diff --git a/src/routes/instances/DeleteAllModal.tsx 
b/src/routes/instances/DeleteAllModal.tsx
new file mode 100644
index 0000000..6f81e2c
--- /dev/null
+++ b/src/routes/instances/DeleteAllModal.tsx
@@ -0,0 +1,29 @@
+import { h, VNode } from "preact";
+import { MerchantBackend } from "../../declaration";
+
+interface Props {
+  element: MerchantBackend.Instances.Instance | null;
+  onCancel: () => void;
+  onConfirm: (i: MerchantBackend.Instances.Instance) => void;
+}
+
+export default function DeleteAllModal({ element, onCancel, onConfirm }: 
Props): VNode {
+  return <div class={element ? "modal is-active is-clipped" : "modal"}>
+    <div class="modal-background jb-modal-close" onClick={e => onCancel()} />
+    <div class="modal-card">
+      <header class="modal-card-head">
+        <p class="modal-card-title">Confirm action</p>
+        <button class="delete jb-modal-close" aria-label="close" onClick={e => 
onCancel()} />
+      </header>
+      <section class="modal-card-body">
+        <p>This will permanently delete instance "{element?.name}" with id 
<b>{element?.id}</b></p>
+        <p>Please confirm this action</p>
+      </section>
+      <footer class="modal-card-foot">
+        <button class="button jb-modal-close" onClick={e => onCancel()} 
>Cancel</button>
+        <button class="button is-danger jb-modal-close" onClick={element ? e 
=> onConfirm(element) : undefined} >Delete</button>
+      </footer>
+    </div>
+    <button class="modal-close is-large jb-modal-close" aria-label="close" 
onClick={e => onCancel()} />
+  </div>
+}
\ No newline at end of file
diff --git a/src/routes/instances/DeleteModal.tsx 
b/src/routes/instances/DeleteModal.tsx
new file mode 100644
index 0000000..c3d0d22
--- /dev/null
+++ b/src/routes/instances/DeleteModal.tsx
@@ -0,0 +1,16 @@
+import { h, VNode } from "preact";
+import { MerchantBackend } from "../../declaration";
+import ConfirmModal from "./ConfirmModal";
+
+interface Props {
+  element: MerchantBackend.Instances.Instance;
+  onCancel: () => void;
+  onConfirm: (i: MerchantBackend.Instances.Instance) => void;
+}
+
+export default function DeleteModal({ element, onCancel, onConfirm }: Props): 
VNode {
+  return <ConfirmModal description="delete instance" danger active 
onCancel={onCancel} onConfirm={() => onConfirm(element)}>
+    <p>This will permanently delete instance "{element.name}" with id 
<b>{element.id}</b></p>
+    <p>Please confirm this actionssss</p>
+  </ConfirmModal>
+}
diff --git a/src/routes/instances/Table.tsx b/src/routes/instances/Table.tsx
index c3a0572..8946867 100644
--- a/src/routes/instances/Table.tsx
+++ b/src/routes/instances/Table.tsx
@@ -1,88 +1,130 @@
 import { h, VNode } from "preact";
-import { MerchantBackend } from "../../declaration";
+import { useEffect, useState } from "preact/hooks";
+import { MerchantBackend, WidthId as WithId } from "../../declaration";
+import DeleteModal from './DeleteModal'
+import UpdateModal from './UpdateModal'
+import CreateModal from './CreateModal'
 
 interface Props {
   instances: MerchantBackend.Instances.Instance[];
+  onCreate: (d: MerchantBackend.Instances.InstanceConfigurationMessage) => 
void;
+  onUpdate: (id: string, d: 
MerchantBackend.Instances.InstanceReconfigurationMessage) => void;
+  onDelete: (id: string) => void;
+  onSelect: (id: string | null) => void;
+  selected: MerchantBackend.Instances.QueryInstancesResponse & WithId | 
undefined;
 }
 
-export default function Table({ instances }: Props): VNode {
-  return <div class="b-table has-pagination">
-    <div class="table-wrapper has-mobile-cards">
-      <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" value="false" />
-                <span class="check" />
-              </label>
-            </th>
-            <th />
-            <th>id</th>
-            <th>name</th>
-            <th>City</th>
-            <th>Progress</th>
-            <th>Created</th>
-            <th />
-          </tr>
-        </thead>
-        <tbody>
-          {instances.map(i => {
-            return <tr>
-              <td class="is-checkbox-cell">
-                <label class="b-checkbox checkbox">
-                  <input type="checkbox" value="false" />
-                  <span class="check" />
-                </label>
-              </td>
-              <td class="is-image-cell">
-                <div class="image">
-                  <img 
src="https://avatars.dicebear.com/4.5/api/female/rebecca-bauch.svg"; 
class="is-rounded" />
-                </div>
-              </td>
-              <td data-label="Name">Rebecca Bauch</td>
-              <td data-label="Company">Daugherty-Daniel</td>
-              <td data-label="City">South Cory</td>
-              <td data-label="Progress" class="is-progress-cell">
-                <progress max="100" class="progress is-small is-primary" 
value="79">79</progress>
-              </td>
-              <td data-label="Created">
-                <small class="has-text-grey is-abbr-like" title="Oct 25, 
2020">Oct 25, 2020</small>
-              </td>
-              <td class="is-actions-cell">
-                <div class="buttons is-right">
-                  <button class="button is-small is-primary" type="button">
-                    <span class="icon"><i class="mdi mdi-eye" /></span>
-                  </button>
-                  <button class="button is-small is-danger jb-modal" 
data-target="sample-modal" type="button">
-                    <span class="icon"><i class="mdi mdi-trash-can" /></span>
-                  </button>
-                </div>
-              </td>
-            </tr>
-          })}
+function toggleSelected<T>(id: T) {
+  return (prev: T[]): T[] => prev.indexOf(id) == -1 ? [...prev, id] : 
prev.filter(e => e != id)
+}
 
-        </tbody>
-      </table>
-    </div>
-    <div class="notification">
-      <div class="level">
-        <div class="level-left">
-          <div class="level-item">
-            <div class="buttons has-addons">
-              <button type="button" class="button is-active">1</button>
-              <button type="button" class="button">2</button>
-              <button type="button" class="button">3</button>
-            </div>
-          </div>
-        </div>
-        <div class="level-right">
-          <div class="level-item">
-            <small>Page 1 of 3</small>
-          </div>
+interface Actions {
+  element: MerchantBackend.Instances.Instance;
+  type: 'DELETE' | 'UPDATE';
+}
+
+function notEmpty<TValue>(value: TValue | null | undefined): value is TValue {
+  return value !== null && value !== undefined;
+}
+
+function buildActions(intances: MerchantBackend.Instances.Instance[], 
selected: string[], action: 'DELETE'): Actions[] {
+  return selected.map(id => intances.find(i => i.id === id))
+    .filter(notEmpty)
+    .map(id => ({ element: id, type: action }))
+}
+
+export default function Table({ instances, onCreate, onDelete, onSelect, 
onUpdate, selected }: Props): VNode {
+  const [toBeCreated, toBeCreatedHandler] = useState<boolean>(false)
+  const [actionQueue, actionQueueHandler] = useState<Actions[]>([]);
+  const [toBeDeleted, toBeDeletedHandler] = 
useState<MerchantBackend.Instances.Instance | null>(null)
+
+  const [rowSelection, rowSelectionHandler] = useState<string[]>([])
+
+  useEffect(() => {
+    if (actionQueue.length > 0 && !toBeDeleted && actionQueue[0].type == 
'DELETE') {
+      toBeDeletedHandler(actionQueue[0].element)
+      actionQueueHandler(actionQueue.slice(1))
+    }
+  }, [actionQueue, toBeDeleted])
+
+  useEffect(() => {
+    if (actionQueue.length > 0 && !selected && actionQueue[0].type == 
'UPDATE') {
+      onSelect(actionQueue[0].element.id)
+      actionQueueHandler(actionQueue.slice(1))
+    }
+  }, [actionQueue, selected])
+
+  return <div class="card has-table">
+    <header class="card-header">
+      <p class="card-header-title"><span class="icon"><i class="mdi 
mdi-account-multiple" /></span>Instances</p>
+      <button class={rowSelection.length > 0 ? "card-header-icon" : 
"card-header-icon is-hidden"} type="button" onClick={e => 
actionQueueHandler(buildActions(instances, rowSelection, 'DELETE'))} >
+        <span class="icon"><i class="mdi mdi-trash-can" /></span>
+      </button>
+      <button class="card-header-icon" type="button" onClick={e => 
toBeCreatedHandler(true)}>
+        <span class="icon"><i class="mdi mdi-plus" /></span>
+      </button>
+    </header>
+    <div class="card-content">
+      <div class="b-table has-pagination">
+        <div class="table-wrapper has-mobile-cards">
+          <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={e => rowSelectionHandler(rowSelection.length === 
instances.length ? [] : instances.map(i => i.id))} />
+                    <span class="check" />
+                  </label>
+                </th>
+                <th>id</th>
+                <th>name</th>
+                <th>public key</th>
+                <th>payments</th>
+                <th />
+              </tr>
+            </thead>
+            <tbody>
+              {instances.map(i => {
+                return <tr>
+                  <td class="is-checkbox-cell">
+                    <label class="b-checkbox checkbox">
+                      <input type="checkbox" 
checked={rowSelection.indexOf(i.id) != -1} onClick={e => 
rowSelectionHandler(toggleSelected(i.id))} />
+                      <span class="check" />
+                    </label>
+                  </td>
+                  <td >{i.id}</td>
+                  <td >{i.name}</td>
+                  <td >{i.merchant_pub}</td>
+                  <td >{i.payment_targets}</td>
+                  <td class="is-actions-cell">
+                    <div class="buttons is-right">
+                      <button class="button is-small is-primary" type="button" 
onClick={e => onSelect(i.id)}>
+                        <span class="icon"><i class="mdi mdi-eye" /></span>
+                      </button>
+                      <button class="button is-small is-danger jb-modal" 
type="button" onClick={e => toBeDeletedHandler(i)}>
+                        <span class="icon"><i class="mdi mdi-trash-can" 
/></span>
+                      </button>
+                    </div>
+                  </td>
+                </tr>
+              })}
+
+            </tbody>
+          </table>
         </div>
+        {toBeDeleted ? <DeleteModal element={toBeDeleted} onCancel={() => 
toBeDeletedHandler(null)} onConfirm={(i) => {
+          onDelete(i.id)
+          toBeDeletedHandler(null);
+        }} /> : null}
+        {selected ? <UpdateModal element={selected} onCancel={() => 
onSelect(null)} onConfirm={(i) => {
+          onUpdate(selected.id, i)
+          onSelect(null);
+        }} /> : null}
+        {toBeCreated ? <CreateModal active={toBeCreated} onCancel={() => 
toBeCreatedHandler(false)} onConfirm={(i) => {
+          onCreate(i)
+          toBeCreatedHandler(false);
+        }} /> : null}
       </div>
     </div>
-  </div>
-
+  </div >
 }
\ No newline at end of file
diff --git a/src/routes/instances/UpdateModal.stories.tsx 
b/src/routes/instances/UpdateModal.stories.tsx
new file mode 100644
index 0000000..db39d61
--- /dev/null
+++ b/src/routes/instances/UpdateModal.stories.tsx
@@ -0,0 +1,24 @@
+/* eslint-disable @typescript-eslint/camelcase */
+import { h } from 'preact';
+import UpdateModal from './UpdateModal'
+
+
+export default {
+  title: 'Instances/UpdateModal',
+  component: UpdateModal,
+  argTypes: {
+    element: { control: 'object' },
+    onCancel: { action: 'onCancel' },
+    onConfirm: { action: 'onConfirm' },
+  }
+};
+
+export const WithDefaultInstance = (a) => <UpdateModal {...a} />;
+WithDefaultInstance.args = {
+  element: {
+    id: 'default',
+    name: 'the default instance',
+    merchant_pub: 'abcdef',
+    payment_targets: ['qwe','asd']
+  }
+}
diff --git a/src/routes/instances/UpdateModal.tsx 
b/src/routes/instances/UpdateModal.tsx
new file mode 100644
index 0000000..1275911
--- /dev/null
+++ b/src/routes/instances/UpdateModal.tsx
@@ -0,0 +1,76 @@
+import { h, VNode } from "preact";
+import { useState } from "preact/hooks";
+import { MerchantBackend } from "../../declaration";
+import * as yup from 'yup';
+import ConfirmModal from "./ConfirmModal";
+
+function stringToArray(this: yup.AnySchema, current: any, original: string): 
string[] {
+  if (this.isType(current)) return current;
+  return original.split(',').filter(s => s.length > 0)
+}
+
+const schema = yup.object().shape({
+  name: yup.string().required().label("Name"),
+  payto_uris: yup.array().of(yup.string())
+    .min(1).label("Payment Method")
+    .meta({ placeholder: 'comma separated values' })
+    .transform(stringToArray),
+  default_max_deposit_fee: yup.string().required().label("Max Deposit Fee"),
+  default_max_wire_fee: yup.string().required().label("Max Wire"),
+  default_wire_fee_amortization: yup.number().required().label("WireFee 
Amortization"),
+  // default_pay_delay: yup.number().required().label("Pay 
delay").transform(numberToDuration),
+  // default_wire_transfer_delay: yup.number().required().label("Wire transfer 
Delay").transform(numberToDuration),
+});
+
+interface Props {
+  element: MerchantBackend.Instances.QueryInstancesResponse | null;
+  onCancel: () => void;
+  onConfirm: (i: MerchantBackend.Instances.InstanceReconfigurationMessage) => 
void;
+}
+
+interface KeyValue {
+  [key: string]: string;
+}
+
+export default function UpdateModal({ element, onCancel, onConfirm }: Props): 
VNode {
+  const copy = !element ? {} : Object.keys(schema.fields).reduce((prev,cur) => 
({...prev, [cur]: (element as any)[cur] }), {})
+
+  const [value, valueHandler] = useState(copy)
+  const [errors, setErrors] = useState<KeyValue>({})
+
+  const submit = (): void => {
+    try {
+      schema.validateSync(value, { abortEarly: false })
+
+      onConfirm({...schema.cast(value), address: {}, jurisdiction: {}, 
default_wire_transfer_delay: { d_ms: 6000 }, default_pay_delay: { d_ms: 3000 }} 
as MerchantBackend.Instances.InstanceReconfigurationMessage);
+    } catch (err) {
+      const errors = err.inner as yup.ValidationError[]
+      const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ 
...prev, [cur.path]: cur.message }), {})
+      setErrors(pathMessages)
+    }
+  }
+
+  return <ConfirmModal description="update instance" active={element != null} 
onConfirm={submit} onCancel={onCancel}>
+    {Object.keys(schema.fields).map(f => {
+
+      const info = schema.fields[f].describe()
+
+      // Just text field for now
+      return <div class="field is-horizontal">
+        <div class="field-label is-normal">
+          <label class="label">{info.label}</label>
+        </div>
+        <div class="field-body">
+          <div class="field">
+            <p class="control is-expanded has-icons-left">
+              <input class="input" type="text" 
placeholder={info?.meta?.placeholder} readonly={info?.meta?.readonly} name={f} 
value={value[f]} onChange={e => valueHandler(prev => ({ ...prev, [f]: 
e.currentTarget.value }))} />
+            </p>
+            {errors[f] ? <p class="help is-danger">{errors[f]}</p> : null}
+          </div>
+        </div>
+      </div>
+
+    })}
+
+  </ConfirmModal>
+}
\ No newline at end of file
diff --git a/src/routes/instances/View.stories.tsx 
b/src/routes/instances/View.stories.tsx
index a508298..208de17 100644
--- a/src/routes/instances/View.stories.tsx
+++ b/src/routes/instances/View.stories.tsx
@@ -13,23 +13,32 @@ export default {
   },
 };
 
-export const Empty = () => <View instances={[]} />
+export const Empty = (a) => <View {...a} />;
+Empty.args = {
+  instances: []
+}
 
-export const WithDefaultInstance = () => <View instances={[{
-  id: 'default',
-  name: 'the default instance',
-  merchant_pub: 'abcdef',
-  payment_targets: []
-}]} />
+export const WithDefaultInstance = (a) => <View {...a} />;
+WithDefaultInstance.args = {
+  instances: [{
+    id: 'default',
+    name: 'the default instance',
+    merchant_pub: 'abcdef',
+    payment_targets: []
+  }]
+}
 
-export const WithTwoInstance = () => <View instances={[{
-  id: 'first',
-  name: 'the first instance',
-  merchant_pub: 'abcdefgh',
-  payment_targets: []
-},{
-  id: 'second',
-  name: 'other instance',
-  merchant_pub: 'zxcvvbnm',
-  payment_targets: ['pay-to']
-}]} />
+export const WithTwoInstance = (a) => <View {...a} />;
+WithTwoInstance.args = {
+  instances: [{
+    id: 'first',
+    name: 'the first instance',
+    merchant_pub: 'abcdefgh',
+    payment_targets: []
+  },{
+    id: 'second',
+    name: 'other instance',
+    merchant_pub: 'zxcvvbnm',
+    payment_targets: ['pay-to']
+  }]
+}
diff --git a/src/routes/instances/View.tsx b/src/routes/instances/View.tsx
index b209726..6d357af 100644
--- a/src/routes/instances/View.tsx
+++ b/src/routes/instances/View.tsx
@@ -1,14 +1,41 @@
 import { h, VNode } from "preact";
-import { MerchantBackend } from "../../declaration";
+import { MerchantBackend, WidthId } from "../../declaration";
 import Table from './Table';
 
 interface Props {
   instances: MerchantBackend.Instances.Instance[];
+  onCreate: (d: MerchantBackend.Instances.InstanceConfigurationMessage) => 
void;
+  onUpdate: (id: string, d: 
MerchantBackend.Instances.InstanceReconfigurationMessage) => void;
+  onDelete: (id: string) => void;
+  onSelect: (id: string | null) => void;
+  selected: MerchantBackend.Instances.QueryInstancesResponse & WidthId | 
undefined;
 }
 
-export default function View({ instances }: Props): VNode {
+export default function View({ instances, onCreate, onDelete, onSelect, 
onUpdate, selected }: Props): VNode {
   return <div id="app">
+    <div class="toast">
+      <article class="message">
+        <div class="message-header">
+          <p>Normal message</p>
+          <button class="delete" aria-label="delete" />
+        </div>
+        <div class="message-body">
+          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+        </div>
+      </article>
+      <article class="message is-danger">
+        <div class="message-header">
+          <p>Normal message</p>
+          <button class="delete" aria-label="delete" />
+        </div>
+        <div class="message-body">
+          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+        </div>
+      </article>
+    </div>
+    
     <section class="section is-title-bar">
+
       <div class="level">
         <div class="level-left">
           <div class="level-item">
@@ -35,40 +62,12 @@ export default function View({ instances }: Props): VNode {
       </div>
     </section>
     <section class="section is-main-section">
-      <div class="card has-table">
-        <header class="card-header">
-          <p class="card-header-title">
-            <span class="icon"><i class="mdi mdi-account-multiple" /></span>
-          Instances
-        </p>
-          <a href="#" class="card-header-icon">
-            <span class="icon"><i class="mdi mdi-reload" /></span>
-          </a>
-        </header>
-        <div class="card-content">
-          <Table instances={instances} />
-        </div>
-      </div>
-
+      <Table instances={instances} onCreate={onCreate}
+        onUpdate={onUpdate}
+        onDelete={onDelete} onSelect={onSelect}
+        selected={selected}
+      />
     </section>
 
-    <div id="sample-modal" class="modal">
-      <div class="modal-background jb-modal-close" />
-      <div class="modal-card">
-        <header class="modal-card-head">
-          <p class="modal-card-title">Confirm action</p>
-          <button class="delete jb-modal-close" aria-label="close" />
-        </header>
-        <section class="modal-card-body">
-          <p>This will permanently delete <b>Some Object</b></p>
-          <p>This is sample modal</p>
-        </section>
-        <footer class="modal-card-foot">
-          <button class="button jb-modal-close">Cancel</button>
-          <button class="button is-danger jb-modal-close">Delete</button>
-        </footer>
-      </div>
-      <button class="modal-close is-large jb-modal-close" aria-label="close" />
-    </div>
-  </div>
+  </div >
 }
\ No newline at end of file
diff --git a/src/routes/instances/index.tsx b/src/routes/instances/index.tsx
index 0aeef3e..b83eee0 100644
--- a/src/routes/instances/index.tsx
+++ b/src/routes/instances/index.tsx
@@ -1,15 +1,22 @@
 import { h, VNode } from 'preact';
 import View from './View';
 import LoginPage from '../../components/auth/LoginPage';
-import { updateToken, useBackendInstances } from 
'../../components/hooks/backend';
+import { updateToken, useBackendInstance, useBackendInstances } from 
'../../components/hooks/backend';
+import { useState } from 'preact/hooks';
 
 
 export default function Instances(): VNode {
-  const resp = useBackendInstances()
+  const list    = useBackendInstances()
+  const [selectedId, select] = useState<string|null>(null)
+  const details = useBackendInstance(selectedId)
 
-  if (!resp.data) {
+  if (!list.data || (selectedId != null && !details.data)) {
     return <LoginPage onLogIn={updateToken} />
   }
 
-  return <View instances={resp.data.instances} />;
-}
\ No newline at end of file
+  return <View instances={list.data.instances} 
+    onCreate={list.create} onUpdate={details.update} 
+    onDelete={details.delete} onSelect={select}
+    selected={ !details.data || !selectedId ? undefined : {...details.data, 
id:selectedId} } 
+  />;
+}
diff --git a/src/scss/main.scss b/src/scss/main.scss
index 657a871..8f6ed75 100644
--- a/src/scss/main.scss
+++ b/src/scss/main.scss
@@ -20,3 +20,26 @@
 @import "modal";
 @import "footer";
 @import "misc";
+
+@import "fonts/nunito.css";
+@import "icons/materialdesignicons-4.9.95.min.css";
+
+.toast {
+  position: fixed;
+  right: 10px;
+  top: 10px;
+  z-index: 999;
+
+  display: flex;
+  flex-direction: column;
+  padding: 15px;
+  text-align: right;
+  align-items: flex-end;
+  width: auto;
+  pointer-events: none;
+}
+
+.toast > .message {
+  white-space:pre-wrap;
+  opacity:80%;
+}
diff --git a/yarn.lock b/yarn.lock
index 8fdddeb..303a427 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -960,7 +960,7 @@
     pirates "^4.0.0"
     source-map-support "^0.5.16"
 
-"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", 
"@babel/runtime@^7.12.5", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", 
"@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4":
+"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.5", 
"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.3.1", 
"@babel/runtime@^7.4.4", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", 
"@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7":
   version "7.12.13"
   resolved 
"https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.13.tgz#0a21452352b02542db0ffb928ac2d3ca7cb6d66d";
   integrity 
sha512-8+3UMPBrjFa/6TtKi/7sehPKqfAm4g6K+YQjyyFOLUTxzOngcRZTlAVY8sc2CORJYqdHQY8gRPHmn+qo15rCBw==
@@ -1018,7 +1018,7 @@
     exec-sh "^0.3.2"
     minimist "^1.2.0"
 
-"@emotion/cache@^10.0.27":
+"@emotion/cache@^10.0.27", "@emotion/cache@^10.0.9":
   version "10.0.29"
   resolved 
"https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0";
   integrity 
sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==
@@ -1028,7 +1028,7 @@
     "@emotion/utils" "0.11.3"
     "@emotion/weak-memoize" "0.2.5"
 
-"@emotion/core@^10.1.1":
+"@emotion/core@^10.0.9", "@emotion/core@^10.1.1":
   version "10.1.1"
   resolved 
"https://registry.yarnpkg.com/@emotion/core/-/core-10.1.1.tgz#c956c1365f2f2481960064bcb8c4732e5fb612c3";
   integrity 
sha512-ZMLG6qpXR8x031NXD8HJqugy/AZSkAuMxxqB46pmAR7ze47MhNJ56cdoX243QPZdGctrdfo+s08yZTiwaUcRKA==
@@ -1040,7 +1040,7 @@
     "@emotion/sheet" "0.9.4"
     "@emotion/utils" "0.11.3"
 
-"@emotion/css@^10.0.27":
+"@emotion/css@^10.0.27", "@emotion/css@^10.0.9":
   version "10.0.27"
   resolved 
"https://registry.yarnpkg.com/@emotion/css/-/css-10.0.27.tgz#3a7458198fbbebb53b01b2b87f64e5e21241e14c";
   integrity 
sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==
@@ -1514,6 +1514,28 @@
   dependencies:
     "@sinonjs/commons" "^1.7.0"
 
+"@storybook/addon-a11y@^6.1.17":
+  version "6.1.17"
+  resolved 
"https://registry.yarnpkg.com/@storybook/addon-a11y/-/addon-a11y-6.1.17.tgz#67fe6e140c6a1365f6547ac9458c454c9d7ad572";
+  integrity 
sha512-RBL0sx5FuNrPNW7GQaSdyly5WwsqD7FB+APPPFYvEbwyIksS5rZ3x2JnO2iM6UQxCkYxOL2Ou3ZPgJloXfwjxA==
+  dependencies:
+    "@storybook/addons" "6.1.17"
+    "@storybook/api" "6.1.17"
+    "@storybook/channels" "6.1.17"
+    "@storybook/client-api" "6.1.17"
+    "@storybook/client-logger" "6.1.17"
+    "@storybook/components" "6.1.17"
+    "@storybook/core-events" "6.1.17"
+    "@storybook/theming" "6.1.17"
+    axe-core "^4.0.1"
+    core-js "^3.0.1"
+    global "^4.3.2"
+    lodash "^4.17.15"
+    react-sizeme "^2.5.2"
+    regenerator-runtime "^0.13.7"
+    ts-dedent "^2.0.0"
+    util-deprecate "^1.0.2"
+
 "@storybook/addon-actions@6.1.17", "@storybook/addon-actions@^6.1.16":
   version "6.1.17"
   resolved 
"https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-6.1.17.tgz#9d32336284738cefa69b99acafa4b132d5533600";
@@ -1633,6 +1655,31 @@
     regenerator-runtime "^0.13.7"
     ts-dedent "^2.0.0"
 
+"@storybook/addon-knobs@^6.1.17":
+  version "6.1.17"
+  resolved 
"https://registry.yarnpkg.com/@storybook/addon-knobs/-/addon-knobs-6.1.17.tgz#c7cdd5be813c2b80ce7f464eabf8ceb06486e82d";
+  integrity 
sha512-WUkoGtHhXIurXFQybsMXZaphAtCNclZjZHvji8O5eg+ahx7pIM/Wldh3uJwOdOkW5LHxT76hLxPvuXvOEysnbw==
+  dependencies:
+    "@storybook/addons" "6.1.17"
+    "@storybook/api" "6.1.17"
+    "@storybook/channels" "6.1.17"
+    "@storybook/client-api" "6.1.17"
+    "@storybook/components" "6.1.17"
+    "@storybook/core-events" "6.1.17"
+    "@storybook/theming" "6.1.17"
+    copy-to-clipboard "^3.0.8"
+    core-js "^3.0.1"
+    escape-html "^1.0.3"
+    fast-deep-equal "^3.1.1"
+    global "^4.3.2"
+    lodash "^4.17.15"
+    prop-types "^15.7.2"
+    qs "^6.6.0"
+    react-color "^2.17.0"
+    react-lifecycles-compat "^3.0.4"
+    react-select "^3.0.8"
+    regenerator-runtime "^0.13.7"
+
 "@storybook/addon-links@^6.1.16":
   version "6.1.17"
   resolved 
"https://registry.yarnpkg.com/@storybook/addon-links/-/addon-links-6.1.17.tgz#53cd2f85a83006950cd86cef9975ae8311ac1de4";
@@ -1651,6 +1698,26 @@
     regenerator-runtime "^0.13.7"
     ts-dedent "^2.0.0"
 
+"@storybook/addon-storysource@^6.1.17":
+  version "6.1.17"
+  resolved 
"https://registry.yarnpkg.com/@storybook/addon-storysource/-/addon-storysource-6.1.17.tgz#8db1ce2851227a2fe705d1b7f2d6cd4cff786481";
+  integrity 
sha512-baRAlC8EErK0slK1GP8XgE34omiQP3zip7690yB2zj5aBdDiUUIjeBqzhluW840OEIGUrBicvLZaO8JmLSffTA==
+  dependencies:
+    "@storybook/addons" "6.1.17"
+    "@storybook/api" "6.1.17"
+    "@storybook/client-logger" "6.1.17"
+    "@storybook/components" "6.1.17"
+    "@storybook/router" "6.1.17"
+    "@storybook/source-loader" "6.1.17"
+    "@storybook/theming" "6.1.17"
+    core-js "^3.0.1"
+    estraverse "^4.2.0"
+    loader-utils "^2.0.0"
+    prettier "~2.0.5"
+    prop-types "^15.7.2"
+    react-syntax-highlighter "^13.5.0"
+    regenerator-runtime "^0.13.7"
+
 "@storybook/addon-toolbars@6.1.17":
   version "6.1.17"
   resolved 
"https://registry.yarnpkg.com/@storybook/addon-toolbars/-/addon-toolbars-6.1.17.tgz#15a015dc871e26be66340b5641631e649925c5e2";
@@ -2207,6 +2274,11 @@
   resolved 
"https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad";
   integrity 
sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==
 
+"@types/lodash@^4.14.165":
+  version "4.14.168"
+  resolved 
"https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.168.tgz#fe24632e79b7ade3f132891afff86caa5e5ce008";
+  integrity 
sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==
+
 "@types/markdown-to-jsx@^6.11.0":
   version "6.11.3"
   resolved 
"https://registry.yarnpkg.com/@types/markdown-to-jsx/-/markdown-to-jsx-6.11.3.tgz#cdd1619308fecbc8be7e6a26f3751260249b020e";
@@ -3062,6 +3134,11 @@ aws4@^1.8.0:
   resolved 
"https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59";
   integrity 
sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
 
+axe-core@^4.0.1:
+  version "4.1.2"
+  resolved 
"https://registry.yarnpkg.com/axe-core/-/axe-core-4.1.2.tgz#7cf783331320098bfbef620df3b3c770147bc224";
+  integrity 
sha512-V+Nq70NxKhYt89ArVcaNL9FDryB3vQOd+BFXZIfO3RP6rwtj+2yqqqdHEkacutglPaZLkJeuXKCjCJDMGPtPqg==
+
 axios@^0.21.1:
   version "0.21.1"
   resolved 
"https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8";
@@ -5327,6 +5404,14 @@ dom-converter@^0.2:
   dependencies:
     utila "~0.4"
 
+dom-helpers@^5.0.1:
+  version "5.2.0"
+  resolved 
"https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.0.tgz#57fd054c5f8f34c52a3eeffdb7e7e93cd357d95b";
+  integrity 
sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ==
+  dependencies:
+    "@babel/runtime" "^7.8.7"
+    csstype "^3.0.2"
+
 dom-serializer@0:
   version "0.2.2"
   resolved 
"https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51";
@@ -5769,7 +5854,7 @@ escape-goat@^2.0.0:
   resolved 
"https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675";
   integrity 
sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==
 
-escape-html@~1.0.3:
+escape-html@^1.0.3, escape-html@~1.0.3:
   version "1.0.3"
   resolved 
"https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988";
   integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
@@ -8993,7 +9078,7 @@ locate-path@^5.0.0:
   dependencies:
     p-locate "^4.1.0"
 
-lodash-es@^4.17.15:
+lodash-es@^4.17.11, lodash-es@^4.17.15:
   version "4.17.20"
   resolved 
"https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.20.tgz#29f6332eefc60e849f869c264bc71126ad61e8f7";
   integrity 
sha512-JD1COMZsq8maT6mnuz1UMV0jvYD0E0aUsSOdrr1/nAG3dhqQXwRRgeW0cSqH1U43INKcqxaiVIQNOUDld7gRDA==
@@ -9270,6 +9355,11 @@ media-typer@0.3.0:
   resolved 
"https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748";
   integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
 
+memoize-one@^5.0.0:
+  version "5.1.1"
+  resolved 
"https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0";
+  integrity 
sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==
+
 memoizerific@^1.11.3:
   version "1.11.3"
   resolved 
"https://registry.yarnpkg.com/memoizerific/-/memoizerific-1.11.3.tgz#7c87a4646444c32d75438570905f2dbd1b1a805a";
@@ -9592,6 +9682,11 @@ nan@^2.12.1, nan@^2.13.2:
   resolved 
"https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19";
   integrity 
sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==
 
+nanoclone@^0.2.1:
+  version "0.2.1"
+  resolved 
"https://registry.yarnpkg.com/nanoclone/-/nanoclone-0.2.1.tgz#dd4090f8f1a110d26bb32c49ed2f5b9235209ed4";
+  integrity 
sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==
+
 nanomatch@^1.2.9:
   version "1.2.13"
   resolved 
"https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119";
@@ -11109,7 +11204,7 @@ prompts@^2.0.1, prompts@^2.2.1:
     kleur "^3.0.3"
     sisteransi "^1.0.5"
 
-prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.6.0, 
prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
+prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.8, 
prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
   version "15.7.2"
   resolved 
"https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5";
   integrity 
sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@@ -11118,6 +11213,11 @@ prop-types@^15.0.0, prop-types@^15.5.10, 
prop-types@^15.6.0, prop-types@^15.6.1,
     object-assign "^4.1.1"
     react-is "^16.8.1"
 
+property-expr@^2.0.4:
+  version "2.0.4"
+  resolved 
"https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.4.tgz#37b925478e58965031bb612ec5b3260f8241e910";
+  integrity 
sha512-sFPkHQjVKheDNnPvotjQmm3KD3uk1fWKUN7CrpdbwmUx3CrG3QiM8QpTSimvig5vTXmTvjz7+TDvXOI9+4rkcg==
+
 property-information@^5.0.0, property-information@^5.3.0:
   version "5.6.0"
   resolved 
"https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69";
@@ -11420,6 +11520,13 @@ react-hotkeys@2.0.0:
   dependencies:
     prop-types "^15.6.1"
 
+react-input-autosize@^3.0.0:
+  version "3.0.0"
+  resolved 
"https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-3.0.0.tgz#6b5898c790d4478d69420b55441fcc31d5c50a85";
+  integrity 
sha512-nL9uS7jEs/zu8sqwFE5MAPx6pPkNAriACQ2rGLlqmKr2sPGtN7TXTyDdQt4lbNXVx7Uzadb40x8qotIuru6Rhg==
+  dependencies:
+    prop-types "^15.5.8"
+
 react-inspector@^5.0.1:
   version "5.1.0"
   resolved 
"https://registry.yarnpkg.com/react-inspector/-/react-inspector-5.1.0.tgz#45a325e15f33e595be5356ca2d3ceffb7d6b8c3a";
@@ -11466,7 +11573,21 @@ react-refresh@0.8.3:
   resolved 
"https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f";
   integrity 
sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==
 
-react-sizeme@^2.6.7:
+react-select@^3.0.8:
+  version "3.2.0"
+  resolved 
"https://registry.yarnpkg.com/react-select/-/react-select-3.2.0.tgz#de9284700196f5f9b5277c5d850a9ce85f5c72fe";
+  integrity 
sha512-B/q3TnCZXEKItO0fFN/I0tWOX3WJvi/X2wtdffmwSQVRwg5BpValScTO1vdic9AxlUgmeSzib2hAZAwIUQUZGQ==
+  dependencies:
+    "@babel/runtime" "^7.4.4"
+    "@emotion/cache" "^10.0.9"
+    "@emotion/core" "^10.0.9"
+    "@emotion/css" "^10.0.9"
+    memoize-one "^5.0.0"
+    prop-types "^15.6.0"
+    react-input-autosize "^3.0.0"
+    react-transition-group "^4.3.0"
+
+react-sizeme@^2.5.2, react-sizeme@^2.6.7:
   version "2.6.12"
   resolved 
"https://registry.yarnpkg.com/react-sizeme/-/react-sizeme-2.6.12.tgz#ed207be5476f4a85bf364e92042520499455453e";
   integrity 
sha512-tL4sCgfmvapYRZ1FO2VmBmjPVzzqgHA7kI8lSJ6JS6L78jXFNRdOZFpXyK6P1NBZvKPPCZxReNgzZNUajAerZw==
@@ -11496,6 +11617,16 @@ react-textarea-autosize@^8.1.1:
     use-composed-ref "^1.0.0"
     use-latest "^1.0.0"
 
+react-transition-group@^4.3.0:
+  version "4.4.1"
+  resolved 
"https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9";
+  integrity 
sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==
+  dependencies:
+    "@babel/runtime" "^7.5.5"
+    dom-helpers "^5.0.1"
+    loose-envify "^1.4.0"
+    prop-types "^15.6.2"
+
 react@16.13.1:
   version "16.13.1"
   resolved 
"https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e";
@@ -13330,6 +13461,11 @@ toposort@^1.0.0:
   resolved 
"https://registry.yarnpkg.com/toposort/-/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029";
   integrity sha1-LmhELZ9k7HILjMieZEOsbKqVACk=
 
+toposort@^2.0.2:
+  version "2.0.2"
+  resolved 
"https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330";
+  integrity sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=
+
 totalist@^1.0.0:
   version "1.1.0"
   resolved 
"https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df";
@@ -14573,6 +14709,19 @@ yocto-queue@^0.1.0:
   resolved 
"https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b";
   integrity 
sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
 
+yup@^0.32.8:
+  version "0.32.8"
+  resolved 
"https://registry.yarnpkg.com/yup/-/yup-0.32.8.tgz#16e4a949a86a69505abf99fd0941305ac9adfc39";
+  integrity 
sha512-SZulv5FIZ9d5H99EN5tRCRPXL0eyoYxWIP1AacCrjC9d4DfP13J1dROdKGfpfRHT3eQB6/ikBl5jG21smAfCkA==
+  dependencies:
+    "@babel/runtime" "^7.10.5"
+    "@types/lodash" "^4.14.165"
+    lodash "^4.17.20"
+    lodash-es "^4.17.11"
+    nanoclone "^0.2.1"
+    property-expr "^2.0.4"
+    toposort "^2.0.2"
+
 zwitch@^1.0.0:
   version "1.0.5"
   resolved 
"https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920";

-- 
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]