-
Check if internal development server is running
-
Clone GIT repo ngcp-csc-ui
git clone ssh://hostname:port/ngcp-csc-ui
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.
yarn run dev:docker dev-web-trunk.mgm.sipwise.com
yarn run config dev-web-trunk.mgm.sipwise.com
yarn run dev
After a test phase with Sencha Ext JS we decided to use Vue.js in combination with the Quasar Framework.
We highly recommend the following courses to understand the principles and ultimately the code:
In addition, we also recommend the following Quasar Framework tutorials:
To keep translation files consistent and updated please run i18n:extract command before each commit to the GIT repo.
yarn run i18n:extract
That CLI command will collect all new translation keys from the JS source code, and will place those keys into all translation files in a proper format. Note that currently the command is set to use bash. If you prefer using sh change the package.json as below:
"i18n:extract": "sh ./bin/vue-i18n-extract/extract.sh",
"i18n:extract-report": "sh ./bin/vue-i18n-extract/extract.sh report"
Example of the JS code with translations:
const someOptions = {
label: this.$t('Remove message'),
message: this.$t('The {email} will be removed. Are you sure?', { email: this.email })
}
Important: We are trying to avoid usage of the dynamic keys (example below) because it's very difficult to detect and collect automatically.
Example (anti-pattern):
function getTranslatedMessage (weatherState) {
return this.$t('Tooday is ' + weatherState)
}
Try to avoid such code and use text messages with substitution variables (like email
in example above) or if there are only a couple similar messages, you can use a map object to convert some exact state to exact translation message.
But if it's really impossible to do, and you have to use dynamic keys, you should place such keys to the English translation file manually and execute i18n:extract
which will do all the rest.
For example, for the code above, you would need to place next lines into en.json
:
{
...
"Today is sunny": "",
"Today is windy": "",
"Today is cloudy": ""
}
Note: if you want to see information about missed or possible unused translation keys you could run i18n:extract-report command. It will just display detailed report without any modifications in the language files.
Keep in mind that some of "Unused translations" keys might be dynamic translation keys which cannot be detected in source code automatically and were added manually.
yarn run i18n:extract-report
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
{
path: '/user/new-feature',
component: CscPageNewFeature,
meta: {
title: i18n.t('New features'),
subtitle: i18n.t('New features sub-title')
}
}
-
Add new feature to the main menu
src/components/CscMainMenuTop.vue
{
to: '/user/new-feature',
icon: 'fancy_icon',
label: this.$t('New features'),
sublabel: this.$t('New features sub-title'),
visible: true
}
The basic dialog component is src/components/CscDialog.vue
.
Check the example implementation in src/components/CscDialogChangePassword.vue
.
To reduce the boilerplate code of dialog components, we call Dialogs via Quasar Dialog Plugin.
this.$q.dialog({
component: CscDialogChangePassword,
parent: this
}).onOk((password) => {
this.changeWebPassword(password)
})
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 for further details.
The standard authentication method to access the API from the browser is the JSON Web Token (JWT) which is specified in RFC7519
After the login request, the JWT is stored in the LocalStorage and is added automatically on each API request.
const list = await getList({
resource: 'subscribers'
})
list.items.forEach(subscriber => {
console.log(subscriber.webusername)
})
const list = await getList({
resource: 'subscribers',
page: 1,
rows: 25
})
console.log(list.lastPage)
const subscriber = await get({
resource: 'subscribers',
resourceId: 21
})
console.log(subscriber.webusername)
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.
const subscriber = await post({
resource: 'subscribers',
body: {
webusername: 'alice',
...
}
})
console.log(subscriber.webusername)
await postMinimal({
resource: 'subscribers',
body: {
webusername: 'alice',
...
}
})
This method helps to update an entire item at once.
const subscriber = await put({
resource: 'subscribers',
resourceId: 21,
body: {
webusername: 'bob',
...
}
})
console.log(subscriber.webusername)
await putMinimal({
resource: 'subscribers',
resourceId: 21,
body: {
webusername: 'bob',
...
}
})
This is the preferred method to update single fields on an item.
await patchReplace({
resource: 'subscribers',
resourceId: 21,
fieldPath: 'webusername',
value: 'carol'
})
const subscriber = await patchReplaceFull({
resource: 'subscribers',
resourceId: 21,
fieldPath: 'webusername',
value: 'dave'
})
console.log(subscriber.webusername)