import { restService } from "../services/restServices";
import { YangParser } from "../yang/yangParser";
import { Module } from "../models/yang";
-import { ViewSpecification, ViewElement, isViewElementReference, isViewElementList, isViewElementObjectOrList, isViewElementRpc, isViewElementChoise, ViewElementChoiseCase } from "../models/uiModels";
-import { element } from 'prop-types';
+import { ViewSpecification, ViewElement, isViewElementReference, isViewElementList, isViewElementObjectOrList, isViewElementRpc, isViewElementChoise, ViewElementChoiseCase, ViewElementString } from "../models/uiModels";
+
export class EnableValueSelector extends Action {
constructor(public listSpecification: ViewSpecification, public listData: any[], public keyProperty: string, public onValueSelected : (value: any) => void ) {
}
export class UpdatViewDescription extends Action {
- constructor (public vPath: string, public viewData: any, public displaySpecification: DisplaySpecification = { displayMode: DisplayModeType.doNotDisplay } ) {
+ constructor (public vPath: string, public viewData: any, public displaySpecification: DisplaySpecification = { displayMode: DisplayModeType.doNotDisplay }) {
super();
}
}
}
}
-export const updateNodeIdAsyncActionCreator = (nodeId: string) => async (dispatch: Dispatch, getState: () => IApplicationStoreState ) => {
+type HttpResult = {
+ status: number;
+ message?: string | undefined;
+ data: {
+ [key: string]: any;
+ } | null | undefined;
+};
+
+const checkResponseCode = (restResult: HttpResult) =>{
+
+ //403 gets handled by the framework from now on
- const availableCapabilities = await restService.getCapabilitiesByMoutId(nodeId);
+ return restResult.status !== 403 && ( restResult.status < 200 || restResult.status > 299);
+
+}
+
+export const updateNodeIdAsyncActionCreator = (nodeId: string) => async (dispatch: Dispatch, getState: () => IApplicationStoreState ) => {
+ dispatch(new UpdateDeviceDescription("", {}, []));
+ dispatch(new SetCollectingSelectionData(true));
+
+ const { availableCapabilities, unavailableCapabilities, importOnlyModules } = await restService.getCapabilitiesByMountId(nodeId);
+
if (!availableCapabilities || availableCapabilities.length <= 0) {
+ dispatch(new SetCollectingSelectionData(false));
+ dispatch(new UpdateDeviceDescription(nodeId, {}, []));
+ dispatch(new UpdatViewDescription("", [], {
+ displayMode: DisplayModeType.displayAsMessage,
+ renderMessage: `NetworkElement : "${nodeId}" has no capabilities.`
+ }));
throw new Error(`NetworkElement : [${nodeId}] has no capabilities.`);
}
- const parser = new YangParser();
+ const parser = new YangParser(unavailableCapabilities || undefined, importOnlyModules || undefined, nodeId);
- const capParser = /^\(.*\?revision=(\d{4}-\d{2}-\d{2})\)(\S+)$/i;
for (let i = 0; i < availableCapabilities.length; ++i){
const capRaw = availableCapabilities[i];
- const capMatch = capRaw && capParser.exec(capRaw.capability);
try {
- capMatch && await parser.addCapability(capMatch[2], capMatch[1]);
+ await parser.addCapability(capRaw.capability, capRaw.version);
} catch (err) {
- console.error(err);
+ console.error(`Error in ${capRaw.capability} ${capRaw.version}`, err);
}
}
parser.postProcess();
- console.log(parser.modules, parser.views)
+ dispatch(new SetCollectingSelectionData(false));
+
+ if (process.env.NODE_ENV === "development" ) {
+ console.log(parser, parser.modules, parser.views);
+ }
return dispatch(new UpdateDeviceDescription(nodeId, parser.modules, parser.views));
}
for (let j = 0; j < dataUrls.length; ++j) {
const dataUrl = dataUrls[j];
const restResult = (await restService.getConfigData(dataUrl));
- if (restResult.data == null || restResult.status < 200 || restResult.status > 299) {
+ if (restResult.data == null || checkResponseCode(restResult)) {
const message = restResult.data && restResult.data.errors && restResult.data.errors.error && restResult.data.errors.error[0] && restResult.data.errors.error[0]["error-message"] || "";
throw new Error(`Server Error. Status: [${restResult.status}]\n${message || restResult.message || ''}`);
}
for (let j = 0; j < dataUrls.length; ++j) {
const dataUrl = dataUrls[j];
const restResult = (await restService.getConfigData(dataUrl));
- if (restResult.data == null || restResult.status < 200 || restResult.status > 299) {
+ if (restResult.data == null || checkResponseCode(restResult)) {
const message = restResult.data && restResult.data.errors && restResult.data.errors.error && restResult.data.errors.error[0] && restResult.data.errors.error[0]["error-message"] || "";
throw new Error(`Server Error. Status: [${restResult.status}]\n${message || restResult.message || ''}`);
}
// 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;
window.setTimeout(() => dispatch(new PushAction(`${vPath}[${refKey.replace(/\//ig, "%2F")}]`)));
}));
} else {
+ // Found a list at root level of a module w/o a refenrece key.
+ dataPath += `?content=config&fields=${encodeURIComponent(viewElement.id)}(${encodeURIComponent(viewElement.key || '')})`;
+ const restResult = (await restService.getConfigData(dataPath));
+ if (restResult && restResult.status === 200 && restResult.data && restResult.data[viewElement.id] ){
+ // spoof the not existing view here
+ const refData = restResult.data[viewElement.id];
+ const refView : ViewSpecification = {
+ id: "-1",
+ canEdit: false,
+ config: false,
+ language: "en-US",
+ elements: {
+ [viewElement.key!] : {
+ uiType: "string",
+ config: false,
+ id: viewElement.key,
+ label: viewElement.key,
+ isList: true,
+ } as ViewElementString
+ }
+ };
+ dispatch(new EnableValueSelector(refView, refData, viewElement.key!, (refKey) => {
+ window.setTimeout(() => dispatch(new PushAction(`${vPath}[${refKey.replace(/\//ig, "%2F")}]`)));
+ }));
+ } else {
+ throw new Error("Found a list at root level of a module and could not determine the keys.");
+ }
dispatch(new SetCollectingSelectionData(false));
- throw new Error("Found a list at root level of a module w/o a refenrece key.");
}
return;
}
extractList = true;
} else {
- // normal case
- dataPath += `/${property}${key ? `=${key.replace(/\//ig, "%2F")}` : ""}`;
-
+ // normal case
// in case of the root element the required namespace will be added later,
// while extracting the data
+
+ dataPath += `/${property}${key ? `=${key.replace(/\%2C/g, ",").replace(/\//ig, "%2F")}` : ""}`;
+
dataMember = namespace === defaultNS
? viewElement.label
: `${namespace}:${viewElement.label}`;
return dispatch(new UpdatViewDescription(vPath, [], ds));
}
throw new Error(`Did not get response from Server. Status: [${restResult.status}]`);
- } else if (restResult.status < 200 || restResult.status > 299) {
+ } else if (checkResponseCode(restResult)) {
const message = restResult.data.errors && restResult.data.errors.error && restResult.data.errors.error[0] && restResult.data.errors.error[0]["error-message"] || "";
throw new Error(`Server Error. Status: [${restResult.status}]\n${message}`);
} else {
// extract the list -> key: list
data = extractList
- ? data[viewElement!.label] || [] // if the list is empty, it does not exist
+ ? data[viewElement!.id] || data[viewElement!.label] || [] // if the list is empty, it does not exist
: data;
} else if (viewElement! && viewElement!.uiType === "rpc") {
}
});
}
-
+
// create display specification
const ds: DisplaySpecification = viewElement! && viewElement!.uiType === "rpc"
? {
+ dataPath,
displayMode: DisplayModeType.displayAsRPC,
inputViewSpecification: inputViewSpecification && resolveViewDescription(defaultNS, vPath, inputViewSpecification),
outputViewSpecification: outputViewSpecification && resolveViewDescription(defaultNS, vPath, outputViewSpecification),
}
: {
+ dataPath,
displayMode: extractList ? DisplayModeType.displayAsList : DisplayModeType.displayAsObject,
viewSpecification: resolveViewDescription(defaultNS, vPath, viewSpecification),
keyProperty: isViewElementList(viewElement!) && viewElement.key || undefined,
+ apidocPath: isViewElementList(viewElement!) && `/apidoc/explorer/index.html?urls.primaryName=$$$standard$$$#/mounted%20${nodeId}%20${viewElement!.module || 'MODULE_NOT_DEFINED'}/$$$action$$$_${dataPath.replace(/^\//,'').replace(/[\/=\-\:]/g,'_')}_${viewElement! != null ? `${viewElement.id.replace(/[\/=\-\:]/g,'_')}_` : '' }` || undefined,
};
// update display specification
dispatch(new SetCollectingSelectionData(false));
throw new Error("No key for list [" + property + "]");
} else if (vPath.endsWith("[]") && pathParts.length - 1 === ind) {
- // handle new element
- key = viewElement.key && String(data[viewElement.key]) || "";
+ // handle new element with any number of arguments
+ let keyList = viewElement.key?.split(" ");
+ let dataPathParam = keyList?.map(id => data[id]).join(",");
+ key = viewElement.key && String(dataPathParam) || "";
isNew = key;
if (!key) {
dispatch(new SetCollectingSelectionData(false));
}
}
+ // remove read-only elements
+ const removeReadOnlyElements = (viewSpecification: ViewSpecification, isList: boolean, data: any) => {
+ if (isList) {
+ return data.map((elm : any) => removeReadOnlyElements(viewSpecification, false, elm));
+ } else {
+ return Object.keys(data).reduce<{[key: string]: any}>((acc, cur)=>{
+ const [nsOrName, name] = cur.split(':',1);
+ const element = viewSpecification.elements[cur] || viewSpecification.elements[nsOrName] || viewSpecification.elements[name];
+ if (!element && process.env.NODE_ENV === "development" ) {
+ throw new Error("removeReadOnlyElements: Could not determine elment for data.");
+ }
+ if (element && element.config) {
+ if (element.uiType==="object") {
+ const view = views[+element.viewId];
+ if (!view) {
+ throw new Error("removeReadOnlyElements: Internal Error could not determine viewId: "+element.viewId);
+ }
+ acc[cur] = removeReadOnlyElements(view, element.isList != null && element.isList, data[cur]);
+ } else {
+ acc[cur] = data[cur];
+ }
+ }
+ return acc;
+ }, {});
+ }
+ };
+ data = removeReadOnlyElements(viewSpecification, embedList, data);
+
+
// embed the list -> key: list
data = embedList
? { [viewElement!.label]: data }
// do not extract root member (0)
if (viewSpecification && viewSpecification.id !== "0") {
- const updateResult = await restService.setConfigData(dataPath, { [`${defaultNS}:${dataMember!}`]: data }); // addDataMember using defaultNS
- if (updateResult.status < 200 || updateResult.status > 299) {
+ const updateResult = await restService.setConfigData(dataPath, { [`${currentNS}:${dataMember!}`]: data }); // addDataMember using currentNS
+ if (checkResponseCode(updateResult)) {
const message = updateResult.data && updateResult.data.errors && updateResult.data.errors.error && updateResult.data.errors.error[0] && updateResult.data.errors.error[0]["error-message"] || "";
throw new Error(`Server Error. Status: [${updateResult.status}]\n${message || updateResult.message || ''}`);
}
}
if (isNew) {
- return dispatch(new ReplaceAction(`/configuration/${nodeId}/${vPath.replace(/\[\]$/i, `[${isNew}]`)}`)) // navigate to new element
+ return dispatch(new ReplaceAction(`/configuration/${nodeId}/${vPath.replace(/\[\]$/i, `[${isNew}]`)}`)); // navigate to new element
}
// create display specification
}
const updateResult = await restService.removeConfigElement(dataPath);
- if (updateResult.status < 200 || updateResult.status > 299) {
+ if (checkResponseCode(updateResult)) {
const message = updateResult.data && updateResult.data.errors && updateResult.data.errors.error && updateResult.data.errors.error[0] && updateResult.data.errors.error[0]["error-message"] || "";
throw new Error(`Server Error. Status: [${updateResult.status}]\n${message || updateResult.message || ''}`);
}
// do not post root member (0)
if ((viewSpecification && viewSpecification.id !== "0") || (dataMember! && !data)) {
const updateResult = await restService.executeRpc(dataPath, { [`${defaultNS}:input`]: data || {} });
- if (updateResult.status < 200 || updateResult.status > 299) {
+ if (checkResponseCode(updateResult)) {
const message = updateResult.data && updateResult.data.errors && updateResult.data.errors.error && updateResult.data.errors.error[0] && updateResult.data.errors.error[0]["error-message"] || "";
throw new Error(`Server Error. Status: [${updateResult.status}]\n${message || updateResult.message || ''}`);
}