Feat: add tip and preset model for plugin editor, improve e2e stability (#2581)

diff --git a/web/cypress/e2e/plugin/create-delete-in-drawer-plugin.cy.js b/web/cypress/e2e/plugin/create-delete-in-drawer-plugin.cy.js
index 4a2b6cf..f665600 100644
--- a/web/cypress/e2e/plugin/create-delete-in-drawer-plugin.cy.js
+++ b/web/cypress/e2e/plugin/create-delete-in-drawer-plugin.cy.js
@@ -292,12 +292,12 @@
       cy.contains(item)
         .parents(selector.pluginCardBordered)
         .within(() => {
-          cy.get('button').click();
+          cy.get('button').click({ force: true });
         });
       cy.get(selector.drawer)
         .should('be.visible')
         .within(() => {
-          cy.get(selector.checkedSwitcher).should('exist');
+          cy.get(selector.disabledSwitcher).should('exist');
         });
       cy.wait(timeout);
       cy.contains('button', 'Delete').click({ force: true });
diff --git a/web/cypress/e2e/plugin/create-route-with-plugin-orchestration.cy.js b/web/cypress/e2e/plugin/create-route-with-plugin-orchestration.cy.js
index 4c3801d..e297b86 100644
--- a/web/cypress/e2e/plugin/create-route-with-plugin-orchestration.cy.js
+++ b/web/cypress/e2e/plugin/create-route-with-plugin-orchestration.cy.js
@@ -59,6 +59,7 @@
     cy.contains('Next').click();
 
     cy.get(selector.groupButton).contains('Orchestration').click();
+    cy.wait(1000);
     cy.get(selector.canvas).should('be.visible');
 
     // Plugin Orchestration
diff --git a/web/cypress/e2e/plugin/plugin-schema.cy.js b/web/cypress/e2e/plugin/plugin-schema.cy.js
index ed46957..37929ad 100644
--- a/web/cypress/e2e/plugin/plugin-schema.cy.js
+++ b/web/cypress/e2e/plugin/plugin-schema.cy.js
@@ -75,10 +75,6 @@
             } else {
               cy.log(`${name} not a global plugin, skipping`);
             }
-
-            if (cases.length === i + 1) {
-              cy.reload(true);
-            }
           });
         });
       });
diff --git a/web/cypress/e2e/rest/service-edit-service-with-upstream.cy.js b/web/cypress/e2e/rest/service-edit-service-with-upstream.cy.js
index c3f6981..8badbbb 100644
--- a/web/cypress/e2e/rest/service-edit-service-with-upstream.cy.js
+++ b/web/cypress/e2e/rest/service-edit-service-with-upstream.cy.js
@@ -88,7 +88,9 @@
     cy.contains('Search').click();
     cy.contains(data.serviceName).siblings().contains('Configure').click();
 
+    cy.contains(data.upstreamName).click();
     cy.wait(500);
+    cy.contains('.ant-select-item-option-content','Custom').click();
     cy.get(selector.nodes_0_host)
       .click({
         force: true,
@@ -96,8 +98,8 @@
       .should('value', data.ip1);
     cy.get(selector.input).should('be.disabled');
 
+    cy.wait(500);
     cy.get(selector.upstreamSelector).click();
-    cy.contains('.ant-select-item-option-content', 'Custom').click();
     cy.get(selector.nodes_0_host).should('not.be.disabled').clear().type(data.ip2);
     cy.get(selector.nodes_0_port).type(data.port);
     cy.get(selector.nodes_0_weight).type(data.weight);
diff --git a/web/cypress/e2e/rest/upstream-create_and_edit_upstream_with_no_nodes.cy.js b/web/cypress/e2e/rest/upstream-create_and_edit_upstream_with_no_nodes.cy.js
index fb57def..ce15556 100644
--- a/web/cypress/e2e/rest/upstream-create_and_edit_upstream_with_no_nodes.cy.js
+++ b/web/cypress/e2e/rest/upstream-create_and_edit_upstream_with_no_nodes.cy.js
@@ -64,7 +64,6 @@
 
     cy.get(selector.upstreamNodeMinus0).should('not.exist');
     cy.contains('button', 'Next').should('not.be.disabled').click();
-    cy.contains('button', 'Next').should('not.be.disabled').click();
     cy.contains('Submit').click({
       force: true,
     });
diff --git a/web/package.json b/web/package.json
index 727b62e..925782c 100644
--- a/web/package.json
+++ b/web/package.json
@@ -6,7 +6,7 @@
   "scripts": {
     "prepare": "cd .. && husky install web/.husky",
     "analyze": "cross-env ANALYZE=1 yarn run build",
-    "build": "cp -R ./node_modules/monaco-editor ./public/ && umi build",
+    "build": "cp -R ./node_modules/monaco-editor ./public/ && NODE_OPTIONS=--max_old_space_size=4096 umi build",
     "dev": "yarn run start:dev",
     "fetch:blocks": "pro fetch-blocks --branch antd@4 && yarn run prettier",
     "i18n-remove": "pro i18n-remove --locale=zh-CN --write",
diff --git a/web/src/components/Plugin/Models.ts b/web/src/components/Plugin/Models.ts
new file mode 100644
index 0000000..2e2e550
--- /dev/null
+++ b/web/src/components/Plugin/Models.ts
@@ -0,0 +1,220 @@
+/*
+ * 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.
+ */
+
+/**
+ * Model List of PluginType of Monaco editor
+ */
+
+import { Uri, editor } from "monaco-editor";
+import * as modelCode from './modelCode'
+
+/**
+* Model type is authentication as fllows:
+*/
+export const authzcasbinModel = editor.createModel(
+    modelCode.authzcasbin,
+    "json",
+    Uri.parse("file:authz-casbin")
+  );
+
+export const authzkeycloakModel = editor.createModel(
+  modelCode.authzkeycloak,
+  "json",
+  Uri.parse("file:authz-keycloak")
+);
+
+export const forwardauthModel = editor.createModel(
+  modelCode.forwardauth,
+  "json",
+  Uri.parse("file:forward-auth")
+);
+
+export const opaModel = editor.createModel(
+  modelCode.opa,
+  "json",
+  Uri.parse("file:opa")
+);
+
+export const openidconnectModel = editor.createModel(
+  modelCode.openidconnect,
+  "json",
+  Uri.parse("file:openid-connect")
+);
+
+/**
+* Model type is security as fllows:
+*/
+
+export const csrfModel = editor.createModel(
+  modelCode.csrf,
+  "json",
+  Uri.parse("file:csrf")
+);
+
+export const iprestrictionModel = editor.createModel(
+  modelCode.iprestriction,
+  "json",
+  Uri.parse("file:ip-restriction")
+);
+
+export const uarestrictionModel = editor.createModel(
+  modelCode.uarestriction,
+  "json",
+  Uri.parse("file:ua-restriction")
+);
+
+export const uriblockerModel = editor.createModel(
+  modelCode.uriblocker,
+  "json",
+  Uri.parse("file:uri-blocker")
+);
+
+/**
+* Model type is traffic as fllows:
+*/
+
+export const clientcontrolModel = editor.createModel(
+  modelCode.clientcontrol,
+  "json",
+  Uri.parse("file:client-control")
+);
+
+export const trafficsplitModel = editor.createModel(
+  modelCode.trafficsplit,
+  "json",
+  Uri.parse("file:traffic-split")
+);
+
+/**
+* Model type is serverless as fllows:
+*/
+
+export const awslambdaModel = editor.createModel(
+  modelCode.awslambda,
+  "json",
+  Uri.parse("file:aws-lambda")
+);
+
+export const azurefunctionsModel = editor.createModel(
+  modelCode.azurefunctions,
+  "json",
+  Uri.parse("file:azure-functions")
+);
+
+export const openwhiskModel = editor.createModel(
+  modelCode.openwhisk,
+  "json",
+  Uri.parse("file:openwhisk")
+);
+
+/**
+* Model type is observability as fllows:
+*/
+
+export const clickhouseloggerModel = editor.createModel(
+  modelCode.clickhouselogger,
+  "json",
+  Uri.parse("file:clickhouse-logger")
+);
+
+export const fileloggerModel = editor.createModel(
+  modelCode.filelogger,
+  "json",
+  Uri.parse("file:file-logger")
+);
+
+export const googlecloudloggingModel = editor.createModel(
+  modelCode.googlecloudlogging,
+  "json",
+  Uri.parse("file:google-cloud-logging")
+);
+
+export const httploggerModel = editor.createModel(
+  modelCode.httplogger,
+  "json",
+  Uri.parse("file:http-logger")
+);
+
+export const kafkaloggerModel = editor.createModel(
+  modelCode.kafkalogger,
+  "json",
+  Uri.parse("file:kafka-logger")
+);
+
+export const logglyModel = editor.createModel(
+  modelCode.loggly,
+  "json",
+  Uri.parse("file:loggly")
+);
+
+export const rocketmqloggerModel = editor.createModel(
+  modelCode.rocketmqlogger,
+  "json",
+  Uri.parse("file:rocketmq-logger")
+);
+
+export const skywalkingModel = editor.createModel(
+  modelCode.skywalking,
+  "json",
+  Uri.parse("file:sky-walking")
+);
+
+export const slsloggerModel = editor.createModel(
+  modelCode.slslogger,
+  "json",
+  Uri.parse("file:sls-logger")
+);
+
+export const splunkhecloggingModel = editor.createModel(
+  modelCode.splunkheclogging,
+  "json",
+  Uri.parse("file:splunk-hec-logging")
+);
+
+export const syslogModel = editor.createModel(
+  modelCode.syslog,
+  "json",
+  Uri.parse("file:syslog")
+);
+
+export const tcploggerModel = editor.createModel(
+  modelCode.tcplogger,
+  "json",
+  Uri.parse("file:tcp-logger")
+);
+
+export const zipkinModel = editor.createModel(
+  modelCode.zipkin,
+  "json",
+  Uri.parse("file:zipkin")
+);
+
+/**
+* Model type is other as fllows:
+*/
+
+export const extpluginprereqModel = editor.createModel(
+  modelCode.extpluginprereq,
+  "json",
+  Uri.parse("file:ext-plugin-pre-req")
+);
+
+export const realipModel = editor.createModel(
+  modelCode.realip,
+  "json",
+  Uri.parse("file:real-ip")
+);
diff --git a/web/src/components/Plugin/PluginDetail.tsx b/web/src/components/Plugin/PluginDetail.tsx
index 4170a15..c4b3996 100644
--- a/web/src/components/Plugin/PluginDetail.tsx
+++ b/web/src/components/Plugin/PluginDetail.tsx
@@ -43,6 +43,8 @@
 import { fetchSchema } from './service';
 import { json2yaml, yaml2json } from '../../helpers';
 import { PluginForm, PLUGIN_UI_LIST } from './UI';
+import * as allModels from './Models';
+import * as modelCode from './modelCode';
 
 type Props = {
   name: string;
@@ -116,6 +118,9 @@
     { label: monacoModeList.YAML, value: monacoModeList.YAML },
   ];
   const targetPluginName = pluginList.find((item) => item.name === name)?.name;
+  const filteredName = name.replace("-","");
+  const targetModel = allModels[`${filteredName}Model`];
+  const targetModelCode = modelCode?.[`${filteredName}`];
 
   if (PLUGIN_UI_LIST.includes(name)) {
     modeOptions.push({
@@ -477,12 +482,13 @@
             }
           }}
           language={monacoMode.toLocaleLowerCase()}
+          beforeMount={editorWillMount}
           onMount={(editor) => {
             // NOTE: for debug & test
             // @ts-ignore
             window.monacoEditor = editor;
+            if(targetModel)editor.setValue(targetModelCode);
           }}
-          beforeMount={editorWillMount}
           options={{
             scrollbar: {
               vertical: 'hidden',
diff --git a/web/src/components/Plugin/modelCode.ts b/web/src/components/Plugin/modelCode.ts
new file mode 100644
index 0000000..52f04ba
--- /dev/null
+++ b/web/src/components/Plugin/modelCode.ts
@@ -0,0 +1,316 @@
+/*
+ * 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.
+ */
+
+/**
+ * Model Code List of Models of Monaco editor
+ */
+
+/**
+* Model code of authentication type as fllows:
+*/
+
+export const authzcasbin = `{
+    "model_path":
+    "policy_path":
+    "username":
+}`;
+
+export const authzkeycloak =`{
+    "token_endpoint":
+    "permissions":
+    "audience":
+}
+`;
+
+export const forwardauth =`{
+    "uri":
+    "request_headers":
+    "upstream_headers":
+    "client_headers":
+}
+`;
+
+export const opa = `{
+    "type":
+    "request": {
+        "scheme":
+        "path":
+        "headers": {
+            "user-agent":
+            "accept":
+            "host":
+        },
+        "query":
+        "port":
+        "method":
+        "host":
+    },
+    "var": {
+        "timestamp":
+        "server_addr":
+        "server_port":
+        "remote_port":
+        "remote_addr":
+    },
+    "route":
+    "service":
+    "consumer":
+}
+`;
+
+export const openidconnect =`{
+    "client_id":
+    "client_secret":
+    "discovery":
+    "introspection_endpoint":
+    "bearer_only":
+    "realm":
+    "introspection_endpoint_auth_method":
+}
+`;
+
+/**
+* Model code of security type as fllows:
+*/
+
+export const csrf =`{
+    "key":
+}
+`;
+
+export const iprestriction =`{
+    "whitelist":
+}
+`;
+
+export const uarestriction =`{
+    "bypass_missing":
+    "allowlist":
+    "denylist":
+}
+`;
+
+export const uriblocker =`{
+    "block_rules":
+}
+`;
+
+/**
+* Model code of traffic type as fllows:
+*/
+
+export const clientcontrol =`{
+    "max_body_size":
+}
+`;
+
+export const trafficsplit =`{
+    "rules": [
+        {
+            "weighted_upstreams": [
+                {
+                    "upstream": {
+                        "name":
+                        "type":
+                        "nodes":
+                        "timeout": {
+                            "connect":
+                            "send":
+                            "read":
+                        }
+                    },
+                    "weight":
+                },
+                {
+                    "weight":
+                }
+            ]
+        }
+    ]
+}
+`;
+
+/**
+* Model code of serverless type as fllows:
+*/
+
+export const awslambda =`{
+  "token_endpoint":
+  "permissions":
+  "audience":
+}
+`;
+
+export const azurefunctions =`{
+    "azure-functions": {
+        "function_uri":
+        "authorization": {
+            "apikey":
+        }
+    }
+}
+`;
+
+export const openwhisk =`{
+    "api_host":
+    "service_token":
+    "namespace":
+    "action":
+}
+`;
+
+/**
+* Model code of observability type as fllows:
+*/
+
+export const clickhouselogger =`{
+    "user":
+    "password":
+    "database":
+    "logtable":
+    "endpoint_addr":
+}
+`;
+
+export const filelogger =`{
+    "path":
+}
+`;
+
+export const googlecloudlogging =`{
+    "auth_config":{
+        "project_id":
+        "private_key":
+        "token_uri":
+        "scopes":
+        "entries_uri":
+    },
+    "resource":{
+        "type":
+    },
+    "log_id":
+    "inactive_timeout":
+    "max_retry_count":
+    "buffer_duration":
+    "retry_delay":
+    "batch_max_size":
+}
+`;
+
+export const httplogger =`{
+    "uri":
+}
+`;
+
+export const kafkalogger =`{
+    "broker_list" :
+    "kafka_topic" :
+    "key" :
+    "batch_max_size":
+    "name":
+}
+`;
+
+export const loggly =`{
+    "nameserver_list":
+    "topic":
+    "batch_max_size":
+    "name":
+}
+`;
+
+export const rocketmqlogger =`{
+  "token_endpoint":
+  "permissions":
+  "audience":
+}
+`;
+
+export const skywalking =`{
+    "sample_ratio":
+}
+`;
+
+export const skywalkinglogger =`{
+    "endpoint_addr":
+}
+`;
+
+export const slslogger =`{
+    "host":
+    "port":
+    "project":
+    "logstore":
+    "access_key_id":
+    "access_key_secret":
+    "timeout":
+}
+`;
+
+export const splunkheclogging =`{
+    "endpoint":{
+        "uri":
+        "token":
+        "channel":
+        "timeout":
+    },
+    "buffer_duration":
+    "max_retry_count":
+    "retry_delay":
+    "inactive_timeout":
+    "batch_max_size":
+}
+`;
+
+export const syslog =`{
+    "host":
+    "port":
+    "flush_limit":
+}
+`;
+
+export const tcplogger =`{
+    "host":
+    "port":
+    "tls":
+    "batch_max_size":
+    "name":
+}
+`;
+
+export const zipkin =`{
+    "endpoint":
+    "sample_ratio":
+    "service_name":
+    "server_addr":
+}
+`;
+
+/**
+* Model code of other type as fllows:
+*/
+
+export const extpluginprereq =`{
+    "conf":
+}
+`;
+
+export const realip =`{
+    "source":
+    "trusted_addresses":
+}
+`;
diff --git a/web/src/locales/en-US/component.ts b/web/src/locales/en-US/component.ts
index fb11721..a9e6643 100644
--- a/web/src/locales/en-US/component.ts
+++ b/web/src/locales/en-US/component.ts
@@ -26,6 +26,7 @@
   'component.global.enable': 'Enable',
   'component.global.disable': 'Disable',
   'component.global.scope': 'Scope',
+  'component.global.example': 'Example',
   'component.global.data.editor': 'Raw Data Editor',
   'component.global.delete': 'Delete',
   'component.global.cancel': 'Cancel',
diff --git a/web/src/locales/tr-TR/component.ts b/web/src/locales/tr-TR/component.ts
index 031355c..58c8b16 100644
--- a/web/src/locales/tr-TR/component.ts
+++ b/web/src/locales/tr-TR/component.ts
@@ -26,6 +26,7 @@
   'component.global.enable': 'Aktifleştir',
   'component.global.disable': 'Devre dışı bırak',
   'component.global.scope': 'Kapsam',
+  'component.global.example': 'Örnek',
   'component.global.data.editor': 'Veri Editörü',
   'component.global.delete': 'Sil',
   'component.global.cancel': 'İptal',
diff --git a/web/src/locales/zh-CN/component.ts b/web/src/locales/zh-CN/component.ts
index a7902e0..bf48733 100644
--- a/web/src/locales/zh-CN/component.ts
+++ b/web/src/locales/zh-CN/component.ts
@@ -26,6 +26,7 @@
   'component.global.enable': '启用',
   'component.global.disable': '禁用',
   'component.global.scope': '作用域',
+  'component.global.example': '例子',
   'component.global.data.editor': '数据编辑器',
   'component.global.delete': '删除',
   'component.global.cancel': '取消',