mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
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:
@@ -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
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 = {};
|
||||
|
||||
Reference in New Issue
Block a user