Skip to content

Commit e8af88d

Browse files
richipargopaveltiunov
authored andcommitted
feat: Lean more on vue slots for state (#148)
* Add support for empty/error/valid states on QueryBuilder * query testing * adjustements on member changing and updating * query builder timedimesions * Query builder member changes * changes to queryBuilder * implement slots on query builder as well * remove overloaded props from renderer * change slot for empty but loaded meta * fix duplicate dependency issue and granularity to members * update docs * mantain full backwards compatibility * use only default slot if no other slot is present and add extra props * remove classes
1 parent 287411b commit e8af88d

13 files changed

Lines changed: 3802 additions & 187 deletions

File tree

docs/Cube.js-Frontend/@cubejs-client-vue.md

Lines changed: 114 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,79 @@ into Vue.js app.
1818
- `query`: analytic query. [Learn more about it's format](query-format).
1919
- `cubejsApi`: `CubejsApi` instance to use.
2020

21-
### Scoped Slot Props
21+
### Slots
2222

23-
- `resultSet`: A `resultSet` is an object containing data obtained from the query. If this object is not defined, it means that the data is still being fetched. [ResultSet](@cubejs-client-core#result-set) object provides a convient interface for data munipulation.
24-
- `error`: Error will be defined if an error has occurred while fetching the query.
25-
- `loadingState`: Provides information about the state of the query loading.
23+
#### Default Slot
24+
25+
##### Slot Props
26+
27+
- `resultSet`: A `resultSet` is an object containing data obtained from the query. [ResultSet](@cubejs-client-core#result-set) object provides a convient interface for data munipulation.
28+
29+
#### Empty Slot
30+
31+
This slot functions as a empty/loading state in which if the query is loading or empty you can show
32+
something in the meantime
33+
34+
#### Error Slot
35+
36+
##### Slot Props
37+
38+
- `error`: will show the details from error.
39+
- `sqlQuery`: will show tried query
40+
41+
### Example
42+
```js
43+
<template>
44+
<div class="hello">
45+
<query-renderer :cubejs-api="cubejs" :query="query" v-if="cubejs">
46+
<template v-slot="{ resultSet }">
47+
<component :is="type" :result="resultSet"/>
48+
</template>
49+
50+
<template v-slot:empty>
51+
<div class="loading-container">
52+
<loading-ring class="loading"/>
53+
</div>
54+
</template>
55+
</query-renderer>
56+
</div>
57+
</template>
58+
59+
<script>
60+
import cubejs from '@cubejs-client/core';
61+
import { QueryRenderer } from '@cubejs-client/vue';
62+
import ChartRenderer from "./ChartRenderer.vue";
63+
64+
const cubejsApi = cubejs(
65+
'YOUR-CUBEJS-API-TOKEN',
66+
{ apiUrl: 'http://localhost:4000/cubejs-api/v1' },
67+
);
68+
69+
export default {
70+
name: "HelloWorld",
71+
components: {
72+
QueryRenderer,
73+
ChartRenderer
74+
},
75+
data() {
76+
const query = {
77+
measures: ["LineItems.count", "LineItems.quantity", "Orders.count"],
78+
timeDimensions: [
79+
{
80+
dimension: "LineItems.createdAt",
81+
granularity: "month"
82+
}
83+
]
84+
};
85+
86+
return {
87+
cubejsApi,
88+
query
89+
};
90+
}
91+
};
92+
</script>
93+
```
2694

2795
## QueryBuilder
2896
`<QueryBuilder />` is used to build interactive analytics query builders. It abstracts state management and API calls to Cube.js Backend. It uses scoped slot props technique.
@@ -33,7 +101,27 @@ into Vue.js app.
33101
- `cubejsApi`: `CubejsApi` instance to use. Required.
34102
- `defaultChartType`: default value of chart type. Default: 'line'.
35103

36-
### Scoped Slot Props
104+
### Slots
105+
106+
#### Default Slot
107+
108+
##### Slot Props
109+
110+
- `resultSet`: A `resultSet` is an object containing data obtained from the query. [ResultSet](@cubejs-client-core#result-set) object provides a convient interface for data munipulation.
111+
112+
#### Empty Slot
113+
114+
This slot functions as a empty/loading state in which if the query is loading or empty you can show
115+
something in the meantime
116+
117+
#### Error Slot
118+
119+
##### Slot Props
120+
121+
- `error`: will show the details from error.
122+
- `sqlQuery`: will show tried query
123+
124+
#### Builder Slot
37125

38126
- `measures`, `dimensions`, `segments`, `timeDimensions`, `filters` - arrays of
39127
selected query builder members.
@@ -49,15 +137,35 @@ API from Cube.js Backend.
49137
- `isQueryPresent` - Bool indicating whether is query ready to be displayed or
50138
not.
51139
- `query` - current query, based on selected members.
52-
- `resultSet`, `error`, `loadingState` - same as `<QueryRenderer />` [Scoped slot params.](#query-scoped-slot-props)
53140

54141
### Example
55142
[Open in CodeSandbox](https://codesandbox.io/s/3rlxjkv2p)
56143
```js
57144
<template>
58145
<div class="hello">
59146
<query-builder :cubejs-api="cubejsApi" :query="query">
147+
<template v-slot:builder="scope">
148+
<div class="report-details-parameters">
149+
<dropdown
150+
placeholder="Chart"
151+
:options="dropdown"/>
152+
<dropdown
153+
:options="scope.availableMeasures"
154+
placeholder="Measure"/>
155+
<dropdown
156+
:options="scope.availableDimensions"
157+
placeholder="Dimensions"/>
158+
</div>
159+
</template>
160+
60161
<template v-slot="{ resultSet }">
162+
<component :is="type" :result="resultSet" class="chart"/>
163+
</template>
164+
165+
<template v-slot:empty>
166+
<div class="loading-container">
167+
<loading-ring class="loading"/>
168+
</div>
61169
</template>
62170
</query-builder>
63171
</div>
@@ -80,19 +188,8 @@ export default {
80188
ChartRenderer
81189
},
82190
data() {
83-
const query = {
84-
measures: ["LineItems.count", "LineItems.quantity", "Orders.count"],
85-
timeDimensions: [
86-
{
87-
dimension: "LineItems.createdAt",
88-
granularity: "month"
89-
}
90-
]
91-
};
92-
93191
return {
94192
cubejsApi,
95-
query
96193
};
97194
}
98195
};

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
"author": "Statsbot, Inc.",
1212
"dependencies": {
1313
"@babel/runtime-corejs2": "^7.0.0",
14-
"@cubejs-client/core": "^0.1.4",
1514
"core-js": "^2.5.3",
1615
"ramda": "^0.25.0",
1716
"whatwg-fetch": "^3.0.0"
@@ -26,8 +25,10 @@
2625
"@babel/preset-env": "^7.0.0",
2726
"@babel/preset-react": "^7.0.0",
2827
"@babel/runtime": "^7.0.0",
28+
"@cubejs-client/core": "^0.10.0",
2929
"babel-runtime": "^6.26.0",
3030
"babelrc-rollup": "^3.0.0",
31+
"flush-promises": "^1.0.2",
3132
"http-server": "^0.11.1",
3233
"lerna": "^3.13.1",
3334
"rollup": "^0.68",

packages/cubejs-vue/jest.config.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
module.exports = {
2+
moduleFileExtensions: [
3+
'js',
4+
'jsx',
5+
'json',
6+
'vue'
7+
],
8+
transform: {
9+
'^.+\\.vue$': 'vue-jest',
10+
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
11+
'^.+\\.jsx?$': 'babel-jest'
12+
},
13+
transformIgnorePatterns: [
14+
'/node_modules/'
15+
],
16+
moduleNameMapper: {
17+
'^@/(.*)$': '<rootDir>/src/$1'
18+
},
19+
snapshotSerializers: [
20+
'jest-serializer-vue'
21+
],
22+
testMatch: [
23+
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
24+
],
25+
testURL: 'http://localhost/',
26+
watchPlugins: [
27+
'jest-watch-typeahead/filename',
28+
'jest-watch-typeahead/testname'
29+
]
30+
}

packages/cubejs-vue/package.json

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,36 @@
33
"version": "0.10.0",
44
"description": "Vue.js components for cube.js",
55
"author": "Ricardo Tapia",
6-
"license": "MIT",
76
"scripts": {
87
"serve": "vue-cli-service serve",
98
"build": "vue-cli-service build",
10-
"lint": "vue-cli-service lint"
9+
"lint": "vue-cli-service lint",
10+
"test:unit": "vue-cli-service test:unit",
11+
"test:unit:watch": "vue-cli-service test:unit --watch --require tests/setup.js"
1112
},
13+
"main": "dist/cubejs-vue.js",
14+
"module": "dist/cubejs-vue.esm.js",
15+
"files": [
16+
"dist",
17+
"src"
18+
],
1219
"dependencies": {
1320
"core-js": "^2.6.5",
14-
"ramda": "^0.26.1",
15-
"vue": "^2.6.6"
21+
"ramda": "^0.26.1"
1622
},
1723
"devDependencies": {
1824
"@vue/cli-plugin-babel": "^3.5.0",
1925
"@vue/cli-plugin-eslint": "^3.5.0",
26+
"@vue/cli-plugin-unit-jest": "^3.8.0",
2027
"@vue/cli-service": "^3.5.0",
28+
"@vue/test-utils": "1.0.0-beta.29",
29+
"babel-core": "7.0.0-bridge.0",
2130
"babel-eslint": "^10.0.1",
31+
"babel-jest": "^23.6.0",
2232
"eslint": "^5.8.0",
2333
"eslint-plugin-vue": "^5.0.0",
24-
"vue-template-compiler": "^2.5.21"
34+
"vue-template-compiler": "^2.5.21",
35+
"vue": "^2.6.6"
2536
},
2637
"eslintConfig": {
2738
"root": true,
@@ -42,17 +53,12 @@
4253
"autoprefixer": {}
4354
}
4455
},
45-
"main": "dist/cubejs-vue.js",
46-
"module": "dist/cubejs-vue.esm.js",
47-
"files": [
48-
"dist",
49-
"src"
50-
],
5156
"browserslist": [
5257
"> 1%",
5358
"last 2 versions",
5459
"not ie <= 8"
5560
],
61+
"license": "MIT",
5662
"publishConfig": {
5763
"access": "public"
5864
}

0 commit comments

Comments
 (0)