From ceabd3c292f3617f5ddddcba9c96069a69f186ff Mon Sep 17 00:00:00 2001
From: "R.Piontik" <r.piontik@mail.ru>
Date: Mon, 11 Apr 2022 19:41:27 +0300
Subject: [PATCH] =?UTF-8?q?=D0=9F=D1=80=D0=B8=20=D0=BA=D1=80=D0=B8=D1=82?=
 =?UTF-8?q?=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=B8=D1=85=20=D0=BE=D1=88=D0=B8?=
 =?UTF-8?q?=D0=B1=D0=BA=D0=B0=D1=85=20=D0=B7=D0=B0=D0=B3=D1=80=D1=83=D0=B7?=
 =?UTF-8?q?=D0=BA=D0=B8,=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D0=B2?=
 =?UTF-8?q?=D1=8B=D0=B2=D0=BE=D0=B4=D0=B8=D1=82=D1=81=D1=8F=20=D0=B8=D0=BD?=
 =?UTF-8?q?=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BE=20?=
 =?UTF-8?q?=D0=BF=D1=80=D0=B8=D1=87=D0=BD=D0=B0=D1=85=20=D0=BD=D0=B0=20?=
 =?UTF-8?q?=D0=B3=D0=BB=D0=B0=D0=B2=D0=BD=D0=BE=D0=BC=20=D1=8D=D0=BA=D1=80?=
 =?UTF-8?q?=D0=B0=D0=BD=D0=B5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/components/Problems/Problems.vue | 48 ++++++++++++++----------
 src/components/Root.vue              | 10 ++++-
 src/main.js                          |  1 +
 src/manifest/manifest_parser.js      | 56 +++++++++++++---------------
 src/manifest/prototype.js            |  3 +-
 src/storage/gitlab.js                | 33 +++++++++++++---
 6 files changed, 93 insertions(+), 58 deletions(-)

diff --git a/src/components/Problems/Problems.vue b/src/components/Problems/Problems.vue
index cc0b295c..3b4d978b 100644
--- a/src/components/Problems/Problems.vue
+++ b/src/components/Problems/Problems.vue
@@ -1,29 +1,39 @@
 <template>
-  <v-container>
-    <v-tabs v-model="currentTab">
-      <v-tab v-for="tab in problems" :key="tab.title" ripple>
-        {{ tab.title }}
-      </v-tab>
-    </v-tabs>
-    <ul v-if="problems.length" style="margin-top: 16px">
-      <template v-for="problem in problems[currentTab].problems">
-        <li :key="problem.route">
-          <router-link v-if="!problem.target"
-              :to="problem.route">{{problem.title}}
-          </router-link>
-          <a v-else :href="problem.route" :target="problem.target">
-            {{problem.title}}
-          </a>
-        </li>
-      </template>
-    </ul>
-  </v-container>
+  <div>
+    <v-container>
+      <v-tabs v-model="currentTab">
+        <v-tab v-for="tab in problems" :key="tab.title" ripple>
+          {{ tab.title }}
+        </v-tab>
+      </v-tabs>
+      <ul v-if="problems.length" style="margin-top: 16px">
+        <template v-for="problem in problems[currentTab].problems">
+          <li :key="problem.route">
+            <a v-if="problem.target === 'plugin'" @click="onGoto(problem.route)">
+              {{problem.title}}
+            </a>
+            <router-link v-else-if="!problem.target"
+                :to="problem.route">{{problem.title}}
+            </router-link>
+            <a v-else :href="problem.route" :target="problem.target">
+              {{problem.title}}
+            </a>
+          </li>
+        </template>
+      </ul>
+    </v-container>
+  </div>
 </template>
 
 <script>
 
 export default {
   name: 'Problems',
+  methods: {
+    onGoto(route) {
+      window.$PAPI.goto(route);
+    }
+  },
   computed: {
     problems() {
       const tabs = {};
diff --git a/src/components/Root.vue b/src/components/Root.vue
index 798b4e98..0f50f4f3 100644
--- a/src/components/Root.vue
+++ b/src/components/Root.vue
@@ -59,7 +59,8 @@
       </v-navigation-drawer>
       <plugin-init v-if="isNotInited"/>
       <v-content v-else v-show="!isLoading" style="min-height:100%" class="router-view">
-        <router-view/>
+        <problems v-if="isCriticalError"></problems>
+        <router-view v-else/>
       </v-content>
       <v-progress-circular
           v-show="isLoading"
@@ -77,6 +78,7 @@
 
 import Menu from "./Menu";
 import PluginInit from '../idea/components/Init.vue'
+import Problems from './Problems/Problems.vue'
 
 const minDrawerSize = 200;
 const defaultDrawerSize = 300;
@@ -85,7 +87,8 @@ export default {
   name: 'Root',
   components: {
     Menu,
-    PluginInit
+    PluginInit,
+    Problems
   },
   mounted() {
     const el = this.$refs.drawer.$el;
@@ -156,6 +159,9 @@ export default {
     },
     isNotInited() {
       return this.isPlugin && this.$store.state.notInited;
+    },
+    isCriticalError() {
+      return this.isPlugin && this.$store.state.criticalError;
     }
   },
   data() {
diff --git a/src/main.js b/src/main.js
index d33d1984..27432e54 100644
--- a/src/main.js
+++ b/src/main.js
@@ -24,6 +24,7 @@ import PlantUML from "./components/Schema/PlantUML";
 
 
 window.Vue = Vue;
+window.Router = router;
 
 Vue.use(Vuex);
 Vue.use(Vuetify);
diff --git a/src/manifest/manifest_parser.js b/src/manifest/manifest_parser.js
index 42b25810..5afe9810 100644
--- a/src/manifest/manifest_parser.js
+++ b/src/manifest/manifest_parser.js
@@ -70,6 +70,29 @@ const parser = {
             this.docs(item, baseURI);
         }
     },
+    //Регистрирует ошибку
+    // e - объект ошибки
+    // uri - источник ошибки
+    registerError(e, uri) {
+        const errorPath = `$errors/requests/${new Date().getTime()}`;
+        this.pushToMergeMap(errorPath, null, uri);
+        // eslint-disable-next-line no-console
+        console.error(e, `Ошибка запроса [${errorPath}:${uri}]`, e);
+        let errorType = (() => {
+            switch (e.name) {
+                case 'YAMLSyntaxError':
+                case 'YAMLSemanticError':
+                    return "syntax";
+                default:
+                    return 'net';
+            }
+        })();
+
+        this.onError && this.onError(errorType, {
+            uri,
+            error: e
+        });
+    },
     // Сохраняет в карте склеивания данные
     pushToMergeMap(path, source, location) {
         if (path && path.split('/').length > 3) return;
@@ -160,16 +183,7 @@ const parser = {
                 context.node[context.property] = this.merge(context.node[context.property], response.data, URI, path);
                 this.touchProjects(URI);
             })
-                .catch((e) => {
-                    const errorPath = `$errors/requests/${new Date().getTime()}`;
-                    // eslint-disable-next-line no-console
-                    console.error(e, `Ошибка запроса (3) [${errorPath}:${URI}]`, e);
-                    this.pushToMergeMap(errorPath, null, URI);
-                    this.onError && this.onError('net', {
-                        uri: URI,
-                        error: e
-                    });
-                })
+                .catch((e) => this.registerError(e, URI))
                 .finally(() => this.decReqCounter())
         }
     },
@@ -196,16 +210,7 @@ const parser = {
                 });
             })
                 // eslint-disable-next-line no-console
-                .catch((e) => {
-                    const errorPath = `$errors/requests/${new Date().getTime()}`;
-                    // eslint-disable-next-line no-console
-                    console.error(e, `Ошибка запроса (4) [${errorPath}:${URI}]`, e);
-                    this.pushToMergeMap(errorPath, null, URI);
-                    this.onError && this.onError('net', {
-                        uri: URI,
-                        error: e
-                    });
-                })
+                .catch((e) => this.registerError(e, URI))
                 .finally(() => this.decReqCounter())
         }
     },
@@ -251,16 +256,7 @@ const parser = {
             });
         })
         // eslint-disable-next-line no-console
-        .catch((e) => {
-            const errorPath = `$errors/requests/${new Date().getTime()}`;
-            // eslint-disable-next-line no-console
-            console.error(e, `Ошибка запроса (5) [${errorPath}:${uri}]`, e);
-            this.pushToMergeMap(errorPath, null, uri);
-            this.onError && this.onError('net', {
-                uri,
-                error: e
-            });
-        })
+        .catch((e) => this.registerError(e, uri))
         .finally(() => {
             this.decReqCounter();
         });
diff --git a/src/manifest/prototype.js b/src/manifest/prototype.js
index 00efd7af..6cec0679 100644
--- a/src/manifest/prototype.js
+++ b/src/manifest/prototype.js
@@ -23,7 +23,8 @@ export default {
 
     // manifest - манифест
     expandAll(mainfest) {
-        [
+        mainfest
+        && [
             "docs", "components", "datasets",
             "contexts", "aspects"
         ].forEach((section) => this.expandSection(mainfest[section]));
diff --git a/src/storage/gitlab.js b/src/storage/gitlab.js
index 95dda001..7c6909a5 100644
--- a/src/storage/gitlab.js
+++ b/src/storage/gitlab.js
@@ -33,7 +33,9 @@ export default {
         // Движок для рендеринга
         renderCore: 'graphviz',
         // Признак инциализации проекта в плагине
-        notInited: null
+        notInited: null,
+        // Признак критической проблемы
+        criticalError: null
     },
 
     mutations: {
@@ -44,6 +46,8 @@ export default {
             state.available_projects = {};
             state.projects = {};
             state.last_changes = {};
+            state.notInited = null;
+            state.criticalError = null;
         },
         setManifest(state, value) {
             state.manifest = value;
@@ -75,6 +79,9 @@ export default {
         setNoInited(state, value) {
             state.notInited = value;
         },
+        setCriticalError(state, value) {
+            state.criticalError = value;
+        }
     },
 
     actions: {
@@ -97,17 +104,31 @@ export default {
                 context.commit('appendProblems', 
                     query.expression(query.problems())
                     .evaluate(parser.manifest[manifest_parser.MODE_AS_IS]) || []);
+                if (!Object.keys(context.state.manifest || {}).length && (context.state.problems ||[]).length) {
+                    context.commit('setCriticalError', true);
+                }
             };
             parser.onStartReload = () => {
                 context.commit('setNoInited', false);
                 context.commit('setIsReloading', true);
             }
             parser.onError = (action, data) => {
-                if (
-                        (data.uri === consts.plugin.ROOT_MANIFEST) 
-                        && (data.error.toString().slice(0, 17) !== "YAMLSemanticError")
-                    ) {
-                        context.commit('setNoInited', true);
+                if (action === 'syntax') {
+                    const problem = {
+                        problem: "Ошибки синтаксиса",
+                        route: (data.error.config || {url: data.uri}).url
+                    };
+                    if (process.env.VUE_APP_DOCHUB_MODE === "plugin") {
+                        problem.target = "plugin";
+                        problem.title = `${data.uri.slice(19)} [${data.error}]`;
+                    } else {
+                        problem.target = "_blank";
+                        problem.title = `${data.uri} [${data.error}]`;
+                    }
+                    context.commit('appendProblems', [problem]);
+
+                } else if (data.uri === consts.plugin.ROOT_MANIFEST) {
+                    context.commit('setNoInited', true);
                 } else {
                     context.commit('appendProblems', [{
                         problem: "Сетевые ошибки",