jambonz webapp refresh (#64)

initial scaffold

switch to preact/compat

add feather icons dep

jambonz-ui, index.html

stub auth and store

readme tweaks

alias preact in vite config

more readme tweaks

Update README.md

lots of things

login flow...

add notes on apis by route

lots of work...

readmes

constants

Update login.tsx

Update index.ts

Update index.ts

Update create-password.tsx

Update actions.ts

Update index.tsx

Update index.tsx

Update actions.ts

Update index.ts

react version for eslint

some refactor and cleanup

Update api.ts

Update create-password.tsx

fetch transport wrapper

api util

toast time -- oops

msg constants

img path for docs/readmes

global dispatch, generic actions etc...

unreachable and stuff

properly wrap require-auth routes

support promise chain and async/await for api fetch transport

initial responsive navi menu

Update navi-data.ts

Update navi.tsx

Update styles.scss

Rename navi-data.ts to navi-items.ts

Update navi.tsx

Update index.ts

Update layout.tsx

Update index.ts

Update layout.tsx

Update index.tsx

Update index.tsx

Update actions.ts

Update index.tsx

Update index.tsx

Update create-password.tsx

Update login.tsx

Update create-password.tsx

move things around

access control interface

Update index.tsx

acl component etc

working on settings form..

more settings, forms, HOCs

service providers workflow

button up modals and toasts

mobile navi and toast timeout

Update index.tsx

Update index.ts

Update and rename index.ts to index.tsx

Update create-password.tsx

Update create-password.tsx

Update Dockerfile

Update entrypoint.sh

Update Dockerfile

Update navi.tsx

Update auth.tsx

Update auth.tsx

Update layout.tsx

Update layout.tsx

Update login.tsx

Update login.tsx

Update settings.tsx

Update index.tsx

Update index.ts

better lint-staged

fix sp undefined

toast dispatch helpers

sass vars -- no magic numbers

Update index.ts

Update create-password.tsx

Update login.tsx

Update index.ts

Update settings.tsx

Update accounts.tsx

working on settings...

Update index.ts

Update settings.tsx

Update index.tsx

more settings view...

get rid of most any usage

Update index.tsx

better api hook

get strong with types

obscured text component

HOC for dispatch type-safety

tweak api types

github icon on login layout

responsive grid -- api keys

better fetch transport with resolve/reject

fix generic action/dispatch typings

prefer interface for GlobalDispatch

Update index.ts

Update auth.tsx

Update auth.tsx

Update create-password.tsx

checkzones

wrap up checkzones

move styles around...

alias src

stub internal views

stub not found container

contrib readme and codeowners

Update README.md

Update and rename setup.md to environment.md

Update environment.md

Update environment.md

Update contrib.md

Update contrib.md

Update contrib.md

Update and rename contrib.md to contributors.md

Update contributors.md

Update index.ts

use api data hook

accounts stub, generic apikeys container

account edit form

Update edit.tsx

Update edit.tsx

add/edit for account form

lots of good refactors

check current sp on settings

grid stuff

Update index.scss

Update styles.scss

Update contributors.md

Update constants.ts

stubbing accounts as card view

Update types.ts

Update types.ts

Update auth.tsx

Update create-password.tsx

Update index.ts

Update index.tsx

fix enum status codes

component cleanup

delete account flow

Update types.ts

Update delete.tsx

Update use-mobile-media.ts

acl hoc

Update types.ts

Update index.ts

Update types.ts

fix generic useapidata

Update types.ts

Update types.ts

Update types.ts

Create index.tsx

Create types.ts

Update types.ts

Create types.ts

Update index.tsx

button up acl, feature flags and docs

subspace initial feature stub

fix some things

wrap up subspace feature

tooltip

Update subspace.tsx

Delete styles.scss

Update types.ts

Update auth.tsx

Update index.ts

some more type stuff

add react/jsx-key error for missing shorthand frag keys

basic spinner...

no accounts

data files for regions and speech

vendor selector logic

tighten up vendor stuff

bit more cleanup

Update types.ts

Update index.tsx

Update index.tsx

Update subspace.tsx

fix some type things

stub mock dev server implementation

add parity for account siprec_hook_sid

latest jambonz-ui update

cleanup package.json

fix docker stuff

docker notes in readme

adding github actions

package lock version

remove unused jest deps

update jambonz-ui

new new jambonz-ui

list view vs cards view

fix no accounts list view

fix prettier config

some house cleaning

file upload component

update pr-checks wildcard

wrappers for fetch transport -- any method (#78)

Refresh tweaks (#80)

* add alerts to mock api dev server

add webhook methods types

fix focus for file upload

update contrib readme

blob fetching

rest props spread for file-upload

* multi element fieldset structure, unique basic auth field names for accounts form

* Fix and simplify webhook state setting

* some ad-hoc cleanup for temp work

Adding generic account filter component (#82)

adding focused styles for account-filter

more robust account-filter props

updates to contrib readme

fix add service provider form a la new styles

required form field UI and labeling

Application page for refresh  (#79)

* Adding barely working Application page (#70)

* resolve conflict and update, still barely working

* perfectly working application page

* Fix the duplicated name logic

* strip some comments

* changes to sync

* delete more condition

* some more changes for parity

* revert changes

* applying b1a9a77

* changes requested

* changes suggested

* changes suggested

* sync changes

organize some styles a bit more

refactor generic small selector styles

use portals for modals and toasts

add new classNames to applications form

handle applications view without accounts condition

sweep through with some cleanup

type-safety for :POST and :PUT api methods

Speech service page for refresh (#84)

* initial commit

* more update, probably one more

* properly rebase

* check box works okay

* properly rebase**2

* initial cleanup and ux-flow evaluation

* obscure secrets on frontend for local state

* refine ui for credential status checks

* ignore error set on unmount for CredentialStatus

* fix obscure field type crash bug

* Update utils.ts

* Update utils.ts

* Update constants.ts

* wrap up the speech credentials flow

Co-authored-by: kitajchuk <bk@kitajchuk.com>

tweaks to ui elements etc

tweak some typings and minor ui styles

better not tested messaging for TTS/STT

better placeholder feature flag for dev

Adding some conditional utilities (#87)

Microsoft Tenant page for refresh (#86)

* initial commit

* fix backend error with adding

* changes suggested

* changes requested

* use all accounts for ms teams tenants

* ui tweaks, add last ditch redirect back to form

Co-authored-by: kitajchuk <bk@kitajchuk.com>

Phone number page for refresh (#85)

* initial commit so I can hop back

* working properly

* carrier related change and mass edit

* mvoing around

* UI for mass edit

* unset selected for mass edit

* some minor ui cleanup

* fix empty/bad classNames on edit action icon

Co-authored-by: kitajchuk <bk@kitajchuk.com>

Update .dockerignore

cleanup and port some helpers

fix applications index useEffect

group synthesis fields and recognizer fields for application form

tweak contrib readme

just run tsc in pre-commit

update contrib readme

Carrier page for refresh  (#89)

* initial commit

* working form but no put/post for gateways yet

* put/post for sip/smpp

* crud app done

* all the functionalities are here, unless it isnt

* changes suggested and delete sip/smpp when delete carrier

* Some initial UI cleanup etc...

* More UI cleanup and what not...

* No need for the 'Status' text here

* Remove the Grid component -- not reused

* Remove as much explicit null type as possible

* Use webhook methods constant in account form

* Some API constants and fix inbound/outbound smpp gateways delete with filter logic

* Tab handling logic for carrier form (#91)

* similar validation logic of sip for smpp

* Tech prefix tab validation

* revert to working sip gateway validation

* More validation cleanup

* Update index.ts

* Update index.ts

* More cleanup and form clarity for if/when required fields

* Fix some logic and reset gateways to delete when deleted

* use api data hooks for index partials

* smpp gateway validation and fqdn validations

* default application selector

* Fix up the SMPP dilemma...

* Typo and remove console log

* Tab switch for all validations

* Move empty SIP check to validation getter

* Render gateway validation messages near the invalid fields

* Explicit return on first active tab condition for browser constraints

* Use IP pattern for outbound smpp gateway since fqdn is disallowed here

* Add fqdn example to ip placeholders

* sticky tabs

* Tweak info text

* Gateway refetch code change

* delete gateways on demand

* move shared api fetching down into forms -- seems better actually

* Fix re-render glitch for gateways UI

Co-authored-by: kitajchuk <bk@kitajchuk.com>

Tweaks and minor cleanups

Few more minor tweaks

prettier package.json -- duh

Functional recent-calls dev server api

switch from moment to dayjs

Functional alerts dev server api

Dev server notes in readme

Fix applications bug which fixes current SP switch

Create hooks for vendor async data

No lazy load for routes (#97)

better speech hook

match dev mock paged response to api server paged response

Generic AccountSelect component

Generic useRedirect hook

Recent call page for refresh (#93)

* initial commit

* changes requested but yet to pcap

* pcap?

* Initial cleanup on RecentCalls

* Normalize set page number and fix status for mock dev server

* Listt item styles and details/pcap fix

* Refactor recent calls subcomponents

* Tighter section padding and smaller page titles

* Update _lists.scss

* Recent calls cleanup and some other tweaks

Co-authored-by: kitajchuk <bk@kitajchuk.com>

Implement proper Checkzone initial checked for carrier form

Add handleSelect prop to SelectFilter component and fix perPageFilter changes for recent calls

Alert view page for refresh  (#99)

* initial commit

* changes suggested

* changes requested

* Style alerts UI

Co-authored-by: kitajchuk <bk@kitajchuk.com>

Refresh enhancement pagination logic (#101)

* initial commit

* Sort of secret props...

Co-authored-by: kitajchuk <bk@kitajchuk.com>

Quick small screen mobile sweep -- add logout button to mobile navi

Update index.tsx

Tweak some styles and restyle navi SP selector

Add key prop to ApiKeys on Settings so SP switch refetches data

fix checkbox margin now that grid-gap is used

Style tweaks

Update types.ts

Update delete.tsx

Update delete.tsx

Move some variable declarations around

Generic application select for forms

Fix issue #105 for carrier form applications

Use memo for filtered carriers on list view

Refactor generic application filter component

Update application-filter.tsx

Update types.ts

Update index.tsx

Update index.tsx

Update index.tsx

Update index.tsx

Cleanup some stuff -- add locked prop for Passwd

Fix unauthorized logout scenarios -- no react state errors :)

Normalize React types usage

Fuzzy search filter for collection lists (#106)

* Fuzzy search filter for collection lists

* Tweak some things for responsiveness

* Carrier preset label and fix All accounts filter for carriers list

Set text overflow on search filter

PR checklist items

Match 'No ...' text for speech services

Return rawCollection if hasLength check is false

Responsive styling for list item--action rows

Fix defaultOption for AccountSelector

Refresh: Add API limits for issue #109 (#111)

* Add API limits for issue #109

* Tighten up initial field renders

Cleanup for issue #104 (#108)

Co-authored-by: kitajchuk <bk@kitajchuk.com>

Tweak local limits

Generic local limits component

No default local limits -- move to forms components

Safe set values for limits -- maintain controlled inputs

Ref support for local limits form component

Handle empty data for local limits effect

Implement DELETE for limits

Singular nomenclature for post limit(s)
This commit is contained in:
Brandon Lee Kitajchuk
2022-09-22 08:38:21 -07:00
committed by GitHub
parent 1276687cc0
commit f381eba694
273 changed files with 23033 additions and 42576 deletions

194
docs/contributors.md Normal file
View File

@@ -0,0 +1,194 @@
<p align="center">
<a href="https://jambonz.org">
<img src="../public/icon192.png" height="128">
<h1 align="center">jambonz</h1>
</a>
</p>
<p align="center">
<a aria-label="GitHub CI" href="https://github.com/jambonz/jambonz-webapp/actions/workflows/main.yml">
<img alt="" src="https://github.com/jambonz/jambonz-webapp/actions/workflows/main.yml/badge.svg">
</a>
</p>
> Contributing to the web app source code
## :rocket: Getting started
In order to run the web app you'll need your local environment setup which you can do
following instructions in our [environment readme](./environment.md).
Once your environment is setup you can fork or clone this repo. To start the web app
just run `npm install` and then `npm start`.
## :pancakes: Dev stack
We're using [vite](https://vitejs.dev/) for development and
the main application is [react](https://reactjs.org/docs/getting-started.html)
with [typescript](https://www.typescriptlang.org/),
[prettier](https://prettier.io/), [eslint](https://eslint.org/),
[husky](https://typicode.github.io/husky/#/)
and [lint-staged](https://www.npmjs.com/package/lint-staged).
## :lock: Auth middleware
We have auth middleware that was initially based on this [useAuth](https://usehooks.com/useAuth/)
example but has been typed and modified to include a `RequireAuth` component for wrapping internal Routes.
The main hook you'll use here is `useAuth`. This hook provides the `AuthStateContext` which has the
following:
- `token`
- `signin(user, pass)`
- `signout()`
- `authorized`
### A note on our ACL implementation
We have some simple ACL utilities for managing access to UI/routes based on conditions.
There is a basic `AccessControl` component and a handy `withAccessControl`
HOC for route containers with redirect. There is also a `useAccessControl` hook for
use at the component-level.
## :joystick: Application state
`ui = fn(state)`
The state for the application has two parts: the local state and the remote server state.
The server state is the source of truth. We keep only the minimal amount of local state
necessary: the current logged in user, the list of service providers and the actively selected
current service provider. We also use local state for a basic permissions matrix and for the
global toast notifications. That's it! Local state is easy.
Because of this limited scope for local state we're **not using a third-party state manager**.
We have a custom store implementation using vanilla React `useReducer` and context to provide
the state to our application. There are many useful functions and hooks for working with state
which include the following:
- `useStateContext()`: returns the entire state object
- `useSelectState(key)`: returns just the piece of state desired
- `useDispatch()`: returns global dispatch method
- `useAccessControl(acl)`: returns true/false for select ACL permissions
- `useFeatureFlag(flag)`: returns true/false for available feature flags
- `withSelectState([...keys])(Component)`: like redux connect it maps state to props
- `toastError(msg)`: helper for dispatching error toasts
- `toastSuccess(msg)`: helper for dispatching success toasts
## :wales: API implementation
We have a centralized API implementation that uses our normalized `fetchTransport` method
under the hood. We have `use` hooks for general `GET` fetching that return the `data` fetched,
a `refetcher` function that, when called, will update the data in the hook and therefore your
component will render the new data, and a possible `error` if the fetch failed. The general
consensus on when to use the hooks vs using a `getFetch` directly are dictated by whether the
API response data needs to be refetched locally based on some user action, such as deleting
an item from a list. In that case use the hooks, otherwise a `getFetch` pattern should work.
The hooks are:
- `useApiData(path)`: returns `[data, refetcher, error]`
- `useServiceProviderData(path)`: returns `[data, refetcher, error]`
All API requests are piped through the `fetchTransport` method which receives a generic type
and returns it as the type of response data resolved. Any `POST`, `PUT` or `DELETE` calls should
have a wrapper method that calls our more generic methods under the hood, which are:
- `getFetch(url)`
- `postFetch(url, payload)`
- `putFetch(url, payload)`
- `deleteFetch(url)`
- `getBlob(url)`
Example of wrapper API methods to `:POST` and `:PUT` for the `Account` type:
```ts
export const postAccount = (payload: Partial<Account>) => {
return postFetch<SidResponse, Partial<Account>>(API_ACCOUNTS, payload);
};
export const putAccount = (sid: string, payload: Partial<Account>) => {
return putFetch<EmptyResponse, Partial<Account>>(
`${API_ACCOUNTS}/${sid}`,
payload
);
};
```
### Local dev mock API server
There are two views that rely on call detail records (CDRs) that don't exist in the local
developer db when running the docker stack. For these views we have a local node express
server that replicates functional parity of the backend APIs in question so you can work
on the UI. The views are `Recent Calls` and `Alerts`. They are simple table views with
filter and pagination functionalities. You can view the implementation at `server/dev.server.ts`.
The approach is to replicate the pattern of how test data is seeded for the API server and
add the filtering on top of it with simple JavaScript functions. To run the dev server:
```shell
npm run dev:server
```
## :file_folder: Vendor data modules
Large data modules are used for menu options on the Applications and Speech Services
forms. These modules are loaded lazily and set to local state in the context in which
they are used. You can find the data modules and their type definitions in the `src/vendor`
directory.
## :sunrise: Component composition
All components that are used as Route elements are considered `containers`.
Containers are organized by `login` and `internal`, the latter of which requires
the user to be authorized via our auth middleware layer. Reusable components are
small with specific pieces of functionality and their own local state. We have
plenty of examples including `toast`, `modal` and so forth. You should review some
of each category of component to get an idea of how the patterns are put into practice.
## :art: UI and styling
We have a UI design system called [jambonz-ui](https://github.com/jambonz/jambonz-ui).
It's public on `npm` and is being used for this project. It's still small and simple
but provides the foundational package content for building jambonz UIs. You can view
the storybook for it [here](https://jambonz-ui.vercel.app/) as well as view the docs
for it [here](https://www.jambonz.org/docs/jambonz-ui/).
### A note on styles
While we use [sass](https://sass-lang.com/) with `scss` syntax it should be stated that the
primary objective is to simply write generally pure `css`. We take advantage of a few nice
features of `sass` like nesting for [BEM](http://getbem.com/naming/) module style etc. We
also take advantage of loading the source `sass` from the UI library. Here's an example of
the `BEM` style we use:
```scss
.example {
// This is the block
&--modifier {
// This is a modifier of the block
}
&__item {
// This is an element
&--modifer {
// This a modifer of the element
}
}
}
```
## :heart: Contributing
If you would like to contribute to this project please follow these simple guidelines:
- Be excellent to each other!
- Follow the best practices and coding standards outlined here.
- Clone or fork this repo, write code and open a PR :+1:
- All code must pass the `pr-checks` and be reviewed by a code owner.
That's it!
## :beetle: Bugs?
If you find a bug please file an issue on this repository with as much information as
possible regarding replication etc :pray:.

95
docs/environment.md Normal file
View File

@@ -0,0 +1,95 @@
<p align="center">
<a href="https://jambonz.org">
<img src="../public/icon192.png" height="128">
<h1 align="center">jambonz</h1>
</a>
</p>
<p align="center">
<a aria-label="GitHub CI" href="https://github.com/jambonz/jambonz-webapp/actions/workflows/main.yml">
<img alt="" src="https://github.com/jambonz/jambonz-webapp/actions/workflows/main.yml/badge.svg">
</a>
</p>
> Setting up a local test environment
This document describes how to set up a local development and test environment on your laptop.
Testing the jambonz-webapp requires a back-end system to run against, and we use docker-compose
to run these back-end components, allowing you to develop and test the web app UI locally.
## Prerequisites
- You will need to have docker and docker-compose installed on your laptop.
- You need to have cloned the [jambonz-api-server](https://github.com/jambonz/jambonz-api-server) repo to a folder on your laptop.
## Running the back-end services
Make sure the docker daemon is running on your laptop. Open a terminal window and cd into the
project folder for jambonz-api-server, then run the following command to start the back-end processes.
```bash
cd jambonz-api-server
npm run integration-test
```
This will take a few minutes to start, but eventually a successfull startup will eventually
look something like this:
```bash
$ npm run integration-test
> jambonz-api-server@v0.7.5 integration-test
> NODE_ENV=test JAMBONES_TIME_SERIES_HOST=127.0.0.1 AWS_REGION='us-east-1' JAMBONES_CURRENCY=USD JWT_SECRET=foobarbazzle JAMBONES_MYSQL_HOST=127.0.0.1 JAMBONES_MYSQL_PORT=3360 JAMBONES_MYSQL_USER=jambones_test JAMBONES_MYSQL_PASSWORD=jambones_test JAMBONES_MYSQL_DATABASE=jambones_test JAMBONES_REDIS_HOST=localhost JAMBONES_REDIS_PORT=16379 JAMBONES_LOGLEVEL=debug JAMBONES_CREATE_CALL_URL=http://localhost/v1/createCall node test/serve-integration.js
starting dockerized mysql and redis..
mysql is running
creating database..
creating schema..
seeding database..
creating admin user..
reset_admin_password, initial admin password is admin
sipp exited with non-zero code 1 signal null
1
ready for testing!
{"level":30, "time": "2022-04-14T18:07:49.318Z","pid":5292,"hostname":"MacBook-Pro-2.local","msg":"listening for HTTP traffic on port 3000","v":1}
{"level":20, "time": "2022-04-14T18:07:49.325Z","pid":5292,"hostname":"MacBook-Pro-2.local","args":[],"msg":"redis event connect","v":1}
{"level":20, "time": "2022-04-14T18:07:49.345Z","pid":5292,"hostname":"MacBook-Pro-2.local","args":[],"msg":"redis event ready","v":1}
```
This starts the a docker-compose network running the following containers:
- mysql
- redis
- influxdb
- heplify-server
- drachtio
- homer-webapp
Leaving the jambonz-api-server process running, open another terminal window, cd into the
folder where you have checked out this project, and start it as shown below:
```
cd jambonz-webapp
npm i
npm start
```
This will start the web app UI on http://localhost:3001.
You should now see the login page to the jambonz webapp and can log in with username admin and
password admin. You will be forced to change the password, and then you should see the main page
of the application.
From here you can make and test changes locally.
## Testing with remote server
If you want to test against a remote server, you must specify the ip:port of
the Jambonz API you will be hitting.
1. Copy `.env` to `.env.local`
2. In `.env.local`, replace `[ip]:[port]` with the API's IP and port
3. `npm start`
4. Access the web app via http://localhost:3001