[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-merchant-backoffice] 01/02: better readme, updated makefile with
From: |
gnunet |
Subject: |
[taler-merchant-backoffice] 01/02: better readme, updated makefile with more commands, add config context, switch to nodejs 12 |
Date: |
Fri, 19 Feb 2021 21:12:25 +0100 |
This is an automated email from the git hooks/post-receive script.
sebasjm pushed a commit to branch master
in repository merchant-backoffice.
commit 6aba8b53ce84c6b723a5c8c31179fd23d132d7c7
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Fri Feb 19 17:00:31 2021 -0300
better readme, updated makefile with more commands, add config context,
switch to nodejs 12
---
README.md | 47 ++++++++++++++--------
build-system/Makefile | 28 ++++++++++---
package.json | 2 +
packages/frontend/.storybook/preview.js | 11 ++++-
packages/frontend/src/components/auth/index.tsx | 2 +-
packages/frontend/src/components/yup/YupField.tsx | 47 ++++++++++++++--------
packages/frontend/src/context/backend.ts | 11 +++++
.../frontend/src/{components => }/hooks/backend.ts | 2 +-
.../frontend/src/{components => }/hooks/index.ts | 0
packages/frontend/src/index.tsx | 44 +++++++++++---------
.../src/routes/instances/Create.stories.tsx | 20 ++++-----
.../frontend/src/routes/instances/CreatePage.tsx | 7 +++-
.../frontend/src/routes/instances/UpdatePage.tsx | 8 +++-
packages/frontend/src/routes/instances/index.tsx | 2 +-
14 files changed, 156 insertions(+), 75 deletions(-)
diff --git a/README.md b/README.md
index eb23b20..4fb7a7e 100644
--- a/README.md
+++ b/README.md
@@ -4,38 +4,53 @@ Merchant Admin Frontend is a Single Page Application that
connect with a running
## System requirements
-- Node version: 14.15.0
-- Yarn version: 1.21.1
+- Node: v12.18.4
+- pnpm: 5.17.2
+- make
+- python>=3.8
-## Environment
+## Compiling from source
-This applications use some configuration from the environment, like the
location of the Merchant Backend.
-Be sure to copy the file `template.env` into `.env` and override with your
custom values.
-## Installation
+Check the requirements and run `./bootstrap` and `./configure`
-First run the command `yarn install` to get all the dependencies.
-The running `yarn dev` should set the server up and running.
-Use the browser to navigate into `http://localhost:8080`
+```shell
+./bootstrap
+./configure
+```
+
+Then run `make` to install all the nodejs dependencies
+
+## Running develop
+
+To run a development server run
+
+```shell
+make dev
+```
+
+This should start a watch process that will reload the server every time that
a file is saved.
+
+## Building for deploy
## CLI Commands
-* `yarn install`: Installs dependencies
+* `make compile`: Installs dependencies and compile with typescript
-* `yarn dev`: Run a development, HMR server. The application will
automatically refresh
+* `make dev`: Run a development, HMR server. The application will
automatically refresh
every time a file is edited
-* `yarn build`: Production-ready build into the `./build` directory. Print
bundle size
+* `make build`: Production-ready build into the `./build` directory. Print
bundle size
information and compare its with previous build using the
`size-plugin.json` file.
-* `yarn serve`: Serves the content into `./build` directory, usefull to test
the result.
+* `make serve`: build and serves the content, usefull to test the result.
-* `yarn lint`: Pass TypeScript files using ESLint
+* `make lint`: Pass TypeScript files using ESLint
-* `yarn test`: Run Jest and Enzyme with
+* `make check`: Run Jest and Enzyme with
[`enzyme-adapter-preact-pure`](https://github.com/preactjs/enzyme-adapter-preact-pure)
for
your tests
-* `yarn storybook`: Run visual components explorer. Usefull for components
design and development
+* `make dev-views`: Run visual components explorer. Usefull for components
design and development
without the need of setting up the whole system.
diff --git a/build-system/Makefile b/build-system/Makefile
index 36279d5..c819c48 100644
--- a/build-system/Makefile
+++ b/build-system/Makefile
@@ -15,13 +15,13 @@ compile:
pnpm i -r
pnpm run compile
-.PHONY: dist
-dist:
- $(git-archive-all) --include ./configure taler-wallet-$(shell git
describe --tags).tar.gz
+# .PHONY: dist
+# dist:
+# $(git-archive-all) --include ./configure taler-wallet-$(shell git
describe --tags).tar.gz
-.PHONY: publish
-publish: compile
- pnpm publish -r --no-git-checks
+# .PHONY: publish
+# publish: compile
+# pnpm publish -r --no-git-checks
# make documentation from docstrings
.PHONY: typedoc
@@ -32,6 +32,10 @@ typedoc:
clean:
pnpm run clean
+.PHONY: build
+build:
+ pnpm run build
+
.PHONY: submodules-update
submodules-update:
git submodule update --recursive --remote
@@ -40,6 +44,18 @@ submodules-update:
check: compile
pnpm run check
+.PHONY: dev
+dev: compile
+ pnpm run --filter merchant-backoffice dev
+
+.PHONY: serve
+serve: build
+ pnpm run --filter merchant-backoffice serve
+
+.PHONY: dev-view
+dev-view: compile
+ pnpm run --filter merchant-backoffice storybook
+
.PHONY: lint
lint:
pnpm run lint
diff --git a/package.json b/package.json
index 12ef94d..99a785d 100644
--- a/package.json
+++ b/package.json
@@ -3,6 +3,8 @@
"scripts": {
"clean": "pnpm run --filter '{packages}' clean",
"compile": "pnpm run --filter '{packages}' compile",
+ "build": "pnpm run --filter '{packages}' build",
+ "serve": "pnpm run --filter '{packages}' serve",
"lint": "pnpm run --filter '{packages}' lint",
"typedoc": "pnpm run --filter '{packages}' typedoc",
"pretty": "pnpm run --filter '{packages}' pretty",
diff --git a/packages/frontend/.storybook/preview.js
b/packages/frontend/.storybook/preview.js
index edb0805..2c732ec 100644
--- a/packages/frontend/.storybook/preview.js
+++ b/packages/frontend/.storybook/preview.js
@@ -1,7 +1,13 @@
import "../src/scss/main.scss"
import { IntlProvider } from 'preact-i18n';
import { h } from "preact";
-import lang from '../src/i18n'
+import { translations } from '../src/i18n'
+import { ConfigContext } from '../src/context/backend'
+
+const mockConfig = {
+ backendURL: 'http://demo.taler.net',
+ currency: 'KUDOS'
+}
export const parameters = {
controls: { expanded: true },
@@ -25,8 +31,9 @@ export const globalTypes = {
export const decorators = [
(Story, { globals }) => {
- return <IntlProvider definition={lang[globals.locale]} mark>
+ return <IntlProvider definition={translations[globals.locale]} mark>
<Story />
</IntlProvider>
},
+ (Story) => <ConfigContext.Provider value={mockConfig}> <Story />
</ConfigContext.Provider>
];
diff --git a/packages/frontend/src/components/auth/index.tsx
b/packages/frontend/src/components/auth/index.tsx
index b6541a4..6ec69c0 100644
--- a/packages/frontend/src/components/auth/index.tsx
+++ b/packages/frontend/src/components/auth/index.tsx
@@ -21,7 +21,7 @@
import { h, VNode } from "preact";
import { useState } from "preact/hooks";
-import { useBackend } from "../hooks";
+import { useBackend } from "../../hooks";
interface Props {
onConfirm?: () => void;
diff --git a/packages/frontend/src/components/yup/YupField.tsx
b/packages/frontend/src/components/yup/YupField.tsx
index 7c08cda..5bbcf33 100644
--- a/packages/frontend/src/components/yup/YupField.tsx
+++ b/packages/frontend/src/components/yup/YupField.tsx
@@ -21,9 +21,7 @@
import { h, VNode } from "preact";
import { Text, useText } from "preact-i18n";
-import { useState } from "preact/hooks";
-import { useBackendConfig } from "../hooks/backend";
-import { useBackend } from "../hooks";
+import { StateUpdater, useContext, useState } from "preact/hooks";
import { intervalToDuration, formatDuration } from 'date-fns'
function readableDuration(duration: number): string {
@@ -33,7 +31,7 @@ function readableDuration(duration: number): string {
// customFormatDuration({ start: 0, end: 10800 * 1000}) // 3 hours
// customFormatDuration({ start: 0, end: 108000 * 1000}) // 1 day 6 hours
-interface Props {
+interface PropsInputInternal {
name: string;
value: string;
readonly?: boolean;
@@ -41,7 +39,7 @@ interface Props {
onChange: any;
}
-interface Props2 {
+interface PropsObject {
name: string;
info: any;
value: any;
@@ -49,8 +47,17 @@ interface Props2 {
onChange: any;
}
+interface Props {
+ name: string;
+ field: string;
+ errors: any;
+ object: any;
+ valueHandler: StateUpdater<any>;
+ info: any;
+}
+import { ConfigContext } from '../../context/backend';
-export function YupField(name: string, field: string, errors: any, object:
any, valueHandler: any, info: any): VNode {
+export function YupField({ name, field, errors, object, valueHandler, info }:
Props): VNode {
const updateField = (f: string) => (v: string): void => valueHandler((prev:
any) => ({ ...prev, [f]: v }))
const values = {
name, errors,
@@ -58,9 +65,7 @@ export function YupField(name: string, field: string, errors:
any, object: any,
value: object && object[field],
onChange: updateField(field)
}
- const [backend] = useBackend()
- const { data } = useBackendConfig()
- const currency = data?.currency || ''
+ const config = useContext(ConfigContext)
switch (info.meta?.type) {
case 'group': return <YupObjectInput name={name}
@@ -69,8 +74,13 @@ export function YupField(name: string, field: string,
errors: any, object: any,
onChange={(updater: any): void => valueHandler((prev: any) => ({
...prev, [field]: updater(prev[field]) }))}
/>
case 'array': return <YupInputArray {...values} />;
- case 'amount': return <YupInputWithAddon {...values} addon={currency}
onChange={(v: string): void => values.onChange(`${currency}:${v}`)}
value={values.value?.split(':')[1]} />;
- case 'url': return <YupInputWithAddon {...values}
addon={`${backend.url}/private/instances/`} />;
+ case 'amount': {
+ if (config.currency) {
+ return <YupInputWithAddon {...values} addon={config.currency}
onChange={(v: string): void => values.onChange(`${config.currency}:${v}`)}
value={values.value?.split(':')[1]} />
+ }
+ return <YupInput {...values} />;
+ }
+ case 'url': return <YupInputWithAddon {...values}
addon={`${config.backendURL}/private/instances/`} />;
case 'secured': return <YupInputSecured {...values} />;
case 'duration': return <YupInputWithAddon
addon={readableDuration(values.value?.d_ms)} atTheEnd {...values}
value={`${values.value?.d_ms / 1000 || ''}`} onChange={(v: string): void =>
values.onChange({ d_ms: (parseInt(v, 10) * 1000) || undefined } as any)} />;
default: return <YupInput {...values} />;
@@ -78,7 +88,7 @@ export function YupField(name: string, field: string, errors:
any, object: any,
}
}
-function YupObjectInput({ name, info, value, errors, onChange }: Props2):
VNode {
+function YupObjectInput({ name, info, value, errors, onChange }: PropsObject):
VNode {
const [active, setActive] = useState(false)
return <div class="card">
<header class="card-header">
@@ -95,13 +105,16 @@ function YupObjectInput({ name, info, value, errors,
onChange }: Props2): VNode
</header>
<div class={active ? "card-content" : "is-hidden"}>
<div class="content">
- {Object.keys(info.fields).map(f => YupField(`${name}.${f}`, f, errors,
value, onChange, info.fields[f]))}
+ {Object.keys(info.fields).map(f => <YupField name={`${name}.${f}`}
+ field={f} errors={errors} object={value}
+ valueHandler={onChange} info={info.fields[f]}
+ />)}
</div>
</div>
</div>
}
-function YupInput({ name, readonly, value, errors, onChange }: Props): VNode {
+function YupInput({ name, readonly, value, errors, onChange }:
PropsInputInternal): VNode {
const dict = useText({
placeholder: `fields.instance.${name}.placeholder`,
tooltip: `fields.instance.${name}.tooltip`,
@@ -133,7 +146,7 @@ function YupInput({ name, readonly, value, errors, onChange
}: Props): VNode {
</div>
}
-function YupInputArray({ name, readonly, value, errors, onChange }: Props):
VNode {
+function YupInputArray({ name, readonly, value, errors, onChange }:
PropsInputInternal): VNode {
const dict = useText({
placeholder: `fields.instance.${name}.placeholder`,
tooltip: `fields.instance.${name}.tooltip`,
@@ -184,7 +197,7 @@ function YupInputArray({ name, readonly, value, errors,
onChange }: Props): VNod
</div>
}
-function YupInputWithAddon({ name, readonly, value, errors, onChange, addon,
atTheEnd }: Props & { addon: string; atTheEnd?: boolean }): VNode {
+function YupInputWithAddon({ name, readonly, value, errors, onChange, addon,
atTheEnd }: PropsInputInternal & { addon: string; atTheEnd?: boolean }): VNode {
const dict = useText({
placeholder: `fields.instance.${name}.placeholder`,
tooltip: `fields.instance.${name}.tooltip`,
@@ -222,7 +235,7 @@ function YupInputWithAddon({ name, readonly, value, errors,
onChange, addon, atT
</div>
}
-function YupInputSecured({ name, readonly, value, errors, onChange }: Props):
VNode {
+function YupInputSecured({ name, readonly, value, errors, onChange }:
PropsInputInternal): VNode {
const dict = useText({
placeholder: `fields.instance.${name}.placeholder`,
tooltip: `fields.instance.${name}.tooltip`,
diff --git a/packages/frontend/src/context/backend.ts
b/packages/frontend/src/context/backend.ts
new file mode 100644
index 0000000..beb6a1b
--- /dev/null
+++ b/packages/frontend/src/context/backend.ts
@@ -0,0 +1,11 @@
+import { createContext } from 'preact'
+
+interface GlobalContext {
+ backendURL: string;
+ currency?: string;
+}
+
+export const ConfigContext = createContext<GlobalContext>({
+ backendURL: '',
+ currency: '',
+})
diff --git a/packages/frontend/src/components/hooks/backend.ts
b/packages/frontend/src/hooks/backend.ts
similarity index 98%
rename from packages/frontend/src/components/hooks/backend.ts
rename to packages/frontend/src/hooks/backend.ts
index 360f87e..0804c7b 100644
--- a/packages/frontend/src/components/hooks/backend.ts
+++ b/packages/frontend/src/hooks/backend.ts
@@ -21,7 +21,7 @@
import useSWR, { mutate } from 'swr';
import axios from 'axios'
-import { MerchantBackend } from '../../declaration';
+import { MerchantBackend } from '../declaration';
type HttpResponse<T> = HttpResponseOk<T> | HttpResponseError<T>;
diff --git a/packages/frontend/src/components/hooks/index.ts
b/packages/frontend/src/hooks/index.ts
similarity index 100%
rename from packages/frontend/src/components/hooks/index.ts
rename to packages/frontend/src/hooks/index.ts
diff --git a/packages/frontend/src/index.tsx b/packages/frontend/src/index.tsx
index 8d7e3ab..c613514 100644
--- a/packages/frontend/src/index.tsx
+++ b/packages/frontend/src/index.tsx
@@ -14,10 +14,10 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
- /**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
+/**
+*
+* @author Sebastian Javier Marchano (sebasjm)
+*/
import "./scss/main.scss"
@@ -29,28 +29,36 @@ import { Footer } from './components/footer';
import { Sidebar } from './components/sidebar';
import { NavigationBar } from './components/navbar';
import { Notifications } from './components/notifications';
-import { useNotifications } from './hooks/notifications';
import { translations } from './i18n';
-import { useLang } from './components/hooks';
+import { useBackend, useLang } from './hooks';
import NotFoundPage from './routes/notfound';
import Instances from './routes/instances';
+import { useNotifications } from "./hooks/notifications";
+import { ConfigContext } from './context/backend';
+import { useBackendConfig } from "./hooks/backend";
export default function App(): VNode {
const { notifications, pushNotification } = useNotifications()
const [lang, setLang] = useLang()
+ const [{url: backendURL}] = useBackend();
+ const { data } = useBackendConfig();
+
return (
- <IntlProvider definition={(translations as any)[lang] || translations.en}>
- <div id="app">
- <NavigationBar lang={lang} setLang={setLang} />
- <Sidebar />
- <Notifications notifications={notifications} />
- <Router>
- <Route path="/" component={Instances}
pushNotification={pushNotification} />
- <Route default component={NotFoundPage} />
- </Router>
- <Footer />
- </div>
- </IntlProvider >
+ <ConfigContext.Provider value={{backendURL, currency: data &&
data.currency}}>
+
+ <IntlProvider definition={(translations as any)[lang] ||
translations.en}>
+ <div id="app">
+ <NavigationBar lang={lang} setLang={setLang} />
+ <Sidebar />
+ <Notifications notifications={notifications} />
+ <Router>
+ <Route path="/" component={Instances}
pushNotification={pushNotification} />
+ <Route default component={NotFoundPage} />
+ </Router>
+ <Footer />
+ </div>
+ </IntlProvider >
+ </ConfigContext.Provider>
);
}
\ No newline at end of file
diff --git a/packages/frontend/src/routes/instances/Create.stories.tsx
b/packages/frontend/src/routes/instances/Create.stories.tsx
index fb8e113..28ab52a 100644
--- a/packages/frontend/src/routes/instances/Create.stories.tsx
+++ b/packages/frontend/src/routes/instances/Create.stories.tsx
@@ -14,23 +14,25 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
- /**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
+/**
+*
+* @author Sebastian Javier Marchano (sebasjm)
+*/
import { h, VNode } from 'preact';
-import {CreatePage} from './CreatePage'
+import { CreatePage } from './CreatePage'
export default {
- title: 'Instances/CreateModal',
+ title: 'Instances/Create',
component: CreatePage,
argTypes: {
- element: { control: 'object' },
- onCancel: { action: 'onCancel' },
- onConfirm: { action: 'onConfirm' },
+ onCreate: { action: 'onCreate' },
+ goBack: { action: 'goBack' },
}
};
export const Example = (a: any): VNode => <CreatePage {...a} />;
+Example.args = {
+ isLoading: false
+}
diff --git a/packages/frontend/src/routes/instances/CreatePage.tsx
b/packages/frontend/src/routes/instances/CreatePage.tsx
index ba32100..7f16c2d 100644
--- a/packages/frontend/src/routes/instances/CreatePage.tsx
+++ b/packages/frontend/src/routes/instances/CreatePage.tsx
@@ -60,7 +60,6 @@ export function CreatePage({ onCreate, isLoading, goBack }:
Props): VNode {
setErrors(pathMessages)
}
}
-
return <div>
<section class="section is-title-bar">
@@ -97,7 +96,11 @@ export function CreatePage({ onCreate, isLoading, goBack }:
Props): VNode {
<div class="columns">
<div class="column" />
<div class="column is-two-thirds">
- {Object.keys(schema.fields).map(f => YupField(f, f, errors, value,
valueHandler, schema.fields[f].describe()))}
+ {Object.keys(schema.fields)
+ .map(f => <YupField name={f}
+ field={f} errors={errors} object={value}
+ valueHandler={valueHandler} info={schema.fields[f].describe()}
+ />)}
<div class="buttons is-right">
<button class="button" onClick={goBack} ><Text id="cancel"
/></button>
<button class="button is-success" onClick={submit} ><Text
id="confirm" /></button>
diff --git a/packages/frontend/src/routes/instances/UpdatePage.tsx
b/packages/frontend/src/routes/instances/UpdatePage.tsx
index fc62337..feed125 100644
--- a/packages/frontend/src/routes/instances/UpdatePage.tsx
+++ b/packages/frontend/src/routes/instances/UpdatePage.tsx
@@ -101,8 +101,12 @@ export function UpdatePage({ onUpdate, isLoading,
selected, goBack }: Props): VN
<div class="columns">
<div class="column" />
<div class="column is-two-thirds">
- {Object.keys(schema.fields).map(f => YupField(f, f, errors, value,
valueHandler, schema.fields[f].describe()))}
- <div class="buttons is-right">
+ {Object.keys(schema.fields)
+ .map(f => <YupField name={f}
+ field={f} errors={errors} object={value}
+ valueHandler={valueHandler} info={schema.fields[f].describe()}
+ />)}
+ <div class="buttons is-right">
<button class="button" onClick={goBack} ><Text id="cancel"
/></button>
<button class="button is-success" onClick={submit} ><Text
id="confirm" /></button>
</div>
diff --git a/packages/frontend/src/routes/instances/index.tsx
b/packages/frontend/src/routes/instances/index.tsx
index 4715424..e44b087 100644
--- a/packages/frontend/src/routes/instances/index.tsx
+++ b/packages/frontend/src/routes/instances/index.tsx
@@ -22,7 +22,7 @@
import { h, VNode } from 'preact';
import { View } from './View';
import { LoginPage } from '../../components/auth';
-import { useBackendInstance, useBackendInstances } from
'../../components/hooks/backend';
+import { useBackendInstance, useBackendInstances } from '../../hooks/backend';
import { useEffect, useState } from 'preact/hooks';
import { Notification } from '../../declaration';
import { CreatePage } from './CreatePage';
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.