Breakdown feature for insights report.

This commit is contained in:
Mike Cao 2023-08-06 22:52:17 -07:00
parent 5e1111db5d
commit f48720c915
6 changed files with 51 additions and 46 deletions

View File

@ -162,6 +162,13 @@ export const labels = defineMessages({
totalRecords: { id: 'labels.total-records', defaultMessage: 'Total records' }, totalRecords: { id: 'labels.total-records', defaultMessage: 'Total records' },
insights: { id: 'label.insights', defaultMessage: 'Insights' }, insights: { id: 'label.insights', defaultMessage: 'Insights' },
dropoff: { id: 'label.dropoff', defaultMessage: 'Dropoff' }, dropoff: { id: 'label.dropoff', defaultMessage: 'Dropoff' },
referrer: { id: 'label.referrer', defaultMessage: 'Referrer' },
country: { id: 'label.country', defaultMessage: 'Country' },
region: { id: 'label.region', defaultMessage: 'Region' },
city: { id: 'label.city', defaultMessage: 'City' },
browser: { id: 'label.browser', defaultMessage: 'Browser' },
device: { id: 'label.device', defaultMessage: 'Device' },
pageTitle: { id: 'label.pageTitle', defaultMessage: 'Page title' },
}); });
export const messages = defineMessages({ export const messages = defineMessages({

View File

@ -1,9 +1,11 @@
import FunnelReport from './funnel/FunnelReport'; import FunnelReport from './funnel/FunnelReport';
import EventDataReport from './event-data/EventDataReport'; import EventDataReport from './event-data/EventDataReport';
import InsightsReport from './insights/InsightsReport';
const reports = { const reports = {
funnel: FunnelReport, funnel: FunnelReport,
'event-data': EventDataReport, 'event-data': EventDataReport,
insights: InsightsReport,
}; };
export default function ReportDetails({ reportId, reportType }) { export default function ReportDetails({ reportId, reportType }) {

View File

@ -11,20 +11,6 @@ import PopupForm from '../PopupForm';
import FilterSelectForm from '../FilterSelectForm'; import FilterSelectForm from '../FilterSelectForm';
import FieldSelectForm from '../FieldSelectForm'; import FieldSelectForm from '../FieldSelectForm';
const fieldOptions = [
{ name: 'url', type: 'string' },
{ name: 'title', type: 'string' },
{ name: 'referrer', type: 'string' },
{ name: 'query', type: 'string' },
{ name: 'browser', type: 'string' },
{ name: 'os', type: 'string' },
{ name: 'device', type: 'string' },
{ name: 'country', type: 'string' },
{ name: 'region', type: 'string' },
{ name: 'city', type: 'string' },
{ name: 'language', type: 'string' },
];
export function InsightsParameters() { export function InsightsParameters() {
const { report, runReport, updateReport, isRunning } = useContext(ReportContext); const { report, runReport, updateReport, isRunning } = useContext(ReportContext);
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
@ -33,9 +19,23 @@ export function InsightsParameters() {
const { websiteId, dateRange, filters, groups } = parameters || {}; const { websiteId, dateRange, filters, groups } = parameters || {};
const queryEnabled = websiteId && dateRange && (filters?.length || groups?.length); const queryEnabled = websiteId && dateRange && (filters?.length || groups?.length);
const fieldOptions = [
{ name: 'url_path', type: 'string', label: formatMessage(labels.url) },
{ name: 'page_title', type: 'string', label: formatMessage(labels.pageTitle) },
{ name: 'referrer_domain', type: 'string', label: formatMessage(labels.referrer) },
{ name: 'url_query', type: 'string', label: formatMessage(labels.query) },
{ name: 'browser', type: 'string', label: formatMessage(labels.browser) },
{ name: 'os', type: 'string', label: formatMessage(labels.os) },
{ name: 'device', type: 'string', label: formatMessage(labels.device) },
{ name: 'country', type: 'string', label: formatMessage(labels.country) },
{ name: 'region', type: 'string', label: formatMessage(labels.region) },
{ name: 'city', type: 'string', label: formatMessage(labels.city) },
{ name: 'language', type: 'string', label: formatMessage(labels.language) },
];
const parameterGroups = [ const parameterGroups = [
{ label: formatMessage(labels.filters), group: REPORT_PARAMETERS.filters },
{ label: formatMessage(labels.breakdown), group: REPORT_PARAMETERS.groups }, { label: formatMessage(labels.breakdown), group: REPORT_PARAMETERS.groups },
{ label: formatMessage(labels.filters), group: REPORT_PARAMETERS.filters },
]; ];
const parameterData = { const parameterData = {
@ -71,12 +71,12 @@ export function InsightsParameters() {
{(close, element) => { {(close, element) => {
return ( return (
<PopupForm element={element} onClose={close}> <PopupForm element={element} onClose={close}>
{group === REPORT_PARAMETERS.filters && (
<FilterSelectForm fields={fieldOptions} onSelect={handleAdd.bind(null, group)} />
)}
{group === REPORT_PARAMETERS.groups && ( {group === REPORT_PARAMETERS.groups && (
<FieldSelectForm fields={fieldOptions} onSelect={handleAdd.bind(null, group)} /> <FieldSelectForm fields={fieldOptions} onSelect={handleAdd.bind(null, group)} />
)} )}
{group === REPORT_PARAMETERS.filters && (
<FilterSelectForm fields={fieldOptions} onSelect={handleAdd.bind(null, group)} />
)}
</PopupForm> </PopupForm>
); );
}} }}
@ -95,19 +95,19 @@ export function InsightsParameters() {
items={parameterData[group]} items={parameterData[group]}
onRemove={index => handleRemove(group, index)} onRemove={index => handleRemove(group, index)}
> >
{({ name, value }) => { {({ value, label }) => {
return ( return (
<div className={styles.parameter}> <div className={styles.parameter}>
{group === REPORT_PARAMETERS.filters && (
<>
<div>{name}</div>
<div className={styles.op}>{value[0]}</div>
<div>{value[1]}</div>
</>
)}
{group === REPORT_PARAMETERS.groups && ( {group === REPORT_PARAMETERS.groups && (
<> <>
<div>{name}</div> <div>{label}</div>
</>
)}
{group === REPORT_PARAMETERS.filters && (
<>
<div>{label}</div>
<div className={styles.op}>{value[0]}</div>
<div>{value[1]}</div>
</> </>
)} )}
</div> </div>

View File

@ -6,14 +6,15 @@ import { ReportContext } from '../Report';
export function InsightsTable() { export function InsightsTable() {
const { report } = useContext(ReportContext); const { report } = useContext(ReportContext);
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { fields = [] } = report?.parameters || {}; const { groups = [] } = report?.parameters || {};
return ( return (
<GridTable data={report?.data || []}> <GridTable data={report?.data || []}>
{fields.map(({ name }) => { {groups.map(({ name, label }) => {
return <GridColumn key={name} name={name} label={name} />; return <GridColumn key={name} name={name} label={label} />;
})} })}
<GridColumn name="total" label={formatMessage(labels.total)} /> <GridColumn name="views" label={formatMessage(labels.views)} width="100px" />
<GridColumn name="visitors" label={formatMessage(labels.visitors)} width="100px" />
</GridTable> </GridTable>
); );
} }

View File

@ -13,7 +13,7 @@ export interface InsightsRequestBody {
}; };
fields: { name: string; type: string; value: string }[]; fields: { name: string; type: string; value: string }[];
filters: string[]; filters: string[];
groups: string[]; groups: { name: string; type: string }[];
} }
export default async ( export default async (
@ -27,24 +27,19 @@ export default async (
const { const {
websiteId, websiteId,
dateRange: { startDate, endDate }, dateRange: { startDate, endDate },
fields,
filters,
groups, groups,
filters,
} = req.body; } = req.body;
if (!(await canViewWebsite(req.auth, websiteId))) { if (!(await canViewWebsite(req.auth, websiteId))) {
return unauthorized(res); return unauthorized(res);
} }
const data = await getInsights( const data = await getInsights(websiteId, groups, {
websiteId, ...filters,
{ startDate: new Date(startDate),
...filters, endDate: new Date(endDate),
startDate: new Date(startDate), });
endDate: new Date(endDate),
},
groups,
);
return ok(res, data); return ok(res, data);
} }

View File

@ -5,7 +5,7 @@ import { EVENT_TYPE } from 'lib/constants';
import { QueryFilters } from 'lib/types'; import { QueryFilters } from 'lib/types';
export async function getInsights( export async function getInsights(
...args: [websiteId: string, filters: QueryFilters, groups: { name: string; type: string }[]] ...args: [websiteId: string, groups: { name: string; type: string }[], filters: QueryFilters]
) { ) {
return runQuery({ return runQuery({
[PRISMA]: () => relationalQuery(...args), [PRISMA]: () => relationalQuery(...args),
@ -15,8 +15,8 @@ export async function getInsights(
async function relationalQuery( async function relationalQuery(
websiteId: string, websiteId: string,
filters: QueryFilters,
groups: { name: string; type: string }[], groups: { name: string; type: string }[],
filters: QueryFilters,
): Promise< ): Promise<
{ {
x: string; x: string;
@ -48,8 +48,8 @@ async function relationalQuery(
async function clickhouseQuery( async function clickhouseQuery(
websiteId: string, websiteId: string,
filters: QueryFilters,
groups: { name: string; type: string }[], groups: { name: string; type: string }[],
filters: QueryFilters,
): Promise< ): Promise<
{ {
x: string; x: string;