diff options
Diffstat (limited to 'sdnr')
6 files changed, 60 insertions, 107 deletions
diff --git a/sdnr/wt/odlux/apps/configurationApp/src/actions/deviceActions.ts b/sdnr/wt/odlux/apps/configurationApp/src/actions/deviceActions.ts index 790d2515c..83134fc92 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/actions/deviceActions.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/actions/deviceActions.ts @@ -182,13 +182,25 @@ const resolveViewDescription = (defaultNS: string | null, vPath: string, view: V // check if-feature | when | and resolve all references. view = { ...view }; view.elements = Object.keys(view.elements).reduce<{ [name: string]: ViewElement }>((acc, cur) => { - const elm = view.elements[cur]; + const resolveHistory : ViewElement[] = []; + let elm = view.elements[cur]; const key = defaultNS && cur.replace(new RegExp(`^${defaultNS}:`, "i"),"") || cur; - if (isViewElementReference(elm)) { - acc[key] = { ...(elm.ref(vPath) || elm), id: key }; - } else { - acc[key] = { ...elm, id: key }; - } + while (isViewElementReference(elm)) { + const result = (elm.ref(vPath)); + if (result) { + const [referencedElement, referencedPath] = result; + if (resolveHistory.some(hist => hist === referencedElement)) { + console.error(`Circle reference found at: ${vPath}`, resolveHistory); + break; + } + elm = referencedElement; + vPath = referencedPath; + resolveHistory.push(elm); + } + } + + acc[key] = { ...elm, id: key }; + return acc; }, {}); return view; diff --git a/sdnr/wt/odlux/apps/configurationApp/src/components/baseProps.ts b/sdnr/wt/odlux/apps/configurationApp/src/components/baseProps.ts index 73812a4b8..c08f5c9bc 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/components/baseProps.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/components/baseProps.ts @@ -23,5 +23,6 @@ export type BaseProps<TValue = string> = { inputValue: TValue, readOnly: boolean, disabled: boolean, - onChange(newValue: TValue): void -}; + onChange(newValue: TValue): void, + isKey?: boolean +};
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementString.tsx b/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementString.tsx index 95841b75d..122f7150a 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementString.tsx +++ b/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementString.tsx @@ -23,7 +23,7 @@ import { BaseProps } from "./baseProps"; import { IfWhenTextInput } from "./ifWhenTextInput"; import { checkRange, checkPattern } from "./verifyer"; -type stringEntryProps = BaseProps & { isKey: boolean }; +type stringEntryProps = BaseProps; export const UiElementString = (props: stringEntryProps) => { @@ -71,7 +71,7 @@ export const UiElementString = (props: stringEntryProps) => { <Tooltip title={isTooltipVisible ? element.description || '' : ''}> <IfWhenTextInput element={element} onChangeTooltipVisuability={setTooltipVisibility} spellCheck={false} autoFocus margin="dense" - id={element.id} label={props.isKey ? "🔑 " + element.label : element.label} type="text" value={props.inputValue} + id={element.id} label={props?.isKey ? "🔑 " + element.label : element.label} type="text" value={props.inputValue} style={{ width: 485, marginLeft: 20, marginRight: 20 }} onChange={(e: any) => { verifyValues(e.target.value) }} error={isError} @@ -81,4 +81,4 @@ export const UiElementString = (props: stringEntryProps) => { /> </Tooltip> ); -}
\ No newline at end of file +} diff --git a/sdnr/wt/odlux/apps/configurationApp/src/models/uiModels.ts b/sdnr/wt/odlux/apps/configurationApp/src/models/uiModels.ts index f0391eebf..a5a52fc2e 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/models/uiModels.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/models/uiModels.ts @@ -101,7 +101,7 @@ export type ViewElementList = (ViewElementBase & { export type ViewElementReference = ViewElementBase & { "uiType": "reference"; "referencePath": string; - "ref": (currentPath: string) => ViewElement | null; + "ref": (currentPath: string) => [ViewElement , string] | undefined; } export type ViewElementUnion = ViewElementBase & { @@ -196,13 +196,14 @@ export const ResolveFunction = Symbol("IsResolved"); export type ViewSpecification = { "id": string; + "ns"?: string; "name"?: string; "title"?: string; "parentView"?: string; "language": string; "ifFeature"?: string; "when"?: string; - "uses"?: (string[]) & { [ResolveFunction]?: () => void }; + "uses"?: (string[]) & { [ResolveFunction]?: (parent: string) => void }; "elements": { [name: string]: ViewElement }; readonly "canEdit": boolean; } diff --git a/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx b/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx index fc3c68e88..7b927785d 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx +++ b/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx @@ -332,6 +332,7 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp ? ( <Element key={uiElement.id} + isKey={isKey} inputValue={viewData[uiElement.id] == null ? '' : viewData[uiElement.id]} value={uiElement} readOnly={!canEdit} @@ -340,75 +341,6 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp /> ) : null ; } - - // // do not show elements w/o any value from the backend - // if (viewData[uiElement.id] == null && !editMode) { - // return null; - // } else if (isViewElementEmpty(uiElement)) { - // return null; - // } else if (uiElement.isList) { - // /* element is a leaf-list */ - // return <UiElementLeafList - // key={uiElement.id} - // inputValue={viewData[uiElement.id] || ''} - // value={uiElement} - // readOnly={!canEdit} - // disabled={editMode && !canEdit} - // onChange={(e) => { this.changeValueFor(uiElement.id, e) }} - // />; - // } else if (isViewElementSelection(uiElement)) { - - // return <UiElementSelection - // key={uiElement.id} - // inputValue={viewData[uiElement.id] || ''} - // value={uiElement} - // readOnly={!canEdit} - // disabled={editMode && !canEdit} - // onChange={(e) => { this.changeValueFor(uiElement.id, e) }} - // /> - - // } else if (isViewElementBoolean(uiElement)) { - // return <UiElementBoolean - // key={uiElement.id} - // inputValue={viewData[uiElement.id] == null ? '' : viewData[uiElement.id]} - // value={uiElement} - // readOnly={!canEdit} - // disabled={editMode && !canEdit} - // onChange={(e) => { this.changeValueFor(uiElement.id, e) }} /> - - // } else if (isViewElementString(uiElement)) { - // return <UiElementString - // key={uiElement.id} - // inputValue={viewData[uiElement.id] == null ? '' : viewData[uiElement.id]} - // value={uiElement} - // isKey={isKey} - // readOnly={!canEdit} - // disabled={editMode && !canEdit} - // onChange={(e) => { this.changeValueFor(uiElement.id, e) }} /> - - // } else if (isViewElementNumber(uiElement)) { - // return <UiElementNumber - // key={uiElement.id} - // value={uiElement} - // inputValue={viewData[uiElement.id] == null ? '' : viewData[uiElement.id]} - // readOnly={!canEdit} - // disabled={editMode && !canEdit} - // onChange={(e) => { this.changeValueFor(uiElement.id, e) }} /> - // } else if (isViewElementUnion(uiElement)) { - // return <UIElementUnion - // key={uiElement.id} - // isKey={false} - // value={uiElement} - // inputValue={viewData[uiElement.id] == null ? '' : viewData[uiElement.id]} - // readOnly={!canEdit} - // disabled={editMode && !canEdit} - // onChange={(e) => { this.changeValueFor(uiElement.id, e) }} /> - // } else { - // if (process.env.NODE_ENV !== "production") { - // console.error(`Unknown element type - ${(uiElement as any).uiType} in ${(uiElement as any).id}.`) - // } - // return null; - // } }; // private renderUIReference = (uiElement: ViewElement, viewData: { [key: string]: any }, keyProperty: string | undefined, editMode: boolean, isNew: boolean) => { @@ -817,4 +749,4 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp } export const ConfigurationApplication = withStyles(styles)(withRouter(connect(mapProps, mapDispatch)(ConfigurationApplicationComponent))); -export default ConfigurationApplication;
\ No newline at end of file +export default ConfigurationApplication; diff --git a/sdnr/wt/odlux/apps/configurationApp/src/yang/yangParser.ts b/sdnr/wt/odlux/apps/configurationApp/src/yang/yangParser.ts index b1c1e7430..0f74297df 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/yang/yangParser.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/yang/yangParser.ts @@ -437,8 +437,8 @@ export class YangParser { // process all groupings this._groupingsToResolve.filter(vs => vs.uses && vs.uses[ResolveFunction]).forEach(vs => { - try { vs.uses![ResolveFunction]!(); } catch (error) { - console.warn(`Error resolving: [${error.message}]`); + try { vs.uses![ResolveFunction] !== undefined && vs.uses![ResolveFunction]!("|"); } catch (error) { + console.warn(`Error resolving: [${vs.name}] [${error.message}]`); } }); @@ -660,7 +660,7 @@ export class YangParser { } const key = this.extractValue(cur, "key") || undefined; if (elmConfig && !key) { - console.error(new Error(`Module: [${context.name}]${currentPath}. Found configurable list without key.`)); + console.warn(`Module: [${context.name}]${currentPath}. Found configurable list without key. Assume config shell be false.`); elmConfig = false; } const [currentView, subViews] = this.extractSubViews(cur, currentId, context, `${currentPath}/${context.name}:${cur.arg}`); @@ -821,6 +821,7 @@ export class YangParser { const viewSpec: ViewSpecification = { id: String(currentId), parentView: String(parentId), + ns: context.name, name: statement.arg != null ? statement.arg : undefined, title: statement.arg != null ? statement.arg : undefined, language: "en-us", @@ -848,7 +849,7 @@ export class YangParser { if (usesRefs && usesRefs.length > 0) { viewSpec.uses = (viewSpec.uses || []); - const resolveFunctions : (()=>void)[] = []; + const resolveFunctions : ((parentElementPath: string)=>void)[] = []; for (let i = 0; i < usesRefs.length; ++i) { const groupingName = usesRefs[i].arg; @@ -857,14 +858,14 @@ export class YangParser { } viewSpec.uses.push(this.resolveReferencePath(groupingName, context)); - - resolveFunctions.push(() => { + + resolveFunctions.push((parentElementPath: string) => { const groupingViewSpec = this.resolveGrouping(groupingName, context); if (groupingViewSpec) { // resolve recursive const resolveFunc = groupingViewSpec.uses && groupingViewSpec.uses[ResolveFunction]; - resolveFunc && resolveFunc(); + resolveFunc && resolveFunc(parentElementPath); Object.keys(groupingViewSpec.elements).forEach(key => { const elm = groupingViewSpec.elements[key]; @@ -878,14 +879,16 @@ export class YangParser { }); } - viewSpec.uses[ResolveFunction] = () => { - resolveFunctions.forEach(res => { - try { - res(); - } catch (error) { - console.error(error); - } + viewSpec.uses[ResolveFunction] = (parentElementPath: string) => { + const currentElementPath = `${parentElementPath} -> ${viewSpec.ns}:${viewSpec.name}`; + resolveFunctions.forEach(resolve => { + try { + resolve(currentElementPath); + } catch (error) { + console.error(error); + } }); + // console.log("Resolved "+currentElementPath, viewSpec); viewSpec?.uses![ResolveFunction] = undefined; } @@ -1136,9 +1139,14 @@ export class YangParser { uiType: "reference", referencePath: refPath, ref(this: ViewElement, currentPath: string) { - const resolved = resolve(refPath, currentPath); - return resolved && { - ...resolved, + const elementPath = `${currentPath}/${cur.arg}`; + + const result = resolve(refPath, elementPath); + if (!result) return undefined; + + const [resolvedElement, resolvedPath] = result; + return resolvedElement && [{ + ...resolvedElement, id: this.id, label: this.label, config: this.config, @@ -1146,7 +1154,7 @@ export class YangParser { isList: this.isList, default: this.default, description: this.description, - } as ViewElement; + } as ViewElement , resolvedPath] || undefined; } }; return res; @@ -1309,7 +1317,7 @@ export class YangParser { const vPathParts = splitVPath(vPath, vPathParser).map(p => ({ ns: p[1], property: p[2], ind: p[3] })); const resultPathParts = !vPath.startsWith("/") - ? splitVPath(currentPath, vPathParser).map(p => ({ ns: p[1], property: p[2], ind: p[3] })) + ? splitVPath(currentPath, vPathParser).map(p => { moduleName = p[1] || moduleName ; return { ns: moduleName, property: p[2], ind: p[3] } }) : []; for (let i = 0; i < vPathParts.length; ++i) { @@ -1333,17 +1341,16 @@ export class YangParser { const view: ViewSpecification = this._views[+element.viewId]; if (moduleName !== pathPart.ns) { moduleName = pathPart.ns; - element = view.elements[`${moduleName}:${pathPart.property}`]; - } else { - element = view.elements[pathPart.property] || view.elements[`${moduleName}:${pathPart.property}`]; - } + } + element = view.elements[pathPart.property] || view.elements[`${moduleName}:${pathPart.property}`]; } else { throw new Error("Could not resolve reference.\r\n" + vPath); } if (!element) throw new Error("Could not resolve path [" + pathPart.property + "] in [" + currentPath + "] \r\n" + vPath); } - return element; + moduleName = ""; // create the vPath for the resolved element, do not add the element itself this will be done later in the res(...) function + return [element, resultPathParts.slice(0,-1).map(p => `${moduleName !== p.ns ? `${moduleName=p.ns}:` : ""}${p.property}${p.ind || ''}`).join("/")]; } private resolveView(vPath: string) { |