Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Customization of Info Panel #2

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
246 changes: 246 additions & 0 deletions active-rfcs/0000-info-panel-customization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
- Start Date: 2020-05-12
- Reference Issues: N/A
- Implementation PR: N/A

# Summary

Support per project customization of Info Panel.

# Motivation

Raw representation of feature's data may be not always enough. If there is a better way
to represent data, possibility to create a custom project-specific presentation of data
will make application more useful.

# Detailed design

Because web application is built as Vue.js single page application, best integration can
be achieved by using the same tech stack. Vue CLI already out of box supports
[library target build](https://cli.vuejs.org/guide/build-targets.html#library), which allows
to build single or even multiple Vue components as library module. Another useful option
is [css.extract](https://cli.vuejs.org/config/#css-extract) option, which determines whether
CSS styles will be generated in separate file, or included (inlined) in JavaScript code.
This will allow to build custom component(s) (including all dependency libraries)
as single JavaScript file.

With possibility to build custom components, there are basically two options how to use them:

1. Define component for the whole detail content. This option will allow maximal customization,
but may require more coding and reusability may be worse.

2. Define component for single field (attribute). This option can be preffered when default
(generic) view will be suitable for many fields, and only a few fields will require replacement.

But in order to use custom component(s) in the project, it's configuration must be extended
to support this feature, and server will have to provide API to upload and serve JavaScript
files with bundled components. And this depends on building/bundling process. Single component
built as separate JavaScript file is easiest to implement, because you doesn't need to know
module's content. But when you build multiple components into single JavaScript UMD module,
application will need to know mapping of module's properties to Vue components. Analyzing
JavaScript file on server after the upload could be difficult. More likely solution could
be manually written or automatically generated (maybe webpack plugin) metadata file, which
would be also uploaded to the server.

## Project configuration file

## Server API

Gisquick's web apps are built as static pages and served with NGINX. All JS, CSS or image files
are generated with filename hashing feature and with pre-generated compressed versions (gzip).
But because custom components should be attached to particular project, serving them with NGINX
may be not sufficient, especially if access should be restricted by project authentication settings.
Vue CLI also doesn't generates files with hashes for library target build, what would allow
to use max. caching headers for serving.

#### Upload

**Request**
<table>
<tbody>
<tr>
<td>URL</td>
<td><code>/api/project/static/{user}/{project}</code></td>
</tr>
<tr>
<td>Method</td>
<td><code>POST</code></td>
</tr>
<tr>
<td>Content-Type</td>
<td><code>multipart/form-data</code></td>
</tr>
</tbody>
</table>

#### Serve

**Request**
<table>
<tbody>
<tr>
<td>URL</td>
<td><code>/api/project/static/{user}/{project}/{file}</code></td>
</tr>
<tr>
<td>Method</td>
<td><code>GET</code></td>
</tr>
</tbody>
</table>

## Map web application

Based on project configuration metadata, application should load required JavaScript modules
and use right components in Info Panel.

## Settings web application

User interface for uploading and configuration.

# Drawbacks

This aproach requires:
- programming skills
- setup of development evnironment for Gisquick's map application
- knowledge of Vue.js and used UI library

Also custom components may need some maintenance to keep up to date with map application.

# Alternatives

N/A

# Unresolved questions

- Support for multiple components in single JavaScript (UMD) module. Using big library
in multiple components would be more effective
- Cache strategy - filenames hashing, http headers
- Compressed (gzip) versions of JavaScript files - allow to upload, or generate after upload
- Access rules for serving project's JavaScript files


# UPDATE

## Upload API proposal

<table>
<tbody>
<tr>
<td>URL</td>
<td><code>/api/project/script/{user}/{directory}</code></td>
</tr>
<tr>
<td>Method</td>
<td><code>POST</code></td>
</tr>
<tr>
<td>Content-Type</td>
<td><code>multipart/form-data</code></td>
</tr>
</tbody>
</table>

Example:
```
Content-Disposition: form-data; name="info"
Content-Type: application/json
{"path":"component.umd.min.js","components":["ComponentName"]}

Content-Disposition: form-data; name="script"; filename="component.umd.min.js"
Content-Type: text/javascript
<file content>
```

Format of `scripts.json`
```json
{
"module": {
"path": "component..umd.js",
"components": ["Widget1", "Widget2"]
},
"widget": {
"path": "infopanel/widget.[hash].umd.js",
"components": ["Widget"]
}
}
```


# Workflow

## Setup and run Gisquick web application locally

```
git clone https://github.com/gislab-npo/gisquick
cd gisquick/clients/gisquick-web
```
See README.md

## Create a new Vue component

Create a component, e.g. in `src/extensions/MyComponent.vue`:

```javascript
export default {
name: 'UniqeName', // mandatory, will be used to identify component
props: {
layer: Object, // layer's config
feature: Object // ol Feature
}
/* rest of the component*/
}
```

In order to use component before it's finished and bundled, you can assign component
during development process with following confguration. This will override project's
configuration in development mode.

`src/dev/components.js`

```javascript
import MyComponent from '@/extensions/MyComponent.vue'

export default {
infoPanelComponents: [
{
layer: 'layername',
component: MyComponent
}
]
}
```

## Build/bundle component(s)

https://markus.oberlehner.net/blog/distributed-vue-applications-loading-components-via-http/

Single component
```
CSS_EXTRACT=False npm run build -- --target lib --formats umd-min --dest dist/ --name mycomponent src/extensions/MyComponent.vue
```

Multiple components

`src/extensions/index.js`

```javascript
import Component1 from './Component1'
import Component2 from './Component2'

export default [
Component1,
Component2
]
```

```
CSS_EXTRACT=False npm run build -- --target lib --formats umd-min --dest dist/ --name components src/extensions/index.js
```

## Upload bundled components

1. Go to your profile page (https://projects.gisquick.org/user)
2. Open settings of published project
3. Go to layers settings
4. Upload <name>.umd.min.js file
5. Select component