Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/MDEGroup/jjodel
Browse files Browse the repository at this point in the history
  • Loading branch information
GiordanoT committed Oct 30, 2024
2 parents 41ad10d + 28b9c6e commit 18758a9
Show file tree
Hide file tree
Showing 28 changed files with 470 additions and 266 deletions.
16 changes: 11 additions & 5 deletions sandbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,15 @@ let data:any, node:any, view:any, component:any;
let otherViews: any, m1Objects:any, firstPackage:any, DefaultNode: any, otherPackages:any, refEdges:any, extendEdges:any, React:any, Edge:any;
/*
lvalue <Select value and values> are working
need to test <select multi={true} value and values/>
with manuual view assignment (edges) if you type wrong view it becomes a mess crash
when deleting viewpoint, it is not removed from project.viewpoints.
make multiselect o isAplialeto && referece default view
!!!!!!!!! for offset
fai che offset settadelle variabili --offset-x, --offset-y che settano in css left e top del grafo.
MA: disabilita la regola se il grafo ha ui-dragging o simile qualsiasi cosa metta jqui
Expand Down Expand Up @@ -41,9 +49,9 @@ node crazy pos: when i resize a node with an edge it goes off screen?
only when changing relative % -> absolute it goes crazy, i think it uses absolute pos as a %
<div onDragEnd={"dragAnchor("+i+")"}></div>
<div onDragEnd={e()=> node.anchor[1].x = e.x;}></div>
<div onDragEnd={e()=> node.anchor[2].x = e.x;}></div>
<div onDragEnd={"dragAnchor("+i+")"}></div>
<div onDragEnd={e()=> node.anchor[1].x = e.x;}></div>
<div onDragEnd={e()=> node.anchor[2].x = e.x;}></div>
anchor roadmap
Expand All @@ -53,7 +61,6 @@ node crazy pos: when i resize a node with an edge it goes off screen?
// todo: check oldprops.views-nextprops.views and always set shouldupdate to views newly introduced or remo**ved



// need to merge file declarations? or use a filename such as the imports will work (use inmemory://? or real urls)
// advanced mode and simple mode: hide some features like positional editor in simple mode or the entire tab in view/node, start in simple mode.
// make .overlap.left .top .dow .right, .y-cemter, x-cemter, .cemter css selectors
Expand Down Expand Up @@ -249,7 +256,6 @@ for (keys in []) gives "joinOriginal" and "separator"!!! i did not override the
// because currently in package, it is child[0].child[0], but in model it's just child[0]



// optimize actions, verify toolbox create must make only 1 compositeaction for dmodelelement and 1 for dgraphelement. thenverify transaction nested nad beign end nested
// view selection in jsx by name instead of pointer (or both)
/*
Expand Down
20 changes: 8 additions & 12 deletions src/common/DV.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,6 @@ export class DefaultView {
{!data && "Model data missing."}
{/* metamodel */}
{data.isMetamodel &&
[<div className={'edges'}>
{[
Expand All @@ -388,14 +387,12 @@ export class DefaultView {
level >= 1 && firstPackage && firstPackage.children.filter(c => c).map(classifier => <DefaultNode key={classifier.id} data={classifier} />)]
}
{/* metamodel */}
{/* model */}
{level >= 1 && m1Objects.filter(o => o).map(m1object => <DefaultNode key={m1object.id} data={m1object} />)}
{decorators}
</Scrollable>
{/* language designer defined controls */}
{/* language designer defined controls */}
<Control title={'Semantic'} payoff={'Zooming'}>
<Slider name={'level'} title={'Detail level '} node={node} max={3} />
</Control>
Expand Down Expand Up @@ -448,14 +445,13 @@ export class DefaultView {

/* CLASS */

public static class(): string { return (`<View className={"root class"} onClick={()=>{/*node.events.e1(Math.random().toFixed(3))*/}}>
{/* ver 2.1 */}
// <View className={"root class " + (level === 1 && abstract ? "abstract")} + onClick={()=>{/*node.events.e1(Math.random().toFixed(3))*/}}>

public static class(): string { return (`<View className={"root class"} onClick={()=>{/*node.events.e1(Math.random().toFixed(3))*/}}>
<div className={'header'}>
{data.isSingleton && <i className='bi bi-1-square'></i>}
{level > 1 && <b className={'class-name'}> {interface ? 'Interface' : abstract ? 'Abstract Class' : 'Class'}:</b>}
{level === 1 && !data.isSingleton && <i className="bi bi-c-square-fill"></i>} <Input data={data} field={'name'} hidden={true} autosize={true} />
{data.isSingleton && <i className='bi bi-1-square'>&nbsp;</i>}
{level > 1 && <b className={'class-name'}>{interface ? 'Interface' : abstract ? 'Abstract Class' : 'Class'}: </b>}
{level === 1 && <i className="bi bi-c-square-fill"></i>}<Input data={data} field={'name'} hidden={true} autosize={true} />
</div>
{level > 2 && data.children.length > 0 && <hr/>}
Expand Down Expand Up @@ -534,7 +530,7 @@ public static enum(): string { return (
);}

/* PARAMETER */

public static parameter(): string { return (
`<View className={'root parameter w-100'}>
<span className={'feature-name'}>
Expand Down
8 changes: 5 additions & 3 deletions src/common/Defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ export class Defaults { /// TODO: this really needs to become dynamically genera
'Pointer_ViewEdgePoint',
// 'Pointer_ViewAnchors',
];
static viewpoints: Pointer<DViewPoint>[] = ['Pointer_ViewPointDefault', 'Pointer_ViewPointValidation'];

// @ts-ignore
static defaultViewsMap: Dictionary<Pointer, boolean> = Defaults.views.reduce((acc, val) => { acc[val] = true; return acc; }, {}); // U.objectFromArrayValues(Defaults.views);

static viewpoints: Pointer<DViewPoint>[] = ['Pointer_ViewPointDefault', 'Pointer_ViewPointValidation'];
// @ts-ignore
static defaultViewPointsMap: Dictionary<Pointer, boolean> = Defaults.viewpoints.reduce((acc, val) => { acc[val] = true; return acc; }, {});

static check(id: string): boolean {
return !!Defaults.defaultViewsMap[id]; // id.indexOf('Pointer_View') !== -1
return !!Defaults.defaultViewsMap[id] || !!Defaults.defaultViewPointsMap[id]; // id.indexOf('Pointer_View') !== -1
}
}
30 changes: 29 additions & 1 deletion src/common/UX.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import ReactJson from 'react-json-view' // npm i react-json-view
import React, {ReactElement, ReactNode} from "react";
import withReactContent from "sweetalert2-react-content";
import Swal from "sweetalert2";
import type { GraphElementOwnProps, GObject, Dictionary, DocString, Pointer, LGraph } from "../joiner";
import {GraphElementOwnProps, GObject, Dictionary, DocString, Pointer, LGraph, MultiSelectOptGroup} from "../joiner";
import type { InputOwnProps, SelectOwnProps } from '../components/forEndUser/Input';
import type { } from '../components/forEndUser/Select';
import {
Expand Down Expand Up @@ -349,6 +349,34 @@ export class UX{
catch (ee: any) { e = ee; jsxCompiled = GraphElementComponent.displayError(e, "JSX Syntax", v, undefined, undefined, true) as any; }
return jsxCompiled;
}
static stopEvt(e: GObject<React.SyntheticEvent>): void{
if (!e) return;
e.persist?.();
(e as any).stopImmediatePropagation?.();
e.stopPropagation?.();
let ne: any = e.nativeEvent;
e._jjIsStopped = true;
if (!ne) return;
ne.stopImmediatePropagation?.();
ne.stopPropagation?.();
if (!ne.isPropagationStopped) ne.isPropagationStopped = ()=>true;
ne._jjIsStopped = true;
}
static isStoppedEvt(e: GObject<React.SyntheticEvent>): boolean{
if (!e) return true;
if (e._jjIsStopped || e.isPropagationStopped?.()) return true;
let ne: any = e.nativeEvent;
if (!ne) return false;
return !!(ne._jjIsStopped || ne.isPropagationStopped?.());
}

static options(validTargets: MultiSelectOptGroup[]): JSX.Element[] {
return validTargets
.filter(e=>!!e)
.map(e => <optgroup label={e.label}>
{ e.options.filter(o=>!!o).map(o=><option value={o.value}>{o.label}</option>) }
</optgroup>);
}
}


Expand Down
10 changes: 6 additions & 4 deletions src/components/abstract/tabs/MetamodelTab.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, {Dispatch, ReactElement} from "react";
import {connect} from "react-redux";
import type {DModel, Pointer} from "../../../joiner";
import {DModel, Pointer, Try} from "../../../joiner";
import {
DState,
CreateElementAction,
Expand Down Expand Up @@ -45,9 +45,11 @@ function MetamodelTabComponent(props: AllProps) {

<div className={'d-flex h-100'}>
<ToolBar model={model.id} isMetamodel={model.isMetamodel} />
<div className={"GraphContainer h-100 w-100"} style={{position:"relative"}}>
{graph && <DefaultNode data={model} nodeid={graph.id} graphid={graph.id}/> || <div>Error: missing DGraph prop</div> }
</div>
<Try>
<div className={"GraphContainer h-100 w-100"} style={{position:"relative"}}>
{graph && <DefaultNode data={model} nodeid={graph.id} graphid={graph.id}/> || <div>Error: missing DGraph prop</div> }
</div>
</Try>
</div>
</div>);

Expand Down
10 changes: 6 additions & 4 deletions src/components/abstract/tabs/ModelTab.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, {Dispatch, ReactElement} from "react";
import {connect} from "react-redux";
import type {DModel, Pointer} from "../../../joiner";
import {DModel, Pointer, Try} from "../../../joiner";
import {CreateElementAction, DGraph, DModelElement, DState, LGraph, LModel, LModelElement} from "../../../joiner";
import {DefaultNode} from "../../../joiner/components";
import ToolBar from "../../toolbar/ToolBar";
Expand All @@ -24,9 +24,11 @@ function ModelTabComponent(props: AllProps) {
<ContextMenu />
<div className={'d-flex h-100'}>
<ToolBar model={model.id} isMetamodel={model.isMetamodel} metamodelId={props.metamodelid} />
<div className={"GraphContainer h-100 w-100"} style={{position:"relative"}}>
{graph && <DefaultNode data={model} nodeid={graph.id} graphid={graph.id} />}
</div>
<Try>
<div className={"GraphContainer h-100 w-100"} style={{position:"relative"}}>
{graph && <DefaultNode data={model} nodeid={graph.id} graphid={graph.id} />}
</div>
</Try>
</div>
</div>);
}
Expand Down
64 changes: 2 additions & 62 deletions src/components/editors/Info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ class builder {
<MultiSelect isMulti={true} options={extendOptions as any} value={extendValue} onChange={(v) => {
console.log('setting extend', v);
lclass.extends = v.map(e => e.value) as Any<string[]>;
}}></MultiSelect>
}} />
</label>
<label className={'input-container'}>
<b className={'me-2'}>Final:</b>
Expand Down Expand Up @@ -329,67 +329,7 @@ class builder {
case DReference.cname: isReference = true; break;
default: isShapeless = true; break;
}
let selectOptions: JSX.Element | JSX.Element[] | null;
if (isReference) {
let isContainment: boolean = value.containment;
let containerObjectsID: Pointer[] = value.fatherList.map(lm => lm.id);
let validObjects = Selectors.getObjects().filter((obj) => (featureType as LClass).isSuperClassOf(obj.instanceof, true));
validObjects = validObjects.filter( obj => !containerObjectsID.includes(obj.id)); // avoiding containment loops damiano todo: put this filter in set_value too
let freeObjects = [];
let boundObjects = [];
for (let o of validObjects) {
// todo: this check of self contain is too simple does not detect loops, would need to use fatherChain
if (isContainment && o.id === value.father.id) continue; // no self contain
if (o.isRoot) freeObjects.push(o); else boundObjects.push(o);
}
let map = (object: LObject) => <option key={object.id} value={object.id}>{object.name/*.feature('name')*/}</option>;
selectOptions = <><optgroup label={'Free Objects'}>{freeObjects.map(map)}</optgroup><optgroup label={'Bound Objects'}>{boundObjects.map(map)}</optgroup></>; }
else if (isEnumerator) {
selectOptions = <optgroup label={'Literals of ' + featureType.name}>{(featureType as LEnumerator).literals.map((literal, i) => <option key={literal.id} value={literal.id}>{literal.name}</option>)}</optgroup>;
}
else if (isShapeless) {
// damiano todo: rewrite entirely this section to separate bound and free objects, copying from if(isref)
// pointables = {objects: Selectors.getObjects(), literals: LPointerTargetable.fromArr(Selectors.getAllEnumLiterals())};
let isContainment: boolean = value.containment;
let enums: LEnumerator[] = LPointerTargetable.fromArr(Selectors.getAllEnumerators())
let classes: LClass[] = LPointerTargetable.fromArr(Selectors.getAllClasses())
let shapelessObjects: LObject[] = Selectors.getObjects().filter((o) => !o.instanceof);
// console.log('select_options', {enums, classes, shapelessObjects});
let classmap: Dictionary<DocString<'classname'>, {free:LObject[], bound:LObject[], all: LObject[]}> = {};
let shapeless: {free:LObject[], bound:LObject[], all: LObject[]} = {free:[], bound:[], all: shapelessObjects};
for (let c of classes) {
let row: {free:LObject[], bound:LObject[], all: LObject[]} = {free: [], bound:[], all: c.instances};
classmap[c.name] = row;
for (let o of row.all) {
// todo: this check of self contain is too simple does not detect loops, would need to use fatherChain
if (isContainment && o.id === value.father.id) continue; // no self contain
if (o.isRoot) row.free.push(o); else row.bound.push(o);
}
}
for (let o of shapelessObjects) { if (o.isRoot) shapeless.free.push(o); else shapeless.bound.push(o); }

selectOptions = <>
<option value={''} key={0}>--- Not a Reference ---</option>
{Object.keys(classmap).map((cname) => !classmap[cname].all.length ? null :
<>
{!classmap[cname].free.length ? null :
<optgroup label={'Free instances of ' + cname} key={'f-' + cname}>
{classmap[cname].free.map((o) => <option value={o.id} key={o.id}>{o.name}</option>)}
</optgroup>
}
{!classmap[cname].bound.length ? null :
<optgroup label={'Bound instances of ' + cname} key={'b-' + cname}>
{classmap[cname].bound.map((o) => <option value={o.id} key={o.id}>{o.name}</option>)}
</optgroup>
}
</>) }
{!shapeless.free.length ? null : <optgroup label={'Free shapeless objects'}>{shapeless.free.map( (o) => <option value={o.id} key={o.id}>{o.name}</option>)}</optgroup>}
{!shapeless.bound.length ? null : <optgroup label={'Bound shapeless objects'}>{shapeless.bound.map( (o) => <option value={o.id} key={o.id}>{o.name}</option>)}</optgroup>}
{enums.map((c) => !c.literals.length ? null : <optgroup label={'Literals of ' + c.name}>{ c.literals.map((o)=> <option value={o.id} key={o.id}>{o.name}</option>)}</optgroup>)}
</>
// console.log('select_options post', {select_options, enums, classes, shapelessObjects});
}
else selectOptions = null;
let selectOptions: JSX.Element | JSX.Element[] | null = value.validTargetsJSX;

let isPtr = isAttribute ? false : (isEnumerator || isReference ? true : undefined);
const valueslist = (filteredValues).map((val, index) =>
Expand Down
6 changes: 3 additions & 3 deletions src/components/editors/info.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
section {
padding: .5rem; // p-2
}
/*section {
padding: .5rem; // p-2 too generic selector
}*/

.console {

Expand Down
58 changes: 34 additions & 24 deletions src/components/editors/languages/Js.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,39 @@
import React, {CSSProperties, Dispatch, ReactElement, ReactNode, useEffect} from 'react';
import {connect} from 'react-redux';
import Editor, {useMonaco} from '@monaco-editor/react';
import {Defaults, DState, DViewElement, LViewElement, Pointer} from '../../../joiner';
import {
Defaults,
DPointerTargetable,
DState,
DViewElement,
LPointerTargetable,
LViewElement, Overlap,
Pointer
} from '../../../joiner';
import {useStateIfMounted} from 'use-state-if-mounted';
import {FakeStateProps} from '../../../joiner/types';
import { CommandBar, Btn } from '../../commandbar/CommandBar';

function JsEditorComponent(props: AllProps) {
const {view, field, placeHolder, height, title, getter, setter, jsxLabel} = props;
const [js, setJs] = useStateIfMounted(view.jsCondition);
const [show, setShow] = useStateIfMounted(props.initialExpand ? props.initialExpand(view, field) : false);

const {placeHolder, height, title, getter, setter, jsxLabel, field} = props;
let data: LPointerTargetable = LPointerTargetable.wrap(props.data) as any;
let value = getter ? getter(data, field) : ((data|| {}) as any)[field as any];
const [js, setJs] = useStateIfMounted(value);
const [show, setShow] = useStateIfMounted(props.initialExpand ? props.initialExpand(data, field) : false);
const [expand, setExpand] = useStateIfMounted(false);
const monaco = useMonaco();
(window as any).monaco = monaco;

const readOnly = props.readonly !== undefined ? props.readonly : Defaults.check(view.id);
const readOnly = props.readonly !== undefined ? props.readonly : !props.debugmode && Defaults.check(data.id);
const change = (value: string|undefined) => {
/* save in local state for frequent changes */
if(value !== undefined) setJs(value);
if (value !== undefined) setJs(value);
}
const blur = () => {
/* confirm in redux state for final state */
if(js && setter) setter(js);
else if(field) (view as any)[field] = js;
if (js && setter) setter(js, data, field);
else if(field) (data as any)[field] = js;
}
const monaco = useMonaco();
(window as any).monaco = monaco;

useEffect(() => {
if (!monaco) return;
Expand All @@ -43,13 +52,11 @@ function JsEditorComponent(props: AllProps) {
monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true);
monaco.languages.typescript.typescriptDefaults.addExtraLib(`declare var data: 'datatype';`);
}, [monaco]);
if (!((data && field) || (getter && setter))) return(<>Either props.data & field or both getter & setter are required.</>);

let value = '';
if(getter) value = getter();
else if(placeHolder) value = placeHolder;
else if(field && view[field]) value = (view as any)[field];
if (placeHolder && !js) value = placeHolder;

const lines = (Math.round(view.oclCondition.split(/\r|\r\n|\n/).length*1.8) < 5 ? 10 : Math.round(view.oclCondition.split(/\r|\r\n|\n/).length*1.8));
const lines = (Math.round(value.split(/\r|\r\n|\n/).length*1.8) < 5 ? 10 : Math.round(value.split(/\r|\r\n|\n/).length*1.8));

return <>
<div style={{...(props.style || {})}} className={'cursor-pointer d-flex'} onClick={e => setShow(!show)}>
Expand Down Expand Up @@ -83,25 +90,28 @@ function JsEditorComponent(props: AllProps) {
}
interface OwnProps {
readonly?: boolean;
viewID: Pointer<DViewElement, 1, 1, LViewElement>;
field?: keyof LViewElement;
data?: Pointer | DPointerTargetable | LPointerTargetable;
field?: string;
placeHolder?: string;
title?: ReactNode;
height?: number;
style?: CSSProperties;
jsxLabel?: ReactNode;
getter?: () => string;
setter?: (js: string) => void;
initialExpand?: (data: LViewElement, field?: string) => boolean;
getter?: (data?:LPointerTargetable, field?: string) => string;
setter?: (js: string, data?:LPointerTargetable, field?: string) => void;
initialExpand?: (data: LPointerTargetable, field?: string) => boolean;
}
interface StateProps { view: LViewElement }
interface StateProps {
data?: LPointerTargetable;
debugmode: boolean;}
interface DispatchProps {}
type AllProps = OwnProps & StateProps & DispatchProps;
type AllProps = Overlap<Overlap<OwnProps, StateProps>, DispatchProps>;


function mapStateToProps(state: DState, ownProps: OwnProps): StateProps {
const ret: StateProps = {} as FakeStateProps;
ret.view = LViewElement.fromPointer(ownProps.viewID);
ret.data = LViewElement.wrap(ownProps.data);
ret.debugmode = state.debug;
return ret;
}

Expand Down
Loading

0 comments on commit 18758a9

Please sign in to comment.