You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
233 lines
5.2 KiB
233 lines
5.2 KiB
# Customer Self-Care Web UI
|
|
|
|
## Development Quick Start for internal developers
|
|
|
|
* Check if [internal development server](https://dev-web-trunk.mgm.sipwise.com/) is running
|
|
* Clone GIT repo ngcp-csc-ui
|
|
|
|
`git clone ssh://hostname:port/ngcp-csc-ui`
|
|
|
|
* [Install Docker](https://docs.docker.com/get-docker)
|
|
* [Install yarn](https://yarnpkg.com/getting-started/install)
|
|
|
|
### Run development environment in Docker
|
|
|
|
This is the preferred way to work with.
|
|
If you have any problems with Docker,
|
|
you can fallback to the method described
|
|
in the next chapter.
|
|
|
|
```shell script
|
|
yarn run dev:docker dev-web-trunk.mgm.sipwise.com
|
|
```
|
|
|
|
### Run development environment in your system of choice
|
|
|
|
```shell script
|
|
yarn run config dev-web-trunk.mgm.sipwise.com
|
|
yarn run dev
|
|
```
|
|
|
|
## Technology
|
|
|
|
### Vue.js and Quasar
|
|
|
|
After a test phase with Sencha Ext JS we decided to use
|
|
[Vue.js](https://vuejs.org) in combination with the [Quasar Framework](https://quasar.dev).
|
|
|
|
### Developers basics
|
|
|
|
We highly recommend the following courses to understand the
|
|
principles and ultimately the code:
|
|
|
|
* [Intro to Vue 2](https://www.vuemastery.com/courses/intro-to-vue-js/vue-instance)
|
|
* [Real World Vue 2](https://www.vuemastery.com/courses/real-world-vue-js/real-world-intro)
|
|
* [Mastering Vuex](https://www.vuemastery.com/courses/mastering-vuex/success-error-notifications)
|
|
|
|
In addition, we also recommend the following Quasar Framework tutorials:
|
|
|
|
* [Quasar Video Tutorials](https://quasar.dev/video-tutorials)
|
|
|
|
## Project Guide
|
|
|
|
* [Reusable Vue.js Components](doc/COMPONENTS.md)
|
|
|
|
### Add a new page
|
|
|
|
In order to add a new page you need to go along the following steps:
|
|
|
|
* Create a new page component using the following naming pattern
|
|
|
|
`src/pages/CscPageNewFeature.vue`
|
|
|
|
* Create a route and add it to the route file
|
|
|
|
`src/router/routes.js`
|
|
|
|
```javascript
|
|
{
|
|
path: '/user/new-feature',
|
|
component: CscPageNewFeature,
|
|
meta: {
|
|
title: i18n.t('pages.newFeature.title'),
|
|
subtitle: i18n.t('navigation.newFeature.subTitle')
|
|
}
|
|
}
|
|
```
|
|
|
|
* Add new feature to the main menu
|
|
|
|
`src/components/CscMainMenuTop.vue`
|
|
|
|
```javascript
|
|
{
|
|
to: '/user/new-feature',
|
|
icon: 'fancy_icon',
|
|
label: this.$t('navigation.newFeature.title'),
|
|
sublabel: this.$t('navigation.newFeature.subTitle'),
|
|
visible: true
|
|
}
|
|
```
|
|
|
|
### Dialogs
|
|
|
|

|
|
|
|
The basic dialog component is `src/components/CscDialog.vue`.
|
|
|
|
#### How to create a new custom dialog
|
|
|
|
Check the example implementation in `src/components/CscDialogChangePassword.vue`.
|
|
|
|
#### How to call custom dialogs from within a Vue.js Component method
|
|
|
|
To reduce the boilerplate code of dialog components, we call Dialogs
|
|
via [Quasar Dialog Plugin](https://quasar.dev/quasar-plugins/dialog).
|
|
|
|
```javascript
|
|
this.$q.dialog({
|
|
component: CscDialogChangePassword,
|
|
parent: this
|
|
}).onOk((password) => {
|
|
this.changeWebPassword(password)
|
|
})
|
|
```
|
|
|
|
### NGCP API
|
|
|
|
All API functions are located in `src/api`. The file `src/api/common.js`
|
|
exports basic convenient functions to perform API requests.
|
|
|
|
Check [API Documentation](https://dev-web-trunk.mgm.sipwise.com:1443/api) for further details.
|
|
|
|
### Authentication
|
|
|
|
The standard authentication method to access the API from the browser is the [JSON Web Token (JWT)](https://jwt.io) which is specified in [RFC7519](https://tools.ietf.org/html/rfc7519)
|
|
|
|
After the login request, the JWT is stored in the LocalStorage and is added automatically on each API request.
|
|
|
|
#### Fetch a list of items
|
|
|
|
```javascript
|
|
const list = await getList({
|
|
resource: 'subscribers'
|
|
})
|
|
list.items.forEach(subscriber => {
|
|
console.log(subscriber.webusername)
|
|
})
|
|
```
|
|
|
|
#### Fetch a paginated list of items
|
|
|
|
```javascript
|
|
const list = await getList({
|
|
resource: 'subscribers',
|
|
page: 1,
|
|
rows: 25
|
|
})
|
|
console.log(list.lastPage)
|
|
```
|
|
|
|
#### Fetch a single item
|
|
```javascript
|
|
const subscriber = await get({
|
|
resource: 'subscribers',
|
|
resourceId: 21
|
|
})
|
|
console.log(subscriber.webusername)
|
|
```
|
|
|
|
#### Create a new item
|
|
|
|
If you use `post`, you create the
|
|
item and get back the sanitised data.
|
|
The method `postMinimal` does exactly
|
|
the same, except that the body is empty.
|
|
|
|
```javascript
|
|
const subscriber = await post({
|
|
resource: 'subscribers',
|
|
body: {
|
|
webusername: 'alice',
|
|
...
|
|
}
|
|
})
|
|
console.log(subscriber.webusername)
|
|
```
|
|
```javascript
|
|
await postMinimal({
|
|
resource: 'subscribers',
|
|
body: {
|
|
webusername: 'alice',
|
|
...
|
|
}
|
|
})
|
|
```
|
|
|
|
#### Update an existing item
|
|
|
|
This method helps to update an entire item at once.
|
|
|
|
```javascript
|
|
const subscriber = await put({
|
|
resource: 'subscribers',
|
|
resourceId: 21,
|
|
body: {
|
|
webusername: 'bob',
|
|
...
|
|
}
|
|
})
|
|
console.log(subscriber.webusername)
|
|
```
|
|
```javascript
|
|
await putMinimal({
|
|
resource: 'subscribers',
|
|
resourceId: 21,
|
|
body: {
|
|
webusername: 'bob',
|
|
...
|
|
}
|
|
})
|
|
```
|
|
|
|
#### Update a specific field on an existing item
|
|
|
|
This is the preferred method to update single fields on an item.
|
|
|
|
```javascript
|
|
await patchReplace({
|
|
resource: 'subscribers',
|
|
resourceId: 21,
|
|
fieldPath: 'webusername',
|
|
value: 'carol'
|
|
})
|
|
```
|
|
```javascript
|
|
const subscriber = await patchReplaceFull({
|
|
resource: 'subscribers',
|
|
resourceId: 21,
|
|
fieldPath: 'webusername',
|
|
value: 'dave'
|
|
})
|
|
console.log(subscriber.webusername)
|