Insights 2.0 (#14096)

* query function added to list

* dashboard reading query, adding to object

* typecasting of filter vals needed still

* numbers accepting strings too

* json-to-graphql-query => devD

* fixed unneeded return in list index.ts

* stitching and calling but not actually calling

* calls on panel change

* query object += new panel before dashboard save

* uuid generated in app not api

* fixed panel ids in query

* fixed the tests I just wrote

* passing the query data down!

* list showing data

* objDiff test moved to test

* metric bug fixes + data

* dashboard logic

* time series conversion started

* timeseries GQL query almost there

* query querying

* chart loading

* aggregate handling improved

* error handling for aggregate+filter errors

* removed query on empty queryObj

* maybe more error handling

* more error handling working

* improvements to erorr handling

* stitchGQL() error return type corrected

* added string fields to COUNT

* pushing up but needs work

* not an endless recursion

* its not pretty but it works.

* throws an error

* system collections supported

* refactor to solve some errors

* loading correct

* metric function fixed

* data loading but not blocking rendering

* removed redundant code.

* relational fields

* deep nesting relations

* options.precision has a default

* relational fields fix. (thanks azri)

* the limit

* limit and time series

* range has a default

* datat to workspace

* v-if

* panels loading

* workspaces dont get data anymore

* package.json

* requested changes

* loading

* get groups util

* timeseries => script setup

* list => script setup

* metric => script setup

* label => script setup

* declare optional props

* loadingPanels: only loading spinner on loading panels

* remove unneeded parseDate!!

* applyDataToPanels tests

* -.only

* remove unneeded steps

* processQuery tests

* tests

* removed unused var

* jest.config and some queryCaller tests

* one more test

* query tests

* typo

* clean up

* fix some but not all bugs

* bugs from merge fixed

* Start cleaning up 🧹

* Refactor custom input type

* Small tweaks in list index

* Cleanup imports

* Require Query object to be returned from query prop

* Tweak return statement

* Fix imports

* Cleanup metric watch effect

* Tweaks tweaks tweaks

* Don't rely on options, simplify fetch logic

* Add paths to validation errors

* [WIP] Start handling things in the store

* Rework query fetching logic into store

* Clean up data passing

* Use composition setup for insights store

* Remove outdated

* Fix missing return

* Allow batch updating in REST API

Allows sending an array of partial items to the endpoints, updating all to their own values

* Add batch update to graphql

* Start integrating edits

* Readd clear

* Add deletion

* Add duplication

* Finish create flow

* Resolve cache refresh on panel config

* Prevent warnings about component name

* Improve loading state

* Finalize dashboard overhaul

* Add auto-refresh sidebar detail

* Add efficient panel reloading

* Set/remove errors on succeeded requests

* Move options rendering to shared

* Fix wrong imports, render options in app

* Selectively reload panels with changed variables

* Ensure newly added panels don't lose data

* Only refresh panel if data query changed

* Never use empty filter object in metric query

* Add default value support to variable panel

* Centralize no-data state

* Only reload data on var change when query is altered

* Fix build

* Fix time series order

* Remove unused utils

* Remove no-longer-used logic

* Mark batch update result as non-nullable in GraphQL schema

* Interim flows fix

* Skip parsing undefined keys

* Refresh insights dashboard when discarding changes

* Don't submit primary key when updating batch

* Handle null prop field better

* Tweak panel padding

Co-authored-by: jaycammarano <jay.cammarano@gmail.com>
Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com>
Co-authored-by: ian <licitdev@gmail.com>
This commit is contained in:
Rijk van Zanten
2022-06-27 15:26:42 -04:00
committed by GitHub
parent 6cba7fb91f
commit 32dd709778
91 changed files with 2259 additions and 1526 deletions

View File

@@ -1,9 +1,9 @@
import { SchemaOverview } from '@directus/schema/dist/types/overview';
import { parseJSON } from '@directus/shared/utils';
import { Column } from 'knex-schema-inspector/dist/types/column';
import env from '../env';
import logger from '../logger';
import getLocalType from './get-local-type';
import { parseJSON } from './parse-json';
export default function getDefaultValue(
column: SchemaOverview[string]['columns'][string] | Column

View File

@@ -8,7 +8,8 @@ import {
GraphQLType,
} from 'graphql';
import { GraphQLJSON } from 'graphql-compose';
import { GraphQLDate, GraphQLGeoJSON } from '../services/graphql';
import { GraphQLDate } from '../services/graphql/types/date';
import { GraphQLGeoJSON } from '../services/graphql/types/geojson';
import { Type } from '@directus/shared/types';
export function getGraphQLType(localType: Type | 'alias' | 'unknown'): GraphQLScalarType | GraphQLList<GraphQLType> {

View File

@@ -1,5 +1,5 @@
import { Accountability, Permission, SchemaOverview } from '@directus/shared/types';
import { deepMap, parseFilter, parsePreset } from '@directus/shared/utils';
import { deepMap, parseFilter, parseJSON, parsePreset } from '@directus/shared/utils';
import { cloneDeep } from 'lodash';
import hash from 'object-hash';
import { getCache, setSystemCache } from '../cache';
@@ -10,7 +10,6 @@ import { RolesService } from '../services/roles';
import { UsersService } from '../services/users';
import { mergePermissions } from '../utils/merge-permissions';
import { mergePermissionsForShare } from './merge-permissions-for-share';
import { parseJSON } from './parse-json';
export async function getPermissions(accountability: Accountability, schema: SchemaOverview) {
const database = getDatabase();

View File

@@ -1,6 +1,6 @@
import SchemaInspector from '@directus/schema';
import { Accountability, Filter, SchemaOverview } from '@directus/shared/types';
import { toArray } from '@directus/shared/utils';
import { parseJSON, toArray } from '@directus/shared/utils';
import { Knex } from 'knex';
import { mapValues } from 'lodash';
import { getCache, setSystemCache } from '../cache';
@@ -13,7 +13,6 @@ import logger from '../logger';
import { RelationsService } from '../services';
import getDefaultValue from './get-default-value';
import getLocalType from './get-local-type';
import { parseJSON } from './parse-json';
export async function getSchema(options?: {
accountability?: Accountability;

View File

@@ -1,51 +0,0 @@
import { renderFn, get, Scope } from 'micromustache';
import { parseJSON } from './parse-json';
type Mustacheable = string | number | boolean | null | Mustacheable[] | { [key: string]: Mustacheable };
type GenericString<T> = T extends string ? string : T;
function resolveFn(path: string, scope?: Scope): unknown {
if (!scope) return undefined;
const value = get(scope, path);
return typeof value === 'object' ? JSON.stringify(value) : value;
}
function renderMustache<T extends Mustacheable>(item: T, scope: Scope): GenericString<T> {
if (typeof item === 'string') {
return renderFn(item, resolveFn, scope, { explicit: true }) as GenericString<T>;
} else if (Array.isArray(item)) {
return item.map((element) => renderMustache(element, scope)) as GenericString<T>;
} else if (typeof item === 'object' && item !== null) {
return Object.fromEntries(
Object.entries(item).map(([key, value]) => [key, renderMustache(value, scope)])
) as GenericString<T>;
} else {
return item as GenericString<T>;
}
}
export function applyOperationOptions(options: Record<string, any>, data: Record<string, any>): Record<string, any> {
return Object.fromEntries(
Object.entries(options).map(([key, value]) => {
if (typeof value === 'string') {
const single = value.match(/^\{\{\s*([^}\s]+)\s*\}\}$/);
if (single !== null) {
return [key, get(data, single[1])];
}
}
return [key, renderMustache(value, data)];
})
);
}
export function optionToObject<T>(option: T): Exclude<T, string> {
return typeof option === 'string' ? parseJSON(option) : option;
}
export function optionToString(option: unknown): string {
return typeof option === 'object' ? JSON.stringify(option) : String(option);
}

View File

@@ -1,16 +0,0 @@
/**
* Run JSON.parse, but ignore `__proto__` properties. This prevents prototype pollution attacks
*/
export function parseJSON(input: string): any {
if (String(input).includes('__proto__')) {
return JSON.parse(input, noproto);
}
return JSON.parse(input);
}
export function noproto<T>(key: string, value: T): T | void {
if (key !== '__proto__') {
return value;
}
}

View File

@@ -1,9 +1,8 @@
import { Accountability, Aggregate, Filter, Query } from '@directus/shared/types';
import { parseFilter } from '@directus/shared/utils';
import { parseFilter, parseJSON } from '@directus/shared/utils';
import { flatten, get, isPlainObject, merge, set } from 'lodash';
import logger from '../logger';
import { Meta } from '../types';
import { parseJSON } from './parse-json';
export function sanitizeQuery(rawQuery: Record<string, any>, accountability?: Accountability | null): Query {
const query: Query = {};