Skip to content
This repository has been archived by the owner on Oct 20, 2021. It is now read-only.

Commit

Permalink
feat(tree): fetch pages recursively
Browse files Browse the repository at this point in the history
  • Loading branch information
NicolasGeraud committed Feb 24, 2019
1 parent 50ea820 commit d239d11
Show file tree
Hide file tree
Showing 11 changed files with 360 additions and 7 deletions.
25 changes: 25 additions & 0 deletions docs/management-api-documentation.md
Expand Up @@ -15,3 +15,28 @@ You can set a page to be a *homepage* by clicking on the *house* button. API hom
You can also configure a page by clicking on the *settings* button. Page's configuration let you fetch page's content from an external resource such as Git repositories, or HTTP urls.

(+) button let you create a new documentation page.

Another possibility is to add a whole directory. Click on the wheel at the top of the screen and import a directory.
If this directory contains a gravitee descriptor (a file named `.gravitee.json`) we will add the content according to the descriptor.

Here is a descriptor sample :
```json
{
"version": 1,
"documentation": {
"pages": [
{
"src": "/docs/readme.md",
"dest": "/my/new/dir/",
"name": "Homepage",
"homepage": true
},
{
"src": "/docs/doc2.md",
"dest": "/my/new/dir/",
"name": "Business"
}
]
}
}
```
25 changes: 25 additions & 0 deletions docs/management-configuration-portal-pages.md
Expand Up @@ -14,3 +14,28 @@ You can set a page to be a *homepage* by clicking on the *house* button. Portal
You can also configure a page by clicking on the *settings* button. Page's configuration let you fetch page's content from an external resource such as Git repositories, or HTTP urls.

(+) button let you create a new documentation page.

Another possibility is to add a whole directory. Click on the wheel at the top of the screen and import a directory.
If this directory contains a gravitee descriptor (a file named `.gravitee.json`) we will add the content according to the descriptor.

Here is a descriptor sample :
```json
{
"version": 1,
"documentation": {
"pages": [
{
"src": "/docs/readme.md",
"dest": "/my/new/dir/",
"name": "Homepage",
"homepage": true
},
{
"src": "/docs/doc2.md",
"dest": "/my/new/dir/",
"name": "Business"
}
]
}
}
```
32 changes: 32 additions & 0 deletions src/management/api/portal/apis.portal.route.ts
Expand Up @@ -283,6 +283,9 @@ function apisPortalRouterConfig($stateProvider) {
},
data: {
menu: null,
docs: {
page: 'management-api-documentation'
},
perms: {
only: ['api-documentation-c']
}
Expand All @@ -300,6 +303,32 @@ function apisPortalRouterConfig($stateProvider) {
}
}
})
.state('management.apis.detail.portal.importdocumentation', {
url: '/documentation/import',
component: 'importPages',
resolve: {
resolvedFetchers: (FetcherService: FetcherService) => {
return FetcherService.list().then(response => {
return response.data;
})
},
resolvedRootPage: (DocumentationService: DocumentationService, $stateParams: StateParams) => {
const q = new DocumentationQuery();
q.type = "ROOT";
return DocumentationService.search(q, $stateParams.apiId)
.then(response => response.data && response.data.length > 0 ? response.data[0] : null);
}
},
data: {
menu: null,
docs: {
page: 'management-api-documentation'
},
perms: {
only: ['api-documentation-c']
}
}
})
.state('management.apis.detail.portal.editdocumentation', {
url: '/documentation/:pageId',
component: 'editPage',
Expand All @@ -319,6 +348,9 @@ function apisPortalRouterConfig($stateProvider) {
},
data: {
menu: null,
docs: {
page: 'management-api-documentation'
},
perms: {
only: ['api-documentation-u']
}
Expand Down
Expand Up @@ -41,13 +41,20 @@ const DocumentationManagementComponent: ng.IComponentOptions = {
this.apiId = $state.params.apiId;

this.$onInit = () => {
// remove the ROOT page
this.pages = this.filterROOTPages(this.pages);

this.rootDir = $state.params.parent;
this.supportedTypes = DocumentationService.supportedTypes();
this.foldersById = _.keyBy(this.folders, 'id');
this.breadcrumb = this.generateBreadcrumb();
$scope.renameFolder = false;
};

this.filterROOTPages = (pagesToFilter: any[]) => {
return _.filter(pagesToFilter, (p) => p.type !== 'ROOT');
};

this.toggleRenameFolder = () => {
$scope.renameFolder = !$scope.renameFolder;
if ($scope.renameFolder) {
Expand Down Expand Up @@ -150,7 +157,7 @@ const DocumentationManagementComponent: ng.IComponentOptions = {
} else {
q.root = true;
}
DocumentationService.search(q, this.apiId).then( (response) => this.pages = response.data);
DocumentationService.search(q, this.apiId).then((response) => this.pages = this.filterROOTPages(response.data));
};

this.togglePublish = (page: any) => {
Expand Down Expand Up @@ -220,6 +227,14 @@ const DocumentationManagementComponent: ng.IComponentOptions = {
}
}
};

this.importPages = () => {
if (this.apiId) {
$state.go('management.apis.detail.portal.importdocumentation', {apiId: this.apiId});
} else {
$state.go('management.settings.importdocumentation');
}
};
}
};

Expand Down
Expand Up @@ -16,7 +16,13 @@
-->
<div class="gv-forms gv-forms-fluid" layout="column">
<h1>Documentation</h1>
<div class="gv-forms-header">
<h1>Documentation</h1>
<a permission permission-only="['portal-documentation-c', 'api-documentation-c']"
ng-click="$ctrl.importPages()">
Import multiple files
</a>
</div>
<div class="gv-form">
<div layout="row" layout-align="space-between center" ng-if="!renameFolder">
<h2>
Expand Down
2 changes: 1 addition & 1 deletion src/management/components/documentation/edit-page.html
Expand Up @@ -117,7 +117,7 @@ <h3>General</h3>
aria-label="Published"
class="md-align-top-left"
flex>
Published this page
Publish this page
</md-checkbox>
</md-input-container>
<!-- SWAGGER Configuration -->
Expand Down
124 changes: 124 additions & 0 deletions src/management/components/documentation/import-pages.component.ts
@@ -0,0 +1,124 @@
/*
* Copyright (C) 2015 The Gravitee team (http://gravitee.io)
*
* Licensed 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.
*/

import NotificationService from "../../../services/notification.service";
import DocumentationService from "../../../services/documentation.service";
import {StateService} from "@uirouter/core";
import {IScope} from "angular";
import _ = require('lodash');

interface IPageScope extends IScope {
fetcherJsonSchema: string;
}
const ImportPagesComponent: ng.IComponentOptions = {
bindings: {
resolvedFetchers: '<',
resolvedRootPage: '<'
},
template: require('./import-pages.html'),
controller: function (
NotificationService: NotificationService,
DocumentationService: DocumentationService,
$state: StateService,
$scope: IPageScope
) {
'ngInject';
this.apiId = $state.params.apiId;

this.codeMirrorOptions = {
lineWrapping: true,
lineNumbers: true,
allowDropFileTypes: true,
autoCloseTags: true,
mode: "javascript"
};

this.$onInit = () => {

this.page = this.resolvedRootPage || {
name: "root",
type: "ROOT"
};

this.fetchers = this.resolvedFetchers;

this.emptyFetcher = {
"type": "object",
"id": "empty",
"properties": {"" : {}}
};
$scope.fetcherJsonSchema = this.emptyFetcher;
this.fetcherJsonSchemaForm = ["*"];

if(!(_.isNil(this.page.source) || _.isNil(this.page.source.type))) {
_.forEach(this.fetchers, fetcher => {
if (fetcher.id === this.page.source.type) {
$scope.fetcherJsonSchema = JSON.parse(fetcher.schema);
}
});
}
};

this.configureFetcher = (fetcher) => {
if (! this.page.source) {
this.page.source = {};
}

this.page.source = {
type: fetcher.id,
configuration: {}
};
$scope.fetcherJsonSchema = JSON.parse(fetcher.schema);
};

this.import = () => {
this.page.name="import";
DocumentationService.import(this.page, this.apiId)
.then( (response: any) => {
if (this.page.id) {
NotificationService.show("'" + response.data.length + "' elements has been updated.");
} else {
NotificationService.show("'" + response.data.length + "' elements has been created.");
}
if (this.apiId) {
$state.go("management.apis.detail.portal.documentation", {apiId: this.apiId});
} else {
$state.go("management.settings.documentation");
}
});
};

this.changeContentMode = (newMode) => {
if ("fetcher" === newMode) {
this.page.source = {
configuration: {}
};
} else {
delete this.page.source;
}
};

this.cancel = () => {
if (this.apiId) {
$state.go("management.apis.detail.portal.documentation", {apiId: this.apiId});
} else {
$state.go("management.settings.documentation");
}
};
}
};

export default ImportPagesComponent;
72 changes: 72 additions & 0 deletions src/management/components/documentation/import-pages.html
@@ -0,0 +1,72 @@
<!--
Copyright (C) 2015 The Gravitee team (http://gravitee.io)
Licensed 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.
-->
<div class="gv-forms gv-forms" layout="column">
<div class="gv-forms-header">
<h1>Import Files</h1>
<a ng-click="$ctrl.cancel()">Back to Documentation</a>
</div>
<div class="gv-form">
<h2></h2>
<div class="gv-form-content" layout="column">

<div class="gv-page-draft-banner">
<ng-md-icon icon="warning" style="fill: #ce4844"></ng-md-icon>
All files (with a supported page type) will be imported, generating one request by file to import.<br>
If you use an external source with rate limiting, you can reach your maximum requests authorized.
</div>

<blockquote>
<p style="font-size: 12px">
<ng-md-icon icon="info" style="fill:grey;"></ng-md-icon>
You can import a whole directory (only available in few sources), or import a Gravitee.io descriptor (refer to the documentation).
If the filepath is not filled, the root directory will be imported.
</p>
</blockquote>

<div style="display: inline-block;">
<md-input-container class="md-block">
<md-checkbox ng-model="$ctrl.page.published"
aria-label="Published"
class="md-align-top-left"
flex>
Publish all imported pages
</md-checkbox>
</md-input-container>

<h3>Select your source:</h3>
<div layout="row">
<md-button ng-repeat="fetcher in $ctrl.fetchers"
ng-click="$ctrl.configureFetcher(fetcher)"
ng-class="{'md-raised': fetcher.id === $ctrl.page.source.type}"
aria-label="fetcher">
<md-icon md-svg-icon="assets/logo_{{fetcher.id | lowercase}}.svg" style="width:80px;height:40px"></md-icon>
</md-button>
</div>
<div layout="column">
<form name="PageConfigFetcherForm" sf-schema="fetcherJsonSchema" sf-form="$ctrl.fetcherJsonSchemaForm" sf-model="$ctrl.page.source.configuration"></form>
</div>
</div>

<div class="md-actions gravitee-api-save-button" layout="row" style="padding-top: 32px;">
<md-button class="md-raised md-primary" type="submit" ng-click="$ctrl.import()" ng-disabled="!$ctrl.page.source.type">
Import
</md-button>
</div>
</div>
</div>
</div>

0 comments on commit d239d11

Please sign in to comment.