Skip to content
This repository was archived by the owner on Feb 24, 2023. It is now read-only.

Commit 5eadc6c

Browse files
authored
Merge branch 'master' into realtime-graph-issue
2 parents 0a70be7 + 75ca8ac commit 5eadc6c

File tree

19 files changed

+479
-203
lines changed

19 files changed

+479
-203
lines changed

api/src/backends/databases/GoogleCloudBigQuery.ts

Lines changed: 133 additions & 181 deletions
Large diffs are not rendered by default.

api/src/backends/databases/MongoDb.ts

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@ import { MongoDbPushConfig } from '../../Types';
1616
import BaseConfig from '../configuration/abstractions/BaseConfig';
1717
import GQLError from '../../errors/GQLError';
1818
import userMessages from '../../errors/UserMessages';
19+
import BaseLogger from '../logging/abstractions/BaseLogger';
1920

2021
@injectable()
2122
export default class MongoDb extends BaseDatabase {
2223
@inject(TYPES.Shell) protected readonly shell!: Shell;
2324
@inject(TYPES.BackendConfig) private readonly config!: BaseConfig;
25+
@inject(TYPES.BackendLogger) private readonly logger!: BaseLogger;
2426

2527
private mongoConnections: Map<string, MongoClient> = new Map<string, MongoClient>();
2628

@@ -97,6 +99,7 @@ export default class MongoDb extends BaseDatabase {
9799
pipeline: { [k: string]: any }[],
98100
limit?: number,
99101
): Promise<any[]> {
102+
//this.logger.info('Pipeline', pipeline).then();
100103
try {
101104
const collection = await this.getCollection(entity);
102105
const aggregation = collection.aggregate(pipeline);
@@ -214,6 +217,12 @@ export default class MongoDb extends BaseDatabase {
214217
};
215218
const getBrowser = () =>
216219
MongoDb.getFilterObjectFromStringFilterOption(queryOptions, 'browser', 'browser_name');
220+
const getBrowserVersion = () =>
221+
MongoDb.getFilterObjectFromStringFilterOption(
222+
queryOptions,
223+
'browser_version',
224+
'browser_version',
225+
);
217226
const getScreenSize = () =>
218227
MongoDb.getFilterObjectFromStringFilterOption(
219228
queryOptions,
@@ -257,6 +266,7 @@ export default class MongoDb extends BaseDatabase {
257266
getReferrerTld(),
258267
getMobile(),
259268
getBrowser(),
269+
getBrowserVersion(),
260270
getScreenSize(),
261271
getOS(),
262272
getCustomReleaseId(),
@@ -268,27 +278,47 @@ export default class MongoDb extends BaseDatabase {
268278
}, {} as { [k: string]: any }) as { [p: string]: any };
269279
}
270280

271-
public async simpleAppAggregation(
281+
protected async simpleAppAggregation<T extends string | string[]>(
272282
app: App,
273283
queryOptions: AppQueryOptions,
274-
key: string,
284+
key: T,
275285
checkExists = false,
276286
stringNulls = false,
277287
): Promise<{
278-
result: { key: string; user_count: number; event_count: number }[];
288+
result: {
289+
key: T extends string ? string : { field: string; value: string }[];
290+
user_count: number;
291+
event_count: number;
292+
}[];
279293
from: Date;
280294
to: Date;
281295
}> {
282296
const getMatch = () => {
283297
const match = this.getAppFilter(queryOptions);
284298
if (checkExists) {
285-
match[key] = { $exists: true };
299+
if (typeof key === 'string') {
300+
match[key] = { $exists: true };
301+
} else {
302+
key.forEach((_) => (match[_] = { $exists: true }));
303+
}
286304
}
287305
return match;
288306
};
289307

290-
const getKey = () =>
291-
stringNulls ? { $ifNull: ['$' + key, MongoDb.NULL_AS_STRING] } : '$' + key;
308+
const getKey = () => {
309+
const handleNulls = (k: string) =>
310+
stringNulls ? { $ifNull: ['$' + k, MongoDb.NULL_AS_STRING] } : '$' + k;
311+
if (typeof key === 'string') {
312+
return handleNulls(key);
313+
} else {
314+
return key.map((_) => {
315+
return {
316+
field: _,
317+
value: handleNulls(_),
318+
};
319+
});
320+
}
321+
};
292322

293323
const rows = await this.runAggregation(
294324
app,
@@ -938,6 +968,27 @@ export default class MongoDb extends BaseDatabase {
938968
return this.simpleAppAggregation(app, queryOptions, 'browser_name');
939969
}
940970

971+
public async browserVersions(
972+
app: App,
973+
queryOptions: AppQueryOptions,
974+
): Promise<{
975+
result: {
976+
key: { field: string; value: string }[];
977+
user_count: number;
978+
event_count: number;
979+
}[];
980+
from: Date;
981+
to: Date;
982+
}> {
983+
return this.simpleAppAggregation(
984+
app,
985+
queryOptions,
986+
['browser_name', 'browser_version'],
987+
false,
988+
true,
989+
);
990+
}
991+
941992
public async screenSizes(
942993
app: App,
943994
queryOptions: AppQueryOptions,
@@ -946,7 +997,7 @@ export default class MongoDb extends BaseDatabase {
946997
from: Date;
947998
to: Date;
948999
}> {
949-
return this.simpleAppAggregation(app, queryOptions, 'screen_size');
1000+
return this.simpleAppAggregation(app, queryOptions, 'screen_size', false, true);
9501001
}
9511002

9521003
public async operatingSystems(

api/src/backends/databases/abstractions/BaseDatabase.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export interface AppQueryOptions extends BaseQueryOptions {
3535
page?: string;
3636
mobile?: boolean;
3737
browser?: string;
38+
browser_version?: string;
3839
screen_size?: string;
3940
os?: string;
4041
event?: string;
@@ -224,6 +225,19 @@ export default abstract class BaseDatabase {
224225
to: Date;
225226
}>;
226227

228+
public abstract browserVersions(
229+
app: App,
230+
queryOptions: AppQueryOptions,
231+
): Promise<{
232+
result: {
233+
key: { field: string; value: string }[];
234+
user_count: number;
235+
event_count: number;
236+
}[];
237+
from: Date;
238+
to: Date;
239+
}>;
240+
227241
public abstract operatingSystems(
228242
app: App,
229243
queryOptions: AppQueryOptions,

api/src/managers/tag/AppManager.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,23 @@ export default class AppManager extends Manager<App> {
7373
event_count: Int!
7474
}
7575
76+
"""
77+
@type
78+
"""
79+
type AppGroupingKeys {
80+
field: String!
81+
value: String!
82+
}
83+
84+
"""
85+
@type
86+
"""
87+
type AppGroupingCompKeysCount {
88+
key: [AppGroupingKeys!]!
89+
user_count: Int!
90+
event_count: Int!
91+
}
92+
7693
"""
7794
@type
7895
"""
@@ -82,6 +99,15 @@ export default class AppManager extends Manager<App> {
8299
result: [AppGroupingCount!]!
83100
}
84101
102+
"""
103+
@type
104+
"""
105+
type AppGroupingCompKeysCountsResponse {
106+
from: DateTime!
107+
to: DateTime!
108+
result: [AppGroupingCompKeysCount!]!
109+
}
110+
85111
"""
86112
@type
87113
"""
@@ -123,6 +149,7 @@ export default class AppManager extends Manager<App> {
123149
page: String
124150
mobile: Boolean
125151
browser: String
152+
browser_version: String
126153
screen_size: String
127154
os: String
128155
event: String
@@ -249,6 +276,12 @@ export default class AppManager extends Manager<App> {
249276
"""
250277
browser_stats(query_options: AppQueryOptions!): AppGroupingCountsResponse!
251278
"""
279+
Browsers Versions
280+
"""
281+
browser_version_stats(
282+
query_options: AppQueryOptions!
283+
): AppGroupingCompKeysCountsResponse!
284+
"""
252285
Screen Sizes
253286
"""
254287
screen_size_stats(query_options: AppQueryOptions!): AppGroupingCountsResponse!
@@ -625,6 +658,18 @@ export default class AppManager extends Manager<App> {
625658
),
626659
);
627660
},
661+
browser_version_stats: async (parent: any, args: any, ctx: CTX) => {
662+
const app = await this.repoFactory(App).findByIdThrows(
663+
new ObjectId(parent.id),
664+
userMessages.appFailed,
665+
);
666+
return await this.orgAuth.asUserWithViewAccess(ctx, app.orgId, async () =>
667+
this.backendDatabaseFactory(app.storageProvider).browserVersions(
668+
app,
669+
args.query_options,
670+
),
671+
);
672+
},
628673
screen_size_stats: async (parent: any, args: any, ctx: CTX) => {
629674
const app = await this.repoFactory(App).findByIdThrows(
630675
new ObjectId(parent.id),

ui/src/components/molecules/AppErrorListTable.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
import { FC } from 'react';
1+
import { Dispatch, FC, SetStateAction } from 'react';
22
import { Box, Table, TableBody, TableCell, TableHead, TableRow, Tooltip } from '@mui/material';
33
import { AnchorLinkIcon } from '../atoms/AnchorLinkIcon';
44
import { CircularProgressWithLabel } from '../atoms/CircularProgressWithLabel';
55
import { AppError } from '../../lazyComponents/lists/AppErrorsList';
6+
import { AppQueryFilters } from '../../types/props/AppAnalyticsContentProps';
67

78
type AppErrorListTableProps = {
89
list: AppError[];
910
totalErrors: number;
1011
setFilter: (key: string, value: string | boolean | undefined) => void;
12+
setFilters: Dispatch<SetStateAction<AppQueryFilters>>;
1113
};
1214

1315
export const AppErrorListTable: FC<AppErrorListTableProps> = ({ list, totalErrors, setFilter }) => {

ui/src/components/organisms/AppDashboardListContent.tsx

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,29 @@ import { FC } from 'react';
22
import { Box } from '@mui/material';
33
import { DashboardListProps } from '../../lazyComponents/abstractions/AppDashboardList';
44
import { CircularProgressWithLabel } from '../atoms/CircularProgressWithLabel';
5-
import { AppGroupingCount } from '../../utils/AnalyticsUtils';
5+
import { AppGroupingCompKeysCount, AppGroupingCount } from '../../utils/AnalyticsUtils';
66

77
export const AppDashboardListContent: FC<
8-
DashboardListProps & { list: AppGroupingCount[]; total: number }
8+
DashboardListProps & { list: (AppGroupingCount | AppGroupingCompKeysCount)[]; total: number }
99
> = ({ list, total, ...props }) => {
10+
const convertKey = (
11+
key:
12+
| string
13+
| {
14+
field: string;
15+
value: string;
16+
}[],
17+
) => {
18+
if (Array.isArray(key)) {
19+
if (props.compositeValueToLabel !== undefined) {
20+
return props.compositeValueToLabel(key);
21+
}
22+
return JSON.stringify(key);
23+
} else {
24+
return key;
25+
}
26+
};
27+
1028
return (
1129
<Box width="100%">
1230
<Box display="flex" alignItems="center" mb={1}>
@@ -23,18 +41,20 @@ export const AppDashboardListContent: FC<
2341

2442
{list.map((_) => {
2543
const hasFilterLink =
26-
props.addFilter !== undefined &&
44+
(props.addFilter !== undefined || props.addCompositeFilter !== undefined) &&
2745
(props.allowFilterOnSingleEntity || list.length > 1);
2846

2947
const addFilter = () => {
3048
if (props.addFilter !== undefined) {
31-
props.addFilter(_.key);
49+
props.addFilter(convertKey(_.key));
50+
} else if (props.addCompositeFilter !== undefined && Array.isArray(_.key)) {
51+
props.addCompositeFilter(_.key);
3252
}
3353
};
3454

3555
return (
36-
<Box key={_.key} display="flex" alignItems="center">
37-
{props.useSourceIcon && (
56+
<Box key={convertKey(_.key)} display="flex" alignItems="center">
57+
{props.useSourceIcon && !Array.isArray(_.key) && (
3858
<Box
3959
component="img"
4060
src={`https://icons.duckduckgo.com/ip3/${_.key}.ico`}
@@ -70,7 +90,7 @@ export const AppDashboardListContent: FC<
7090
}
7191
onClick={hasFilterLink ? addFilter : undefined}
7292
>
73-
{_.key}
93+
{convertKey(_.key)}
7494
</Box>
7595
</Box>
7696
<Box width={100} mx={1} flexShrink={0} textAlign="right">

ui/src/dynamicPages/app/analytics.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ const AppAnalyticsPage: FC<DynamicPageProps> = (props: DynamicPageProps) => {
8585
<AppAnalyticsPageTagCheck
8686
chartPeriodProps={chartPeriodProps}
8787
setFilter={setFilter}
88+
setFilters={setFilters}
8889
setEventGroup={setEventGroup}
8990
referrerTLD={filters.referrer_tld ?? undefined}
9091
appQueryOptions={queryOptions}

ui/src/dynamicPages/app/errors.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const AppErrorsPage: FC<DynamicPageProps> = (props: DynamicPageProps) => {
1414

1515
const chartPeriodProps = useChartPeriod('errors', periodParam);
1616

17-
const { filters, setFilter } = useFilters('errors', {
17+
const { filters, setFilter, setFilters } = useFilters('errors', {
1818
event: 'error',
1919
});
2020

@@ -42,6 +42,7 @@ const AppErrorsPage: FC<DynamicPageProps> = (props: DynamicPageProps) => {
4242
<AppErrorsPageContainer
4343
chartPeriodProps={chartPeriodProps}
4444
setFilter={setFilter}
45+
setFilters={setFilters}
4546
appQueryOptions={queryOptions}
4647
appSummaryQueryOptions={summaryQueryOptions}
4748
appSummaryQueryOptionsPrev={summaryQueryOptionsPrev}
@@ -53,6 +54,7 @@ const AppErrorsPage: FC<DynamicPageProps> = (props: DynamicPageProps) => {
5354
<AppErrorsPageContent
5455
chartPeriodProps={chartPeriodProps}
5556
setFilter={setFilter}
57+
setFilters={setFilters}
5658
appQueryOptions={queryOptions}
5759
appSummaryQueryOptions={summaryQueryOptions}
5860
appSummaryQueryOptionsPrev={summaryQueryOptionsPrev}

0 commit comments

Comments
 (0)