diff --git a/package-lock.json b/package-lock.json index e22c869e5..157f3be5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,7 +35,7 @@ "ng-file-upload": "^12.2.13", "ng-tags-input": "^3.2.0", "oclazyload": "^1.1.0", - "ontotext-yasgui-web-component": "1.3.14", + "ontotext-yasgui-web-component": "1.3.15", "shepherd.js": "^11.2.0" }, "devDependencies": { @@ -9137,9 +9137,9 @@ } }, "node_modules/ontotext-yasgui-web-component": { - "version": "1.3.14", - "resolved": "https://registry.npmjs.org/ontotext-yasgui-web-component/-/ontotext-yasgui-web-component-1.3.14.tgz", - "integrity": "sha512-FTuIoKypwi1w2ogFobuQyU3F6kzaflM5HGZqJ2uNs6u26FKWIH0CdDDGlOGoro7/b4l6nrEBKH6FWcFte/lq5Q==", + "version": "1.3.15", + "resolved": "https://registry.npmjs.org/ontotext-yasgui-web-component/-/ontotext-yasgui-web-component-1.3.15.tgz", + "integrity": "sha512-8PKne4gJSKbZuewPq8WVKZTcjvPoVIhyNdGrNYGlfIpvnt/wUuuNgVJkFXsVRMJ6+fucAA+WSr5D/m5PdTUeVg==", "dependencies": { "@stencil/core": "^2.21.0", "tippy.js": "^6.3.7" @@ -22530,9 +22530,9 @@ } }, "ontotext-yasgui-web-component": { - "version": "1.3.14", - "resolved": "https://registry.npmjs.org/ontotext-yasgui-web-component/-/ontotext-yasgui-web-component-1.3.14.tgz", - "integrity": "sha512-FTuIoKypwi1w2ogFobuQyU3F6kzaflM5HGZqJ2uNs6u26FKWIH0CdDDGlOGoro7/b4l6nrEBKH6FWcFte/lq5Q==", + "version": "1.3.15", + "resolved": "https://registry.npmjs.org/ontotext-yasgui-web-component/-/ontotext-yasgui-web-component-1.3.15.tgz", + "integrity": "sha512-8PKne4gJSKbZuewPq8WVKZTcjvPoVIhyNdGrNYGlfIpvnt/wUuuNgVJkFXsVRMJ6+fucAA+WSr5D/m5PdTUeVg==", "requires": { "@stencil/core": "^2.21.0", "tippy.js": "^6.3.7" diff --git a/package.json b/package.json index 81e7b8c9f..cc467453d 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "ng-file-upload": "^12.2.13", "ng-tags-input": "^3.2.0", "oclazyload": "^1.1.0", - "ontotext-yasgui-web-component": "1.3.14", + "ontotext-yasgui-web-component": "1.3.15", "shepherd.js": "^11.2.0" }, "resolutions": { diff --git a/src/js/angular/models/ontotext-yasgui/ontotext-yasgui-config.js b/src/js/angular/models/ontotext-yasgui/ontotext-yasgui-config.js index fdc20ae4f..a70e0abae 100644 --- a/src/js/angular/models/ontotext-yasgui/ontotext-yasgui-config.js +++ b/src/js/angular/models/ontotext-yasgui/ontotext-yasgui-config.js @@ -153,6 +153,13 @@ export class OntotextYasguiConfig { */ this.immutableSameAs = undefined; + /** + * If the Yasgui state should be cleared to the initial state. Default value is false. + * + * @type {boolean} + */ + this.clearState = false; + /** * If the configured endpoint should be preconfigured to any new opened editor tab. * diff --git a/src/js/angular/sparql-editor/controllers.js b/src/js/angular/sparql-editor/controllers.js index 2dfe06395..5dc4bac51 100644 --- a/src/js/angular/sparql-editor/controllers.js +++ b/src/js/angular/sparql-editor/controllers.js @@ -15,13 +15,13 @@ import {VIEW_SPARQL_EDITOR} from "../models/sparql/constants"; import {CancelAbortingQuery} from "../models/sparql/cancel-aborting-query"; import {QueryMode} from "../models/ontotext-yasgui/query-mode"; import 'angular/core/services/event-emitter-service'; -import {YasguiResetFlags} from "../models/ontotext-yasgui/yasgui-reset-flags"; const modules = [ 'ui.bootstrap', 'graphdb.framework.rest.connectors.service', 'graphdb.framework.externalsync.controllers', - 'graphdb.framework.utils.event-emitter-service' + 'graphdb.framework.utils.event-emitter-service', + 'graphdb.framework.utils.localstorageadapter' ]; angular @@ -44,7 +44,9 @@ SparqlEditorCtrl.$inject = [ 'GuidesService', 'ModalService', 'MonitoringRestService', - 'EventEmitterService']; + 'EventEmitterService', + 'LocalStorageAdapter', + 'LSKeys']; function SparqlEditorCtrl($rootScope, $scope, @@ -61,13 +63,14 @@ function SparqlEditorCtrl($rootScope, GuidesService, ModalService, MonitoringRestService, - EventEmitterService) { + EventEmitterService, + LocalStorageAdapter, + LSKeys) { this.repository = ''; const QUERY_EDITOR_ID = '#query-editor'; - // When the view is loaded the repository change watcher will be triggered. We need to have this flag to prevent - // resetting the yasgui on the first load. This flag will be set to false after the first repository change. - let initialRepoInitialization = true; + let activeRepository = $repositories.getActiveRepository(); + let isOntopRepo = $repositories.isActiveRepoOntopType(); /** * @type {OntotextYasguiConfig} @@ -84,24 +87,29 @@ function SparqlEditorCtrl($rootScope, // ========================= // Public functions // ========================= - $scope.updateConfig = () => { + /** + * Updates the Yasgui configuration + * @param {boolean} clearYasguiState if set to true, the Yasgui will reinitialize and clear all tab results. Queries will remain. + */ + $scope.updateConfig = (clearYasguiState) => { $scope.yasguiConfig = { endpoint: getEndpoint, componentId: VIEW_SPARQL_EDITOR, prefixes: $scope.prefixes, - infer: $scope.inferUserSetting, - sameAs: $scope.sameAsUserSetting, + infer: isOntopRepo || $scope.inferUserSetting, + sameAs: isOntopRepo || $scope.sameAsUserSetting, yasrToolbarPlugins: [exploreVisualGraphYasrToolbarElementBuilder], beforeUpdateQuery: getBeforeUpdateQueryHandler(), outputHandlers: new Map([ [EventDataType.QUERY_EXECUTED, queryExecutedHandler], [EventDataType.REQUEST_ABORTED, requestAbortedHandler] - ]) + ]), + clearState: clearYasguiState !== undefined ? clearYasguiState : false }; }; $scope.getActiveRepositoryNoError = () => { - return $repositories.getActiveRepository(); + return activeRepository; }; // ========================= @@ -124,8 +132,13 @@ function SparqlEditorCtrl($rootScope, return $repositories.resolveSparqlEndpoint(yasqe.getQueryMode()); }; - const initViewFromUrlParams = () => { - $scope.updateConfig(); + /** + * Initializes the editor from the URL parameters. + * @param {boolean} clearYasguiState if set to true, the Yasgui will reinitialize and clear all tab results. Queries will remain. + * The default is false. + */ + const initViewFromUrlParams = (clearYasguiState = false) => { + $scope.updateConfig(clearYasguiState); const queryParams = $location.search(); if (queryParams.hasOwnProperty(RouteConstants.savedQueryName)) { // init new tab from shared saved query link @@ -409,7 +422,7 @@ function SparqlEditorCtrl($rootScope, }; // Initialization and bootstrap - const init = () => { + const init = (clearYasguiState) => { // This script check is required, because of the following scenario: // I am in the SPARQL view; // Then I go to a different view and change the language; @@ -430,12 +443,12 @@ function SparqlEditorCtrl($rootScope, return; } } - Promise.all([$jwtAuth.getPrincipal(), $repositories.getPrefixes($repositories.getActiveRepository())]) + Promise.all([$jwtAuth.getPrincipal(), $repositories.getPrefixes(activeRepository)]) .then(([principal, usedPrefixes]) => { $scope.prefixes = usedPrefixes; setInferAndSameAs(principal); // check is there is a saved query or query url parameter and init the editor - initViewFromUrlParams(); + initViewFromUrlParams(clearYasguiState); }); // TODO: we should also watch for changes in namespaces // scope.$watch('namespaces', function () {}); @@ -446,24 +459,17 @@ function SparqlEditorCtrl($rootScope, // ========================= const subscriptions = []; - const reInitYasgui = (flags) => { - YasguiComponentDirectiveUtil.getOntotextYasguiElementAsync(QUERY_EDITOR_ID) - .then((yasguiComponent) => { - return yasguiComponent.reInitYasgui(flags); - }) - .catch(() => { - console.error('Failed to reset yasr results'); - }); - }; - - const repositoryChangedHandler = (activeRepo) => { - if (activeRepo) { - if (!initialRepoInitialization) { - const flags = new YasguiResetFlags(true, true, true, true); - reInitYasgui(flags); - } - init(); - initialRepoInitialization = false; + const repositoryChangedHandler = (object) => { + if (!object) { + return; + } + activeRepository= $repositories.getActiveRepository(); + isOntopRepo = $repositories.isActiveRepoOntopType(object); + if (LocalStorageAdapter.get(LSKeys.SPARQL_LAST_REPO) !== activeRepository) { + init(true); + persistLasstUsedRepository(); + } else { + init(false); } }; @@ -538,6 +544,25 @@ function SparqlEditorCtrl($rootScope, window.removeEventListener('beforeunload', beforeunloadHandler); }; + const finalizeAndDestroy = () => { + persistLasstUsedRepository(); + removeAllListeners(); + }; + + const persistLasstUsedRepository = () => { + // The active repository is set when the controller is initialized and when the repository is changed. + // It holds the actual repository when the YASGUI is initialized. DON'T use runtime fetching of the actual repository here, because there is a scenario: + // 1. Open a tab with the SPARQL view open; + // 2. Open the SPARQL view in another tab and execute a query; + // 3. Switch to the repositories view and change the repository; + // 4. Switch back to the SPARQL view, and the YASR is not cleared. + // The problem occurs because of the second tab. When the repository is changed, its ID is persisted to local storage, which triggers the "storage" event to be fired. + // In the main controller, a listener has been registered to listen to that event and refresh the page outside of the Angular scope. + // Reloading the page triggers the destruction of the component and persistence of the active repository. The reloading of the page is out of the Angular scope, so the "activeRepository" + // holds the real repository when the YASGUI is created. If we use $$repositories.getActiveRepository(), the new value will be fetched, which in this case will be incorrect. + LocalStorageAdapter.set(LSKeys.SPARQL_LAST_REPO, activeRepository); + } + subscriptions.push( $scope.$on('language-changed', function () { location.reload(); @@ -561,7 +586,7 @@ function SparqlEditorCtrl($rootScope, )); // Deregister the watcher when the scope/directive is destroyed - $scope.$on('$destroy', removeAllListeners); + subscriptions.push($scope.$on('$destroy', finalizeAndDestroy)); // Wait until the active repository object is set, otherwise "canWriteActiveRepo()" may return a wrong result and the "ontotext-yasgui" // readOnly configuration may be incorrect. diff --git a/src/js/angular/utils/local-storage-adapter.js b/src/js/angular/utils/local-storage-adapter.js index 9865aa0a5..67d1167b0 100644 --- a/src/js/angular/utils/local-storage-adapter.js +++ b/src/js/angular/utils/local-storage-adapter.js @@ -27,7 +27,8 @@ angular 'REPOSITORY_ID': 'repository-id', 'REPOSITORY_LOCATION': 'repository-location', 'JSONLD_EXPORT_SETTINGS': 'jsonld-export-settings', - 'IMPORT_VIEW': 'import-view' + 'IMPORT_VIEW': 'import-view', + 'SPARQL_LAST_REPO': 'sparql-last-repo' }); LocalStorageAdapter.$inject = ['localStorageService', 'LSKeys']; diff --git a/test-cypress/integration/sparql-editor/actions/expand-results-over-sameas.spec.js b/test-cypress/integration/sparql-editor/actions/expand-results-over-sameas.spec.js index 1b4ea17de..e53cb649d 100644 --- a/test-cypress/integration/sparql-editor/actions/expand-results-over-sameas.spec.js +++ b/test-cypress/integration/sparql-editor/actions/expand-results-over-sameas.spec.js @@ -71,7 +71,7 @@ describe('Expand results over owl:sameAs', () => { YasqeSteps.getActionButtonTooltip(4).should('have.attr', 'data-tooltip', 'Expand results over owl:sameAs: ON'); }); - it('should not be enabled when infer is true and sameAs is false in user settings', () => { + it('should not be enabled when infer is true and sameAs is false in user settings', {retries: {runMode: 2}},() => { QueryStubs.stubInferAndSameAsDefaults(true, false); // When I visit a page with "ontotext-yasgui-web-component" in it.