Skip to content

Commit

Permalink
[MODFQMMGR-271] Support nested entity types in creator (#252)
Browse files Browse the repository at this point in the history
  • Loading branch information
ncovercash committed Apr 29, 2024
1 parent dfe8487 commit a7414cf
Show file tree
Hide file tree
Showing 8 changed files with 300 additions and 21 deletions.
56 changes: 45 additions & 11 deletions entity-type-creator/components/EntityTypeEditor.tsx
Expand Up @@ -2,12 +2,12 @@ import { formatSql } from '@/utils/sqlUtils';
import { PostgreSQL, sql } from '@codemirror/lang-sql';
import { Refresh } from '@mui/icons-material';
import { Alert, Button, Checkbox, FormControlLabel, Grid, IconButton, InputAdornment, TextField } from '@mui/material';
import CodeMirror from '@uiw/react-codemirror';
import { useEffect, useMemo, useState } from 'react';
import { Socket } from 'socket.io-client';
import { v4 as uuid } from 'uuid';
import { DataTypeValue, EntityType } from '../types';
import EntityTypeFieldEditor from './EntityTypeFieldEditor';
import SourceEditor from './SourceEditor';

export default function EntityTypeManager({
entityTypes,
Expand All @@ -32,7 +32,7 @@ export default function EntityTypeManager({
useEffect(() => {
setEntityType({
...initialValues,
fromClause: formatSql(initialValues.fromClause),
sources: initialValues.sources ?? [],
columns: initialValues.columns?.map((column) => ({
...column,
valueGetter: column.valueGetter ? formatSql(column.valueGetter) : undefined,
Expand All @@ -54,7 +54,7 @@ export default function EntityTypeManager({
defaultSchema: 'TENANT_mod_fqm_manager',
upperCaseKeywords: true,
}),
[schema]
[schema],
);

return (
Expand Down Expand Up @@ -114,6 +114,7 @@ export default function EntityTypeManager({
label="Root"
control={
<Checkbox
indeterminate={entityType.root === undefined}
checked={entityType.root}
onChange={(e) => setEntityType({ ...entityType, root: e.target.checked })}
/>
Expand All @@ -123,6 +124,7 @@ export default function EntityTypeManager({
label="Private"
control={
<Checkbox
indeterminate={entityType.private === undefined}
checked={entityType.private}
onChange={(e) => setEntityType({ ...entityType, private: e.target.checked })}
/>
Expand Down Expand Up @@ -164,14 +166,45 @@ export default function EntityTypeManager({
</FormControl>
</Grid> */}
<Grid item xs={12}>
<fieldset style={{ display: 'flex' }}>
<legend>FROM clause</legend>
<CodeMirror
style={{ width: 0, flexGrow: 1 }}
value={entityType.fromClause}
onChange={(value) => setEntityType({ ...entityType, fromClause: value })}
extensions={[codeMirrorExtension]}
/>
<fieldset>
<legend>Sources</legend>
{entityType.sources?.map((source, i) => (
<SourceEditor
key={i}
entityTypes={entityTypes}
schema={schema}
source={source}
sources={entityType.sources ?? []}
isRoot={i === 0}
onChange={(newSource) =>
setEntityType({
...entityType,
sources: entityType.sources?.map((s, j) => (j === i ? newSource : s)),
})
}
onRemove={() =>
setEntityType({ ...entityType, sources: entityType.sources!.filter((_, j) => j !== i) })
}
/>
))}
<Button
variant="outlined"
sx={{ width: '100%', height: '4em', mt: 2 }}
onClick={() =>
setEntityType({
...entityType,
sources: [
...(entityType.sources ?? []),
{
alias: '',
type: 'db',
},
],
})
}
>
Add source
</Button>
</fieldset>
</Grid>
<Grid item xs={12}>
Expand All @@ -184,6 +217,7 @@ export default function EntityTypeManager({
parentName={entityType.name}
entityType={entityType}
entityTypes={entityTypes}
sources={entityType.sources ?? []}
codeMirrorExtension={codeMirrorExtension}
field={column}
onChange={(newColumn) =>
Expand Down
40 changes: 37 additions & 3 deletions entity-type-creator/components/EntityTypeFieldEditor.tsx
@@ -1,7 +1,8 @@
import { DataTypeValue, EntityType, EntityTypeField } from '@/types';
import { DataTypeValue, EntityType, EntityTypeField, EntityTypeSource } from '@/types';
import { LanguageSupport } from '@codemirror/language';
import { ArrowDownward, ArrowUpward, Clear } from '@mui/icons-material';
import {
Autocomplete,
Button,
Checkbox,
FormControl,
Expand All @@ -12,6 +13,7 @@ import {
MenuItem,
Select,
TextField,
Typography,
} from '@mui/material';
import CodeMirror from '@uiw/react-codemirror';
import { useMemo } from 'react';
Expand All @@ -21,6 +23,7 @@ export default function EntityTypeFieldEditor({
parentName,
entityType,
entityTypes,
sources,
codeMirrorExtension,
field,
onChange,
Expand All @@ -36,6 +39,7 @@ export default function EntityTypeFieldEditor({
parentName: string;
entityType: EntityType;
entityTypes: EntityType[];
sources: EntityTypeSource[];
codeMirrorExtension: LanguageSupport;
field: EntityTypeField;
onChange: (newColumn: EntityTypeField) => void;
Expand All @@ -55,7 +59,7 @@ export default function EntityTypeFieldEditor({
</legend>

<Grid container spacing={2}>
<Grid item xs={5}>
<Grid item xs={3}>
<TextField
label="Name"
required
Expand All @@ -65,11 +69,31 @@ export default function EntityTypeFieldEditor({
inputProps={{ style: { fontFamily: 'monospace' } }}
/>
</Grid>
<Grid item xs={5} container sx={{ justifyContent: 'space-around' }}>
<Grid item xs={3}>
<Autocomplete
freeSolo
options={sources.map((s) => s.alias)}
renderInput={(params) => (
<TextField
{...params}
label="Source"
value={field.sourceAlias ?? ''}
onChange={(e) =>
onChange({
...field,
sourceAlias: e.target.value,
})
}
/>
)}
/>
</Grid>
<Grid item xs={4} container sx={{ justifyContent: 'space-around' }}>
<FormControlLabel
label="Queryable"
control={
<Checkbox
indeterminate={field.queryable === undefined}
checked={field.queryable}
onChange={(e) => onChange({ ...field, queryable: e.target.checked })}
/>
Expand All @@ -80,6 +104,7 @@ export default function EntityTypeFieldEditor({
label="Visible by default"
control={
<Checkbox
indeterminate={field.visibleByDefault === undefined}
checked={field.visibleByDefault}
onChange={(e) => onChange({ ...field, visibleByDefault: e.target.checked })}
/>
Expand Down Expand Up @@ -149,6 +174,7 @@ export default function EntityTypeFieldEditor({
label="Is ID column"
control={
<Checkbox
indeterminate={field.visibleByDefault === undefined}
checked={field.visibleByDefault}
onChange={(e) => onChange({ ...field, visibleByDefault: e.target.checked })}
/>
Expand Down Expand Up @@ -479,6 +505,14 @@ export default function EntityTypeFieldEditor({
),
[field],
)}
<Grid item xs={2} />
<Grid item xs={10}>
<Typography variant="subtitle2" sx={{ mt: 0 }}>
<i>
Use <code>:sourceAlias</code> to refer to the selected source <code>{field.sourceAlias}</code>
</i>
</Typography>
</Grid>

<NestedDataTypeEditor
parentName={`${parentName}.${field.name}`}
Expand Down
7 changes: 5 additions & 2 deletions entity-type-creator/components/EntityTypeManager.tsx
@@ -1,5 +1,5 @@
import { Add } from '@mui/icons-material';
import { MenuItem, Select, Typography } from '@mui/material';
import { Add, Refresh } from '@mui/icons-material';
import { IconButton, MenuItem, Select, Typography } from '@mui/material';
import { useEffect, useState } from 'react';
import { Socket } from 'socket.io-client';
import { EntityType } from '../types';
Expand Down Expand Up @@ -55,6 +55,9 @@ export default function EntityTypeManager({
</MenuItem>
))}
</Select>
<IconButton onClick={() => socket.emit('refresh-entity-types')}>
<Refresh />
</IconButton>
</Typography>

{selected === 'new' && (
Expand Down
8 changes: 4 additions & 4 deletions entity-type-creator/components/PostgresConnector.tsx
Expand Up @@ -11,11 +11,11 @@ export default function PostgresConnector({
const [open, setOpen] = useState(true);

const [postgresConnection, setPostgresConnection] = useState<PostgresConnection>({
host: 'localhost',
host: 'host',
port: 5432,
database: 'db',
user: 'postgres',
password: 'postgres',
database: 'folio',
user: 'folio',
password: '',
});
const [connectionState, setConnectionState] = useState({ connected: false, message: 'Waiting to connect...' });

Expand Down

0 comments on commit a7414cf

Please sign in to comment.