diff --git a/packages/components/src/components/LazyLoader.vue b/packages/components/src/components/LazyLoader.vue
new file mode 100644
index 0000000000..23e11a1056
--- /dev/null
+++ b/packages/components/src/components/LazyLoader.vue
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/components/src/components/LoadingSpinner.vue b/packages/components/src/components/LoadingSpinner.vue
new file mode 100644
index 0000000000..064fff4275
--- /dev/null
+++ b/packages/components/src/components/LoadingSpinner.vue
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
diff --git a/packages/components/src/components/SearchBar.vue b/packages/components/src/components/SearchBar.vue
index 99838d3e5c..1492b47ecf 100644
--- a/packages/components/src/components/SearchBar.vue
+++ b/packages/components/src/components/SearchBar.vue
@@ -222,7 +222,7 @@ export default {
return this.$refs.input === window?.document?.activeElement;
},
onWindowClick(event) {
- if (!getEventTarget(event.target, this.$refs.form)) {
+ if (!getEventTarget(event.target, this.$refs.form) && this.searchValue) {
if (this.$refs.input !== window.document.activeElement) this.showSuggestions = false;
if (
diff --git a/packages/components/src/pages/VsCodeExtension.vue b/packages/components/src/pages/VsCodeExtension.vue
index 442257ed48..2f8a887b72 100644
--- a/packages/components/src/pages/VsCodeExtension.vue
+++ b/packages/components/src/pages/VsCodeExtension.vue
@@ -80,10 +80,13 @@
:tabName="VIEW_COMPONENT"
:ref="VIEW_COMPONENT"
>
-
+
+
+
+
-
+
+
+
+
-
+
+
+
+
@@ -125,13 +134,16 @@
:tabName="VIEW_FLAMEGRAPH"
:allow-scroll="false"
>
-
+
+
+
+
@@ -372,6 +384,7 @@ import {
filterStringToFilterState,
base64UrlEncode,
AppMapFilter,
+ AppMap,
} from '@appland/models';
import { unparseDiagram } from '@appland/sequence-diagram';
@@ -438,6 +451,8 @@ import isPrecomputedSequenceDiagram from '@/lib/isPrecomputedSequenceDiagram';
import { SAVED_FILTERS_STORAGE_ID } from '../components/FilterMenu.vue';
import { DEFAULT_SEQ_DIAGRAM_COLLAPSE_DEPTH } from '../components/DiagramSequence.vue';
import VCompassIcon from '@/assets/compass-simpler.svg';
+import VLazyLoader from '@/components/LazyLoader.vue';
+import VLoadingSpinner from '@/components/LoadingSpinner.vue';
const browserPrefixes = ['', 'webkit', 'moz'];
@@ -478,6 +493,8 @@ export default {
VUnlicensedNotice,
VConfigurationRequired,
VCompassIcon,
+ VLazyLoader,
+ VLoadingSpinner,
},
store,
data() {
@@ -504,6 +521,8 @@ export default {
isFullscreen: false,
showDetailsPanel: false,
rightColumnWidth: 0,
+ filteredAppMap: this.emptyFilteredAppMap(),
+ isDiagramLoading: false,
};
},
mixins: [EmitLinkMixin],
@@ -554,6 +573,17 @@ export default {
},
},
watch: {
+ '$store.state.filters': {
+ async handler(filters) {
+ await this.applyFilters(filters, this.$store.state.appMap, true);
+ },
+ deep: true,
+ },
+ '$store.state.appMap': {
+ handler(appMap) {
+ this.applyFilters(this.filters, appMap);
+ },
+ },
'$store.state.currentView': {
handler(view) {
this.$refs.tabs.activateTab(this.$refs[view]);
@@ -675,10 +705,6 @@ export default {
filters() {
return this.$store.state.filters;
},
- filteredAppMap() {
- const { appMap } = this.$store.state;
- return this.filters.filter(appMap, this.findings);
- },
viewState() {
return this.getStateObject();
},
@@ -884,6 +910,23 @@ export default {
},
},
methods: {
+ async applyFilters(filter, appMap, isAsync = false) {
+ if (isAsync) {
+ this.isDiagramLoading = true;
+ await new Promise((resolve) => {
+ setTimeout(() => {
+ this.filteredAppMap = filter.filter(appMap, this.findings);
+ this.isDiagramLoading = false;
+ resolve();
+ }, 0);
+ });
+ } else {
+ this.filteredAppMap = filter.filter(appMap, this.findings);
+ }
+ },
+ emptyFilteredAppMap() {
+ return new AppMapFilter().filter(new AppMap());
+ },
detailsPanelTransitionEnd() {
this.rightColumnWidth = this.$refs.mainColumnRight.offsetWidth;
},
@@ -1452,9 +1495,11 @@ export default {
if (this.isGiantAppMap) {
this.showStatsPanel = true;
this.setView(null);
+ } else if (this.showStatsPanel && this.currentView === null) {
+ this.showStatsPanel = false;
+ this.setView(this.defaultView);
}
},
-
beforeDestroy() {
browserPrefixes.forEach((prefix) => {
document.removeEventListener(prefix + 'fullscreenchange', this.checkFullscreen);
diff --git a/packages/components/tests/unit/VsCodeExtension.spec.js b/packages/components/tests/unit/VsCodeExtension.spec.js
index debb72c376..24887d1a4a 100644
--- a/packages/components/tests/unit/VsCodeExtension.spec.js
+++ b/packages/components/tests/unit/VsCodeExtension.spec.js
@@ -305,6 +305,11 @@ describe('VsCodeExtension.vue', () => {
await wrapper.find('[data-cy="export-button"]').trigger('click');
const exportJSON = wrapper.find('[data-cy="exportJSON"]');
expect(exportJSON.exists()).toBe(true);
+
+ // TODO: This is a hack to wait for the filters to be applied
+ // We should really fix this at some point
+ await new Promise((resolve) => setTimeout(resolve, 0));
+
await exportJSON.trigger('click');
const exportJSONEventParameters = rootWrapper.emitted()['exportJSON'];
diff --git a/packages/components/tsconfig.json b/packages/components/tsconfig.json
index 83d3278c7d..7a1b1cc736 100644
--- a/packages/components/tsconfig.json
+++ b/packages/components/tsconfig.json
@@ -13,7 +13,7 @@
"useDefineForClassFields": true,
"sourceMap": true,
"baseUrl": ".",
- "types": ["webpack-env", "jest"],
+ "types": ["webpack-env", "jest", "vue/types/vue"],
"paths": {
"@/*": ["src/*"]
},