This is an automated email from the ASF dual-hosted git repository.
zehnder pushed a commit to branch 3112-opc-ua-multi-node-selection-editor
in repository https://gitbox.apache.org/repos/asf/streampipes.git
The following commit(s) were added to
refs/heads/3112-opc-ua-multi-node-selection-editor by this push:
new b3beb3e6d0 feat(#3112): First version of text input works now
b3beb3e6d0 is described below
commit b3beb3e6d0088fd8fb2d1196b705382c183007e2
Author: Philipp Zehnder <[email protected]>
AuthorDate: Tue Aug 13 10:16:15 2024 +0200
feat(#3112): First version of text input works now
---
...eNodeBuilder.ts => TreeNodeUserInputBuilder.ts} | 7 +-
.../model/{TreeNode.ts => TreeNodeUserInput.ts} | 3 +-
.../tests/connect/{ => opcua}/opcAdapter.spec.ts | 77 ++++++++++++++--------
.../{ => opcua}/opcAdapterConfiguration.spec.ts | 65 ++++++++++++------
.../static-tree-input-text-editor.component.html | 26 ++++++++
.../static-tree-input-text-editor.component.ts | 70 ++++++++++++++++++++
6 files changed, 198 insertions(+), 50 deletions(-)
diff --git a/ui/cypress/support/builder/TreeNodeBuilder.ts
b/ui/cypress/support/builder/TreeNodeUserInputBuilder.ts
similarity index 90%
rename from ui/cypress/support/builder/TreeNodeBuilder.ts
rename to ui/cypress/support/builder/TreeNodeUserInputBuilder.ts
index 0dd04ff1c7..fcec8db9ef 100644
--- a/ui/cypress/support/builder/TreeNodeBuilder.ts
+++ b/ui/cypress/support/builder/TreeNodeUserInputBuilder.ts
@@ -22,7 +22,7 @@ export class TreeNodeBuilder {
private readonly node: TreeNode;
constructor(name: string) {
- this.node = { name, children: [] };
+ this.node = { name, children: [] , isTextConfig: false};
}
addChildren(...childrenBuilders: TreeNodeBuilder[]): TreeNodeBuilder {
@@ -32,6 +32,11 @@ export class TreeNodeBuilder {
return this;
}
+ isTextConfig(): TreeNodeBuilder {
+ this.node.isTextConfig = true;
+ return this
+ }
+
static create(
name: string,
...children: TreeNodeBuilder[]
diff --git a/ui/cypress/support/model/TreeNode.ts
b/ui/cypress/support/model/TreeNodeUserInput.ts
similarity index 94%
rename from ui/cypress/support/model/TreeNode.ts
rename to ui/cypress/support/model/TreeNodeUserInput.ts
index 49c717c0d3..681a0a4629 100644
--- a/ui/cypress/support/model/TreeNode.ts
+++ b/ui/cypress/support/model/TreeNodeUserInput.ts
@@ -16,6 +16,7 @@
*
*/
export class TreeNode {
- name: String;
+ name: string;
children?: TreeNode[];
+ isTextConfig?: boolean = false;
}
diff --git a/ui/cypress/tests/connect/opcAdapter.spec.ts
b/ui/cypress/tests/connect/opcua/opcAdapter.spec.ts
similarity index 77%
rename from ui/cypress/tests/connect/opcAdapter.spec.ts
rename to ui/cypress/tests/connect/opcua/opcAdapter.spec.ts
index f7addefa16..1e3cd8c907 100644
--- a/ui/cypress/tests/connect/opcAdapter.spec.ts
+++ b/ui/cypress/tests/connect/opcua/opcAdapter.spec.ts
@@ -27,19 +27,63 @@ describe('Test OPC-UA Adapter Pull Mode', () => {
});
it('Test OPC-UA Adapter Pull Mode', () => {
- const adapterInput = getAdapterBuilder(true);
+ const adapterInput = getAdapterBuilderWithTreeNodes(true);
ConnectUtils.testAdapter(adapterInput);
});
it('Test OPC-UA Adapter Subscription Mode', () => {
- const adapterInput = getAdapterBuilder(false);
+ const adapterInput = getAdapterBuilderWithTreeNodes(false);
+
+ ConnectUtils.testAdapter(adapterInput);
+ });
+
+ it('Test OPC-UA Adapter Text Editor Configuration', () => {
+ const adapterInput = getAdapterBuilderWithTextNodes(false);
ConnectUtils.testAdapter(adapterInput);
});
});
-const getAdapterBuilder = (pullMode: boolean) => {
+const getAdapterBuilderWithTreeNodes = (pullMode: boolean) => {
+
+ const builder = getBaseAdapterConfigBuilder(pullMode);
+ builder.addTreeNode(
+ TreeNodeBuilder.create(
+ 'Objects',
+ TreeNodeBuilder.create(
+ 'OpcPlc',
+ TreeNodeBuilder.create(
+ 'Telemetry',
+ TreeNodeBuilder.create('Basic').addChildren(
+ TreeNodeBuilder.create('AlternatingBoolean'),
+ TreeNodeBuilder.create('StepUp'),
+ TreeNodeBuilder.create('RandomSignedInt32'),
+ TreeNodeBuilder.create('RandomUnsignedInt32'),
+ ),
+ ),
+ ),
+ ),
+ );
+
+
+ return builder.build();
+};
+
+const getAdapterBuilderWithTextNodes = (pullMode: boolean) => {
+ const builder = getBaseAdapterConfigBuilder(pullMode);
+ builder.addTreeNode(
+ TreeNodeBuilder.create('ns=3;s=StepUp')
+ .isTextConfig()
+ );
+
+ return builder.build();
+};
+
+
+
+
+const getBaseAdapterConfigBuilder = (pullMode: boolean) : AdapterBuilder => {
const host: string = ParameterUtils.get('localhost', 'opcua');
const builder = AdapterBuilder.create('OPC_UA').setName(
@@ -62,32 +106,7 @@ const getAdapterBuilder = (pullMode: boolean) => {
'opc.tcp://' + host + ':50000',
);
- builder.addTreeNode(
- TreeNodeBuilder.create(
- 'Objects',
- TreeNodeBuilder.create(
- 'OpcPlc',
- TreeNodeBuilder.create(
- 'Telemetry',
- TreeNodeBuilder.create('Basic').addChildren(
- TreeNodeBuilder.create('AlternatingBoolean'),
- TreeNodeBuilder.create('StepUp'),
- TreeNodeBuilder.create('RandomSignedInt32'),
- TreeNodeBuilder.create('RandomUnsignedInt32'),
- ),
- // TreeNodeBuilder.create('Anomaly')
- // .addChildren(
- // TreeNodeBuilder.create('DipData'),
- // TreeNodeBuilder.create('NegativeTrendData'),
- // TreeNodeBuilder.create('PositiveTrendData'),
- // TreeNodeBuilder.create('SpikeData'),
- // ),
- ),
- ),
- ),
- );
-
builder.setAutoAddTimestampPropery();
- return builder.build();
+ return builder;
};
diff --git a/ui/cypress/tests/connect/opcAdapterConfiguration.spec.ts
b/ui/cypress/tests/connect/opcua/opcAdapterConfiguration.spec.ts
similarity index 76%
rename from ui/cypress/tests/connect/opcAdapterConfiguration.spec.ts
rename to ui/cypress/tests/connect/opcua/opcAdapterConfiguration.spec.ts
index 57b10bd41a..24173c88b5 100644
--- a/ui/cypress/tests/connect/opcAdapterConfiguration.spec.ts
+++ b/ui/cypress/tests/connect/opcua/opcAdapterConfiguration.spec.ts
@@ -23,13 +23,30 @@ import { TreeNodeBuilder } from
'../../support/builder/TreeNodeBuilder';
import { StaticPropertyUtils } from
'../../support/utils/userInput/StaticPropertyUtils';
import { TreeStaticPropertyUtils } from
'../../support/utils/userInput/TreeStaticPropertyUtils';
-describe('Test OPC-UA Adapter Pull Mode', () => {
+describe('Test OPC-UA Adapter Configuration', () => {
beforeEach('Setup Test', () => {
cy.initStreamPipesTest();
});
- it('Test OPC-UA Adapter Pull Mode', () => {
- const adapterConfiguration = getAdapterBuilder();
+ it('Test OPC-UA Tree Node Configuration', () => {
+ const adapterBuilder = getAdapterBuilder();
+ adapterBuilder.addTreeNode(
+ TreeNodeBuilder.create(
+ 'Objects',
+ TreeNodeBuilder.create(
+ 'OpcPlc',
+ TreeNodeBuilder.create(
+ 'Telemetry',
+ TreeNodeBuilder.create('Basic').addChildren(
+ TreeNodeBuilder.create('AlternatingBoolean'),
+ TreeNodeBuilder.create('StepUp'),
+ ),
+ ),
+ ),
+ ),
+ );
+
+ const adapterConfiguration = adapterBuilder.build();
// Set up initial configuration
ConnectUtils.goToConnect();
@@ -62,6 +79,30 @@ describe('Test OPC-UA Adapter Pull Mode', () => {
TreeStaticPropertyUtils.clickClearAndReloadButton();
TreeStaticPropertyUtils.validateAmountOfSelectedNodes(0);
});
+
+ it('Test OPC-UA Code Editor', () => {
+ const adapterConfiguration = getAdapterBuilder().build();
+
+ // Set up initial configuration
+ ConnectUtils.goToConnect();
+ ConnectUtils.goToNewAdapterPage();
+ ConnectUtils.selectAdapter(adapterConfiguration.adapterType);
+ StaticPropertyUtils.input(adapterConfiguration.adapterConfiguration);
+
+
+ TreeStaticPropertyUtils.treeEditor().should('be.visible');
+ TreeStaticPropertyUtils.textEditor().should('not.exist');
+
+ // Switch to text editor
+ TreeStaticPropertyUtils.switchToTextEditor();
+
+ // Validate that text editor is shown
+ TreeStaticPropertyUtils.treeEditor().should('not.exist');
+ TreeStaticPropertyUtils.textEditor().should('be.visible');
+
+ TreeStaticPropertyUtils.typeInTextEditor('ns=3;s=StepUp');
+
+ });
});
const getAdapterBuilder = () => {
@@ -78,22 +119,8 @@ const getAdapterBuilder = () => {
'undefined-OPC_SERVER_URL-0',
'opc.tcp://' + host + ':50000',
)
- .addTreeNode(
- TreeNodeBuilder.create(
- 'Objects',
- TreeNodeBuilder.create(
- 'OpcPlc',
- TreeNodeBuilder.create(
- 'Telemetry',
- TreeNodeBuilder.create('Basic').addChildren(
- TreeNodeBuilder.create('AlternatingBoolean'),
- TreeNodeBuilder.create('StepUp'),
- ),
- ),
- ),
- ),
- )
+
.setAutoAddTimestampPropery();
- return builder.build();
+ return builder;
};
diff --git
a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input-text-editor/static-tree-input-text-editor.component.html
b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input-text-editor/static-tree-input-text-editor.component.html
new file mode 100644
index 0000000000..c1d07b3dad
--- /dev/null
+++
b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input-text-editor/static-tree-input-text-editor.component.html
@@ -0,0 +1,26 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this file except in compliance with
+ ~ the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~
+ -->
+
+<ngx-codemirror
+ style='width: 100%'
+ [(ngModel)]='textEditor'
+ (ngModelChange)='onTextEditorChange($event)'
+ [options]='editorOptions'
+ data-cy='static-tree-input-text-editor'
+>
+</ngx-codemirror>
diff --git
a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input-text-editor/static-tree-input-text-editor.component.ts
b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input-text-editor/static-tree-input-text-editor.component.ts
new file mode 100644
index 0000000000..6042c9554d
--- /dev/null
+++
b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input-text-editor/static-tree-input-text-editor.component.ts
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+import { Subject } from 'rxjs';
+import { debounceTime } from 'rxjs/operators';
+import { RuntimeResolvableTreeInputStaticProperty } from
'@streampipes/platform-services';
+
+@Component({
+ selector: 'sp-static-tree-input-text-editor',
+ templateUrl: './static-tree-input-text-editor.component.html',
+})
+export class StaticTreeInputTextEditorComponent {
+
+ @Input()
+ staticProperty: RuntimeResolvableTreeInputStaticProperty;
+
+ @Output()
+ performValidationEmitter: EventEmitter<void> = new EventEmitter<void>();
+
+ editorOptions = {
+ mode: 'text/plain',
+ autoRefresh: true,
+ theme: 'dracula',
+ lineNumbers: true,
+ lineWrapping: true,
+ readOnly: false,
+ extraKeys: {
+ 'Ctrl-Space': 'autocomplete',
+ },
+ };
+
+ textEditor: string = '';
+
+ private textChangeSubject: Subject<string> = new Subject<string>();
+
+ constructor() {
+ this.textChangeSubject.pipe(
+ debounceTime(500),
+ ).subscribe(value => {
+ this.onTextChange(value);
+ });
+ }
+
+ onTextEditorChange(value: string): void {
+ this.textChangeSubject.next(value);
+ }
+
+ onTextChange(value: string): void {
+ const lines = value.split('\n').filter(line => !line.startsWith('#'));
+ this.staticProperty.selectedNodesInternalNames = lines;
+ this.performValidationEmitter.emit();
+ }
+
+}