| # UI Development |
| |
| The modern CloudStack UI is role-based progressive app that uses Vue.js and Ant Design. |
| |
| JavaScript, Vue.js references: |
| - https://www.w3schools.com/js/ |
| - https://www.geeksforgeeks.org/javascript-tutorial/ |
| - https://vuejs.org/v2/guide/ |
| - https://www.youtube.com/watch?v=Wy9q22isx3U |
| |
| All the source is in the `src` directory with its entry point at `main.js`. |
| The following tree shows the basic UI codebase filesystem: |
| |
| ```bash |
| src |
| ├── assests # sprites, icons, images |
| ├── components # Shared vue files used to render various generic / widely used components |
| ├── config # Contains the layout details of the various routes / sections available in the UI |
| ├── locales # Custom translation keys for the various supported languages |
| ├── store # A key-value storage for all the application level state information such as user info, etc |
| ├── utils # Collection of custom libraries |
| ├── views # Custom vue files used to render specific components |
| ├── ... |
| └── main.js # Main entry-point |
| ``` |
| |
| ## Development |
| |
| Clone the repository: |
| |
| ``` |
| git clone https://github.com/apache/cloudstack.git |
| cd cloudstack/ui |
| npm install |
| ``` |
| Override the default `CS_URL` to a running CloudStack management server: |
| ``` |
| cp .env.local.example .env.local |
| ``` |
| Change the `CS_URL` in the `.env.local` file |
| To configure https, you may use `.env.local.https.example`. |
| Build and run: |
| ``` |
| npm run serve |
| ``` |
| |
| ## Implementation |
| |
| ## Defining a new Section |
| |
| ### Section Config Definition |
| |
| A new section may be added in `src/config/section` and in `src/config/router.js`, |
| import the new section's (newconfig.js as example) configuration file and rules to |
| `asyncRouterMap` as: |
| |
| import newconfig from '@/config/section/newconfig' |
| |
| [ ... snipped ... ] |
| |
| generateRouterMap(newSection), |
| |
| ### Section |
| |
| An existing or new section's config/js file must export the following parameters: |
| |
| - `name`: Unique path in URL |
| - `title`: The name to be displayed in navigation and breadcrumb |
| - `icon`: The icon to be displayed, from AntD's icon set |
| https://vue.ant.design/components/icon/ |
| - `docHelp`: Allows to provide a link to a document to provide details on the |
| section |
| - `searchFilters`: List of parameters by which the resources can be filtered |
| via the list API |
| - `children`: (optional) Array of resources sub-navigation under the parent |
| group |
| - `permission`: When children are not defined, the array of APIs to check against |
| allowed auto-discovered APIs |
| - `columns`: When children is not defined, list of column keys |
| - `component`: When children is not defined, the custom component for rendering |
| the route view |
| |
| See `src/config/section/compute.js` and `src/config/section/project.js` for example. |
| |
| The children should have: |
| |
| - `name`: Unique path in the URL |
| - `title`: The name to be displayed in navigation and breadcrumb |
| - `icon`: The icon to be displayed, from AntD's icon set |
| https://vue.ant.design/components/icon/ |
| - `permission`: The array of APIs to check against auto-discovered APIs |
| - `columns`: List of column keys for list view rendering |
| - `details`: List of keys for detail list rendering for a resource |
| - `tabs`: Array of custom components that will get rendered as tabs in the |
| resource view |
| - `component`: The custom component for rendering the route view |
| - `related`: A list of associated entity types that can be listed via passing |
| the current resource's id as a parameter in their respective list APIs |
| - `actions`: Array of actions that can be performed on the resource |
| |
| ## Custom Actions |
| |
| The actions defined for children show up as group of buttons on the default |
| autogen view (that shows tables, actions etc.). Each action item should define: |
| |
| - `api`: The CloudStack API for the action. The action button will be hidden if |
| the user does not have permission to execute the API |
| - `icon`: The icon to be displayed, from AntD's icon set |
| https://vue.ant.design/components/icon/ |
| - `label`: The action button name label and modal header |
| - `message`: The action button confirmation message |
| - `docHelp`: Allows to provide a link to a document to provide details on the |
| action |
| - `listView`: (boolean) Whether to show the action button in list view (table). |
| Defaults to false |
| - `dataView`: (boolean) Whether to show the action button in resource/data view. |
| Defaults to false |
| - `args`: List of API arguments to render/show on auto-generated action form. |
| Can be a function which returns a list of arguments |
| - `show`: Function that takes in a records and returns a boolean to control if |
| the action button needs to be shown or hidden. Defaults to true |
| - `groupShow`: Same as show but for group actions. Defaults to true |
| - `popup`: (boolean) When true, displays any custom component in a popup modal |
| than in its separate route view. Defaults to false |
| - `groupAction`: Whether the button supports groupable actions when multiple |
| items are selected in the table. Defaults to false |
| - `mapping`: The relation of an arg to an api and the associated parameters to |
| be passed and filtered on the result (from which its id is used as a |
| select-option) or a given hardcoded list of select-options |
| - `groupMap`: Function that maps the args and returns the list of parameters to |
| be passed to the api |
| - `component`: The custom component to render the action (in a separate route |
| view under src/views/<component>). Uses an autogenerated form by default. |
| Examples of such views can be seen in the src/views/ directory |
| |
| For Example: |
| ``` |
| { |
| api: 'startVirtualMachine', |
| icon: 'caret-right', |
| label: 'label.action.start.instance', |
| message: 'message.action.start.instance', |
| docHelp: 'adminguide/virtual_machines.html#stopping-and-starting-vms', |
| dataView: true, |
| groupAction: true, |
| groupMap: (selection) => { return selection.map(x => { return { id: x } }) }, |
| show: (record) => { return ['Stopped'].includes(record.state) }, |
| args: (record, store) => { |
| var fields = [] |
| if (store.userInfo.roletype === 'Admin') { |
| fields = ['podid', 'clusterid', 'hostid'] |
| } |
| if (record.hypervisor === 'VMware') { |
| if (store.apis.startVirtualMachine.params.filter(x => x.name === 'bootintosetup').length > 0) { |
| fields.push('bootintosetup') |
| } |
| } |
| return fields |
| }, |
| response: (result) => { return result.virtualmachine && result.virtualmachine.password ? `Password of the VM is ${result.virtualmachine.password}` : null } |
| } |
| ``` |
| |
| ## Resource List View |
| |
| After having, defined a section and the actions that can be performed in the |
| particular section; on navigating to the section, we can have a list of |
| resources available, for example, on navigating to **Compute > Instances** |
| section, we see a list of all the VM instances (each instance referred to as a |
| resource). |
| |
| The columns that should be made available while displaying the list of |
| resources can be defined in the section's configuration file under the |
| columns attribute (as mentioned above). **columns** maybe defined as an array |
| or a function in case we need to selectively (i.e., based on certain |
| conditions) restrict the view of certain columns. |
| |
| It also contains router-links to the resource and other related data such as the |
| account, domain, etc of the resource if present |
| |
| For example: |
| |
| ``` |
| ... |
| // columns defined as an array |
| columns: ['name', 'state', 'displaytext', 'account', 'domain'], |
| |
| // columns can also be defined as a function, so as to conditionally restrict view of certain columns |
| columns: () => { |
| var fields = ['name', 'hypervisor', 'ostypename'] |
| if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) { |
| fields.push('account') |
| } |
| ... |
| } |
| ``` |
| |
| ## Resource Detail View Customization |
| |
| From the List View of the resources, on can navigate to the individual |
| resource's detail view, which in CloudStack UI we refer to as the |
| *Resource View* by click on the specific resource. |
| The Resource View has 2 sections: |
| - InfoCard to the left that has basic / minimal details of that resource along |
| with the related entities |
| - DetailsTab to the right which provide the basic details about the resource. |
| |
| Custom tabs to render custom details, additional information of the resource |
| The list of fields to be displayed maybe defined as an array |
| or a function in case we need to selectively (i.e., based on certain |
| conditions) restrict the view of certain columns. The names specified in the |
| details array should correspond to the api parameters |
| |
| For example, |
| |
| ``` |
| ... |
| details: ['name', 'id', 'displaytext', 'projectaccountname', 'account', 'domain'], |
| ... |
| // To render the above mentioned details in the right section of the Resource View, we must import the DetailsTab |
| tabs: [ |
| { |
| name: 'details', |
| component: () => import('@/components/view/DetailsTab.vue') |
| }, |
| ... |
| ] |
| ``` |
| |
| Additional tabs can be defined by adding on to the tabs section. |