Skip to content

Commit

Permalink
Feature/frontend/queryeditor fix editor form (#36)
Browse files Browse the repository at this point in the history
* Update QueryEditor.tsx

add Timezone label

* Update QueryEditor.tsx

add Timezone label

* Add metadata type

* Fix bug backend get metadata

* Formatting & add default load option at Metrics & Diemsions

* Add Description at Metrics & Dimensions

* Remove tooltips new line

* Change timezone label

* Remove unused function

* Update 0.1.1, Update CHANGELOG.md

* .

Co-authored-by: IM CHAECHEOL <[email protected]>
  • Loading branch information
pjainxido and lcc3108 authored Mar 21, 2021
1 parent e46d6f6 commit 73cb661
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 139 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## 0.1.1
- enhancement query editor ui
- add timezone label at query editor
- get metric bug fix
- add Metrics & Dimensions description
- add Metadata type for typescript
- remove unused function


## 0.1.0

Initial release. Not fit for production use.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "blackcowmoo-googleanalytics-datasource",
"version": "0.1.0",
"version": "0.1.1",
"description": " Google-Analytics to Grafana",
"scripts": {
"build": "rm -rf node_modules/@grafana/data/node_modules; grafana-toolkit plugin:build",
Expand Down
9 changes: 5 additions & 4 deletions pkg/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ type MetadataItemAttribute struct {
Description string `json:"description,omitempty"`
AllowedInSegments string `json:"allowedInSegments,omitempty"`
AddedInAPIVersion string `json:"addedInApiVersion,omitempty"`
ReplacedBy string `json:"replacedBy,omitempty"`
}

type AttributeType string
Expand Down Expand Up @@ -160,7 +161,7 @@ func (ga *GoogleAnalytics) getFilteredMetadata() ([]MetadataItem, []MetadataItem
var dimensionItems = make([]MetadataItem, 0)
var metricItems = make([]MetadataItem, 0)
for _, item := range metadata.Items {
if item.Attributes.Status == "DEPRECATED" {
if item.Attributes.Status == "DEPRECATED" || item.Attributes.ReplacedBy != "" {
continue
}
if item.Attributes.Type == AttributeTypeDimension {
Expand All @@ -170,7 +171,7 @@ func (ga *GoogleAnalytics) getFilteredMetadata() ([]MetadataItem, []MetadataItem
}
}

return dimensionItems, metadata.Items, nil
return metricItems, dimensionItems, nil
}

func (ga *GoogleAnalytics) GetDimensions() ([]MetadataItem, error) {
Expand All @@ -179,7 +180,7 @@ func (ga *GoogleAnalytics) GetDimensions() ([]MetadataItem, error) {
return dimensions.([]MetadataItem), nil
}

dimensions, _, err := ga.getFilteredMetadata()
_, dimensions, err := ga.getFilteredMetadata()
if err != nil {
return nil, err
}
Expand All @@ -194,7 +195,7 @@ func (ga *GoogleAnalytics) GetMetrics() ([]MetadataItem, error) {
if metrics, _, found := ga.Cache.GetWithExpiration(cacheKey); found {
return metrics.([]MetadataItem), nil
}
_, metrics, err := ga.getFilteredMetadata()
metrics, _, err := ga.getFilteredMetadata()
if err != nil {
return nil, err
}
Expand Down
28 changes: 17 additions & 11 deletions src/DataSource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DataSourceInstanceSettings, SelectableValue } from '@grafana/data';
import { DataSourceWithBackend } from '@grafana/runtime';
import { GADataSourceOptions, GAQuery } from './types';
import { GADataSourceOptions, GAMetadata, GAQuery } from './types';

export class DataSource extends DataSourceWithBackend<GAQuery, GADataSourceOptions> {
constructor(instanceSettings: DataSourceInstanceSettings<GADataSourceOptions>) {
Expand Down Expand Up @@ -38,29 +38,35 @@ export class DataSource extends DataSourceWithBackend<GAQuery, GADataSourceOptio
});
}

async getMetrics(query?: string): Promise<Array<SelectableValue<string>>> {
async getMetrics(query: string): Promise<Array<SelectableValue<string>>> {
return this.getResource('metrics').then(({ metrics }) => {
return metrics.reduce((pre: Array<SelectableValue<string>>, element: any) => {
let id = element.id as string;
if (query && id.toLowerCase().indexOf(query) > -1) {
return metrics.reduce((pre: Array<SelectableValue<string>>, element: GAMetadata) => {
if (
element.id.toLowerCase().indexOf(query) > -1 ||
element.attributes.uiName.toLowerCase().indexOf(query) > -1
) {
pre.push({
label: element.id,
label: element.attributes.uiName,
value: element.id,
description: element.attributes.description,
} as SelectableValue<string>);
}
return pre;
}, []);
});
}

async getDimensions(query?: string): Promise<Array<SelectableValue<string>>> {
async getDimensions(query: string): Promise<Array<SelectableValue<string>>> {
return this.getResource('dimensions').then(({ dimensions }) => {
return dimensions.reduce((pre: Array<SelectableValue<string>>, element: any) => {
let id = element.id as string;
if (query && id.toLowerCase().indexOf(query) > -1) {
return dimensions.reduce((pre: Array<SelectableValue<string>>, element: GAMetadata) => {
if (
element.id.toLowerCase().indexOf(query) > -1 ||
element.attributes.uiName.toLowerCase().indexOf(query) > -1
) {
pre.push({
label: element.id,
label: element.attributes.uiName,
value: element.id,
description: element.attributes.description,
} as SelectableValue<string>);
}
return pre;
Expand Down
230 changes: 107 additions & 123 deletions src/QueryEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { QueryEditorProps, SelectableValue } from '@grafana/data';
import { AsyncMultiSelect, InlineFormLabel, SegmentAsync } from '@grafana/ui';
import { AsyncMultiSelect, InlineFormLabel, InlineLabel, SegmentAsync } from '@grafana/ui';
import { DataSource } from 'DataSource';
import React, { PureComponent } from 'react';
import { GADataSourceOptions, GAQuery } from 'types';
Expand All @@ -8,16 +8,6 @@ type Props = QueryEditorProps<DataSource, GAQuery, GADataSourceOptions>;

const defaultCacheDuration = 300;

export const formatCacheTimeLabel = (s: number = defaultCacheDuration) => {
if (s < 60) {
return s + 's';
} else if (s < 3600) {
return s / 60 + 'm';
}

return s / 3600 + 'h';
};

export class QueryEditor extends PureComponent<Props> {
constructor(props: Readonly<Props>) {
super(props);
Expand Down Expand Up @@ -121,126 +111,120 @@ export class QueryEditor extends PureComponent<Props> {

render() {
const { query, datasource } = this.props;
const { accountId, webPropertyId, profileId, selectedMetrics, selectedDimensions } = query;
const { accountId, webPropertyId, profileId, selectedMetrics, selectedDimensions, timezone } = query;
return (
<>
<div className="gf-form-inline">
<InlineFormLabel
width={10}
className="query-keyword"
tooltip={
<p>
The <code>accountId</code> is used to identify which GoogleAnalytics is to be accessed or altered.
</p>
}
>
Account ID
</InlineFormLabel>
<SegmentAsync
loadOptions={() => datasource.getAccountIds()}
placeholder="Enter Account ID"
value={accountId}
allowCustomValue={true}
onChange={this.onAccountIdChange}
></SegmentAsync>
<div className="gf-form gf-form--grow">
<div className="gf-form-group">
<div className="gf-form">
<InlineFormLabel
width={8}
className="query-keyword"
tooltip={
<>
The <code>accountId</code> is used to identify which GoogleAnalytics is to be accessed or altered.
</>
}
>
Account ID
</InlineFormLabel>
<SegmentAsync
loadOptions={() => datasource.getAccountIds()}
placeholder="Enter Account ID"
width={6}
value={accountId}
allowCustomValue
onChange={this.onAccountIdChange}
/>
<InlineFormLabel
width={8}
className="query-keyword"
tooltip={
<>
The <code>webPropertyId</code> is used to identify which GoogleAnalytics is to be accessed or altered.
</>
}
>
Web Property ID
</InlineFormLabel>
<SegmentAsync
loadOptions={() => datasource.getWebPropertyIds(accountId)}
placeholder="Enter Web Property ID"
value={webPropertyId}
allowCustomValue
onChange={this.onWebPropertyIdChange}
/>
<InlineFormLabel
className="query-keyword"
width={8}
tooltip={
<>
The <code>profileId</code> is used to identify which GoogleAnalytics is to be accessed or altered.
</>
}
>
Profile ID
</InlineFormLabel>
<SegmentAsync
loadOptions={() => datasource.getProfileIds(accountId, webPropertyId)}
placeholder="Enter Profile ID"
value={profileId}
allowCustomValue
onChange={this.onProfileIdChange}
/>
<InlineLabel className="query-keyword" width={'auto'} tooltip={<>GA timeZone</>}>
Timezone
</InlineLabel>
<InlineLabel width="auto">{timezone ? timezone : 'determined by profileId'}</InlineLabel>
<div className="gf-form-label gf-form-label--grow" />
</div>
</div>
<div className="gf-form-inline">
<InlineFormLabel
width={10}
className="query-keyword"
tooltip={
<p>
The <code>webPropertyId</code> is used to identify which GoogleAnalytics is to be accessed or altered.
</p>
}
>
Web Property ID
</InlineFormLabel>
<SegmentAsync
loadOptions={() => datasource.getWebPropertyIds(accountId)}
placeholder="Enter Web Property ID"
value={webPropertyId}
allowCustomValue={true}
onChange={this.onWebPropertyIdChange}
></SegmentAsync>
<div className="gf-form gf-form--grow">
<div className="gf-form-label gf-form-label--grow" />
<div className="gf-form">
<InlineFormLabel
className="query-keyword"
width={10}
tooltip={
<>
The <code>metric</code> ga:*
</>
}
>
Metrics
</InlineFormLabel>
<AsyncMultiSelect
loadOptions={(q) => datasource.getMetrics(q)}
placeholder={'ga:sessions'}
value={selectedMetrics}
onChange={this.onMetricChange}
backspaceRemovesValue
cacheOptions
noOptionsMessage={'Search Metrics'}
defaultOptions
/>
</div>
</div>

<div className="gf-form-inline">
<InlineFormLabel
width={10}
className="query-keyword"
tooltip={
<div>
The <code>profileId</code> is used to identify which GoogleAnalytics is to be accessed or altered. This
</div>
}
>
Profile ID
</InlineFormLabel>
<SegmentAsync
loadOptions={() => datasource.getProfileIds(accountId, webPropertyId)}
placeholder="Enter Profile ID"
value={profileId}
allowCustomValue={true}
onChange={this.onProfileIdChange}
></SegmentAsync>

<div className="gf-form gf-form--grow">
<div className="gf-form-label gf-form-label--grow" />
<div className="gf-form">
<InlineFormLabel
className="query-keyword"
width={10}
tooltip={
<>
The <code>dimensions</code> At least one ga:date* is required.
</>
}
>
Dimensions
</InlineFormLabel>
<AsyncMultiSelect
loadOptions={(q) => datasource.getDimensions(q)}
placeholder={'ga:dateHour'}
value={selectedDimensions}
onChange={this.onDimensionChange}
backspaceRemovesValue
cacheOptions
noOptionsMessage={'Search Dimension'}
defaultOptions
/>
</div>
</div>

<div className="gf-form-inline">
<InlineFormLabel
width={10}
className="query-keyword"
tooltip={
<p>
The <code>metric</code> ga:*
</p>
}
>
Metrics
</InlineFormLabel>
<AsyncMultiSelect
loadOptions={(q) => datasource.getMetrics(q)}
placeholder={'ga:sessions'}
value={selectedMetrics}
onChange={this.onMetricChange}
backspaceRemovesValue
cacheOptions
noOptionsMessage={'Search Metrics'}
></AsyncMultiSelect>
</div>

<div className="gf-form-inline">
<InlineFormLabel
width={10}
className="query-keyword"
tooltip={
<p>
The <code> dimensions </code> At least one ga:date* is required.
</p>
}
>
Dimension
</InlineFormLabel>
<AsyncMultiSelect
loadOptions={(q) => datasource.getDimensions(q)}
placeholder={'ga:dateHour'}
value={selectedDimensions}
onChange={this.onDimensionChange}
backspaceRemovesValue
cacheOptions
noOptionsMessage={'Search Dimension'}
></AsyncMultiSelect>
</div>
</>
);
}
Expand Down
17 changes: 17 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,20 @@ export interface GASecureJsonData {
profileId?: string;
timezone?: string;
}

export interface GAMetadata {
id: string;
kind: string;
attributes: GAMetadataAttribute;
}

export interface GAMetadataAttribute {
type: string;
dataType: string;
group: string;
status?: string;
uiName: string;
description: string;
allowedInSegments?: string;
addedInAPIVersion?: string;
}

0 comments on commit 73cb661

Please sign in to comment.