diff --git a/app/services/PageService.scala b/app/services/PageService.scala index 3c5cfb036..9b89ea0a9 100644 --- a/app/services/PageService.scala +++ b/app/services/PageService.scala @@ -277,7 +277,7 @@ class PageService @Inject()(config: Configuration, projectRepository: ProjectRep private def insertOrUpdateIndex(pageJoinProject: PageJoinProject) = { - hierarchyService.getHierarchyPath(pageJoinProject).map{ hierarchy => + hierarchyService.getHierarchyPath(pageJoinProject).map { hierarchy => val document = PageIndexDocument(id = hierarchy + "/" + pageJoinProject.page.path, hierarchy = hierarchy, path = pageJoinProject.page.path, diff --git a/app/services/ProjectService.scala b/app/services/ProjectService.scala index 05ff2a73d..f954bc6ef 100644 --- a/app/services/ProjectService.scala +++ b/app/services/ProjectService.scala @@ -17,7 +17,7 @@ import scala.concurrent.duration._ @Singleton class ProjectService @Inject()(projectRepository: ProjectRepository, gitService: GitService, featureService: FeatureService, featureRepository: FeatureRepository, branchRepository: BranchRepository, directoryRepository: DirectoryRepository, - pageRepository: PageRepository, menuService: MenuService, pageService: PageService, + pageRepository: PageRepository, menuService: MenuService, pageService: PageService, indexService: IndexService, config: Configuration, environment: Environment, actorSystem: ActorSystem)(implicit ec: ExecutionContext) extends Logging { val projectsRootDirectory = config.get[String]("projects.root.directory") val synchronizeInterval = config.get[Int]("projects.synchronize.interval") @@ -288,6 +288,7 @@ class ProjectService @Inject()(projectRepository: ProjectRepository, gitService: def refreshAllPagesFromAllProjects(): Unit = { val startTime = System.currentTimeMillis() logger.info("Start refreshing pages not in cache") + indexService.reset() projectRepository.findAll().foreach(p => refreshAllPages(p, forceRefresh = false)) val endTime = System.currentTimeMillis() val duration = DurationUtil.durationFromMillisToHumanReadable( endTime-startTime ) diff --git a/app/services/SearchService.scala b/app/services/SearchService.scala index d0fa535cb..d453a4e95 100644 --- a/app/services/SearchService.scala +++ b/app/services/SearchService.scala @@ -33,7 +33,7 @@ object SearchResult { @Singleton class IndexService { - val luceneSearchIndex = new DirectLucene(uniqueFields = List("id"), defaultFullTextSearchable = true, appendIfExists = false, autoCommit = true) + val luceneSearchIndex = new DirectLucene(uniqueFields = List("id"), defaultFullTextSearchable = true, appendIfExists = false, autoCommit = false) private val id = luceneSearchIndex.create.field[String]("id") private val hierarchy = luceneSearchIndex.create.field[String]("hierarchy") @@ -65,6 +65,7 @@ class IndexService { pageContent(document.pageContent) ).index() luceneSearchIndex.commit() + () } private def exists(document: PageIndexDocument) = { diff --git a/frontend/package-lock.json b/frontend/package-lock.json index ae9a1bc13..ba5c9b42c 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -5556,12 +5556,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -5580,6 +5582,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } diff --git a/frontend/src/app/_components/page/header/header.component.ts b/frontend/src/app/_components/page/header/header.component.ts index b79f3335f..23729e478 100644 --- a/frontend/src/app/_components/page/header/header.component.ts +++ b/frontend/src/app/_components/page/header/header.component.ts @@ -45,18 +45,18 @@ export class HeaderComponent implements OnInit { }); } - getCurrentRoute(): NavigationRoute{ - let params : NavigationParams; - if (this.activatedRoute.firstChild && this.activatedRoute.firstChild.snapshot){ + getCurrentRoute(): NavigationRoute { + let params: NavigationParams; + if (this.activatedRoute.firstChild && this.activatedRoute.firstChild.snapshot) { params = this.activatedRoute.firstChild.snapshot.params; - if (this.activatedRoute.firstChild.snapshot.url){ - this.url = this.activatedRoute.firstChild.snapshot.url.join('/'); + if (this.activatedRoute.firstChild.snapshot.url) { + this.url = this.activatedRoute.firstChild.snapshot.url.join('/'); } } - if (!params && this.activatedRoute && this.activatedRoute.snapshot){ + if (!params && this.activatedRoute && this.activatedRoute.snapshot) { params = this.activatedRoute.snapshot.params; - if (this.activatedRoute.firstChild.snapshot.url){ - this.url = this.activatedRoute.firstChild.snapshot.url.join('/'); + if (this.activatedRoute.snapshot.url) { + this.url = this.activatedRoute.snapshot.url.join('/'); } } return this.routeService.navigationParamsToNavigationRoute(params); diff --git a/frontend/src/app/_services/route.service.spec.ts b/frontend/src/app/_services/route.service.spec.ts index 1f723b50f..1e4eb42d7 100644 --- a/frontend/src/app/_services/route.service.spec.ts +++ b/frontend/src/app/_services/route.service.spec.ts @@ -159,10 +159,12 @@ describe('RouteService', () => { }); it('relativeUrlToFullFrontEndUrl ', () => { - + expect(service.relativeUrlToFullFrontEndUrl('Public/Features/OfferFeeds/Feature',{nodes: '_publisher_systems_services_shopping',project: 'shoppingAPI',branch: 'qa',directories: '_',page: 'Why'} )) + .toEqual("app/documentation/navigate/_publisher_systems_services_shopping/shoppingAPI/qa/_Public_Features_OfferFeeds/Feature"); + expect(service.relativeUrlToFullFrontEndUrl('../../Guides/Feeds/UseCases',{nodes: '_publisher_systems_services_shopping',project: 'shoppingAPI',branch: 'qa',directories: '_Public_Features_OfferFeeds',page: 'Feature'} )) + .toEqual("app/documentation/navigate/_publisher_systems_services_shopping/shoppingAPI/qa/_Public_Guides_Feeds/UseCases"); expect(service.relativeUrlToFullFrontEndUrl('../OfferSearch/Feature',{nodes: '_platform_publisher_systems_public',project: 'shoppingAPIPublic',branch: 'feature_PUB-4629-review-doc',directories: '_Features_OfferFeeds',page: 'Feature'} )) .toEqual("app/documentation/navigate/_platform_publisher_systems_public/shoppingAPIPublic/feature_PUB-4629-review-doc/_Features_OfferSearch/Feature"); - expect(service.relativeUrlToFullFrontEndUrl('https://thegardener.kelkoogroup.com',{nodes: 'Tools',project: 'theGardener',branch: 'master',directories: '_Guide_Write',page: 'Basics'} )) .toEqual("https://thegardener.kelkoogroup.com"); expect(service.relativeUrlToFullFrontEndUrl('OpenApi',{nodes: 'Tools',project: 'theGardener',branch: 'master',directories: '_Guide_Write',page: 'Basics'} )) @@ -198,7 +200,6 @@ describe('RouteService', () => { expect(service.directoryPathSimilar(navigationRoute, { nodes: ["publisher"], project: "ecs", branch: "master", directories: [] as Array, page: "Meta" })).toBeTrue(); }); - it('pagePathSimilar ', () => { const navigationRoute = { nodes: ["publisher"], project: "ecs", branch: "_", directories: [] as Array, page: "Meta" }; @@ -218,4 +219,10 @@ describe('RouteService', () => { expect(service.urlToRelativePath('_features_foo_bar')).toEqual('/features/foo/bar'); expect(service.urlToRelativePath('_features_foo.foo_bar')).toEqual('/features/foo_foo/bar'); }); + + it('extractKeyword ', () => { + expect(service.extractKeyword({ nodes: ["publisher","services","shopping"], project: "shoppingAPI", branch: "_", directories: ["Public","Guides"], page: "AuthenticationWithSignedUrlGuide" })) + .toEqual('publisher services shopping shopping A P I Authentication With Signed Url Guide'); + }); + }); diff --git a/frontend/src/app/_services/route.service.ts b/frontend/src/app/_services/route.service.ts index 7424d0930..4477117a8 100644 --- a/frontend/src/app/_services/route.service.ts +++ b/frontend/src/app/_services/route.service.ts @@ -107,7 +107,8 @@ export class RouteService { } else { directoryNavigationForward = directoriesAndPageArray.join(EMPTY_CHAR); } - targetDirectoriesPath += directoryNavigationForward; + targetDirectoriesPath += EMPTY_CHAR + directoryNavigationForward; + targetDirectoriesPath = targetDirectoriesPath.replace('__','_') } @@ -125,6 +126,7 @@ export class RouteService { } else { const subDirectories = subDirectoriesAndPage.slice(0, subDirectoriesAndPage.length - 1); targetDirectoriesPath = navigationParams.directories + EMPTY_CHAR + subDirectories.join(EMPTY_CHAR); + targetDirectoriesPath = targetDirectoriesPath.replace('__','_') } return `${NAVIGATE_PATH}${navigationParams.nodes}/${navigationParams.project}/${navigationParams.branch}/${targetDirectoriesPath}/${page}`; } @@ -328,4 +330,9 @@ export class RouteService { } return hierarchyFrontEndPath + '/' + navigationRoute.project + '/' + navigationRoute.branch + '/' + directories + '/' + navigationRoute.page; } + + extractKeyword(targetedRoute: NavigationRoute) { + const join = targetedRoute.nodes.join(" ")+ " " + targetedRoute.project+ " " + targetedRoute.page; + return join.replace(/([a-zA-Z])(?=[A-Z])/g, '$1 '); + } } diff --git a/frontend/src/app/output/page-content/page-content.component.ts b/frontend/src/app/output/page-content/page-content.component.ts index 05465f0b8..994fee376 100644 --- a/frontend/src/app/output/page-content/page-content.component.ts +++ b/frontend/src/app/output/page-content/page-content.component.ts @@ -12,8 +12,8 @@ import { PagePart, ScenarioPart } from '../../_models/page'; -import {NotificationService} from '../../_services/notification.service'; -import {RouteService} from "../../_services/route.service"; +import {RouteService, SEARCH_PATH} from "../../_services/route.service"; +import {NavigationRoute} from "../../_models/route"; @Component({ @@ -28,11 +28,11 @@ export class PageContentComponent implements OnInit, OnDestroy, AfterViewChecked private routerSubscription: Subscription; private fragment: string; private canScroll: boolean = true; + private targetedRoute: NavigationRoute; constructor(private activatedRoute: ActivatedRoute, private pageService: PageService, private routeService: RouteService, - private notificationService: NotificationService, private router: Router, private ngZone: NgZone) { } @@ -62,16 +62,17 @@ export class PageContentComponent implements OnInit, OnDestroy, AfterViewChecked return params; }), switchMap(params => { - const navigationRoute = this.routeService.navigationParamsToNavigationRoute(params); - if ( navigationRoute.page == undefined ){ + this.targetedRoute = this.routeService.navigationParamsToNavigationRoute(params); + if ( this.targetedRoute.page == undefined ){ return of(); }else{ - const backEndPath = this.routeService.navigationRouteToBackEndPath(navigationRoute); + const backEndPath = this.routeService.navigationRouteToBackEndPath(this.targetedRoute); return this.pageService.getPage(backEndPath.pathFromProject); } }), catchError(err => { - this.notificationService.showError(`Error while loading page`, err); + const keyword = this.routeService.extractKeyword(this.targetedRoute); + this.router.navigateByUrl(SEARCH_PATH + `?keyword=${keyword.trim()}`); return of(); }) ).subscribe(page => { diff --git a/local-conf/application.conf b/local-conf/application.conf index 4b1c135b4..4db021e44 100644 --- a/local-conf/application.conf +++ b/local-conf/application.conf @@ -78,7 +78,7 @@ play.evolutions.autoApply = true # db.default.jndiName=DefaultDS projects.root.directory = "target/data/git/" -projects.synchronize.interval = 1800 +projects.synchronize.interval = 600 projects.synchronize.initial.delay = 5 projects.synchronize.from.remote.enabled = true diff --git a/test/services/ProjectServiceTest.scala b/test/services/ProjectServiceTest.scala index b11f2d968..e0967396b 100644 --- a/test/services/ProjectServiceTest.scala +++ b/test/services/ProjectServiceTest.scala @@ -38,10 +38,11 @@ class ProjectServiceTest extends WordSpec with MustMatchers with BeforeAndAfter val featureService = mock[FeatureService] val menuService = mock[MenuService] val pageService = mock[PageService] + val indexService = mock[IndexService] val environment = mock[Environment] - val projectService = new ProjectService(projectRepository, gitService, featureService, featureRepository, branchRepository, directoryRepository, pageRepository, menuService, pageService, Configuration.load(Environment.simple()), environment, ActorSystem()) + val projectService = new ProjectService(projectRepository, gitService, featureService, featureRepository, branchRepository, directoryRepository, pageRepository, menuService, pageService, indexService, Configuration.load(Environment.simple()), environment, ActorSystem()) val project = Project("suggestionsWS", "Suggestions WebServices", "git@github.com:library/suggestionsWS.git", Some("http://github.com:library/suggestionsWS/blob/${branch}/${path}"), "master", Some("^(^master$)|(^feature\\/.*$)"), Some("test/features")) val masterDirectory = projectService.getLocalRepository(project.id, project.stableBranch) diff --git a/test/steps/CommonSteps.scala b/test/steps/CommonSteps.scala index 03c5405e2..8a2c05ab3 100644 --- a/test/steps/CommonSteps.scala +++ b/test/steps/CommonSteps.scala @@ -113,7 +113,7 @@ object CommonSteps extends MockitoSugar with MustMatchers { val spyMenuService = spy(menuService) val replicaService = new ReplicaClient(conf, wsClient) val spyReplicaService = spy(replicaService) - val projectService = new ProjectService(projectRepository, gitService, featureService, featureRepository, branchRepository, directoryRepository, pageRepository, menuService, pageService, conf, environment, actorSystem) + val projectService = new ProjectService(projectRepository, gitService, featureService, featureRepository, branchRepository, directoryRepository, pageRepository, menuService, pageService, pageIndex, conf, environment, actorSystem) val spyProjectService = spy(projectService)