├── client ├── src │ ├── assets │ │ ├── .gitkeep │ │ ├── img │ │ │ └── doc.png │ │ ├── background.jpg │ │ ├── icons │ │ │ ├── favicon.ico │ │ │ ├── favicon.png │ │ │ ├── electron.bmp │ │ │ ├── favicon.icns │ │ │ ├── favicon.256x256.png │ │ │ └── favicon.512x512.png │ │ └── svg │ │ │ ├── add.svg │ │ │ ├── closeNav.svg │ │ │ ├── doc.svg │ │ │ ├── comment.svg │ │ │ ├── save_api_as.svg │ │ │ ├── copyI.svg │ │ │ ├── editApi.svg │ │ │ ├── api_link.svg │ │ │ └── searchI.svg │ ├── app │ │ ├── home │ │ │ ├── diff │ │ │ │ ├── diff.component.scss │ │ │ │ ├── diff.component.spec.ts │ │ │ │ ├── diff.component.html │ │ │ │ └── diff.component.ts │ │ │ ├── doc-page │ │ │ │ ├── doc-page.component.scss │ │ │ │ ├── doc-page.component.html │ │ │ │ ├── doc-dash-board │ │ │ │ │ ├── doc-create-dialog │ │ │ │ │ │ ├── doc-create-dialog.component.scss │ │ │ │ │ │ ├── doc-create-dialog.component.html │ │ │ │ │ │ ├── doc-create-dialog.component.ts │ │ │ │ │ │ └── doc-create-dialog.component.spec.ts │ │ │ │ │ ├── doc-dash-board.component.spec.ts │ │ │ │ │ └── doc-dash-board.component.html │ │ │ │ ├── doc-page.component.ts │ │ │ │ ├── doc-page.component.spec.ts │ │ │ │ ├── doc-detail │ │ │ │ │ ├── doc-detail.component.spec.ts │ │ │ │ │ ├── doc-menu-tree │ │ │ │ │ │ ├── doc-menu-tree.component.spec.ts │ │ │ │ │ │ └── doc-menu-tree.component.scss │ │ │ │ │ └── doc-detail.component.ts │ │ │ │ └── doc-editor │ │ │ │ │ ├── doc-editor.component.spec.ts │ │ │ │ │ └── doc-editor.component.html │ │ │ ├── home │ │ │ │ ├── home.component.scss │ │ │ │ ├── home.component.html │ │ │ │ ├── home.component.ts │ │ │ │ └── home.component.spec.ts │ │ │ ├── mock-page │ │ │ │ ├── mock-page.component.html │ │ │ │ ├── mock-page.component.scss │ │ │ │ ├── mock-page.component.spec.ts │ │ │ │ └── mock-page.component.ts │ │ │ ├── setting │ │ │ │ ├── setting.component.scss │ │ │ │ └── setting.component.spec.ts │ │ │ └── api-test │ │ │ │ ├── api-test.component.html │ │ │ │ ├── api-test.component.spec.ts │ │ │ │ ├── api-test.component.scss │ │ │ │ └── api-test.component.ts │ │ ├── app.component.scss │ │ ├── detail │ │ │ ├── detail.component.scss │ │ │ ├── detail.component.html │ │ │ ├── detail.module.ts │ │ │ ├── detail-routing.module.ts │ │ │ ├── detail.component.ts │ │ │ └── detail.component.spec.ts │ │ ├── app.component.html │ │ ├── shared │ │ │ ├── components │ │ │ │ ├── page-not-found │ │ │ │ │ ├── page-not-found.component.scss │ │ │ │ │ ├── page-not-found.component.html │ │ │ │ │ ├── page-not-found.component.ts │ │ │ │ │ └── page-not-found.component.spec.ts │ │ │ │ ├── api │ │ │ │ │ ├── work-bench │ │ │ │ │ │ ├── http-work-bench │ │ │ │ │ │ │ ├── request-tabs │ │ │ │ │ │ │ │ ├── form-editor │ │ │ │ │ │ │ │ │ ├── form-editor.component.scss │ │ │ │ │ │ │ │ │ ├── form-editor.component.spec.ts │ │ │ │ │ │ │ │ │ └── form-editor.component.html │ │ │ │ │ │ │ │ ├── query-table │ │ │ │ │ │ │ │ │ ├── query-table.component.scss │ │ │ │ │ │ │ │ │ ├── query-table.component.spec.ts │ │ │ │ │ │ │ │ │ └── query-table.component.html │ │ │ │ │ │ │ │ ├── inner │ │ │ │ │ │ │ │ │ ├── check-box-cell │ │ │ │ │ │ │ │ │ │ ├── check-box-cell.component.scss │ │ │ │ │ │ │ │ │ │ ├── check-box-cell.component.html │ │ │ │ │ │ │ │ │ │ ├── check-box-cell.component.spec.ts │ │ │ │ │ │ │ │ │ │ └── check-box-cell.component.ts │ │ │ │ │ │ │ │ │ ├── check-box-cell-editor │ │ │ │ │ │ │ │ │ │ ├── check-box-cell-editor.component.scss │ │ │ │ │ │ │ │ │ │ ├── check-box-cell-editor.component.html │ │ │ │ │ │ │ │ │ │ ├── check-box-cell-editor.component.spec.ts │ │ │ │ │ │ │ │ │ │ └── check-box-cell-editor.component.ts │ │ │ │ │ │ │ │ │ ├── cell-content │ │ │ │ │ │ │ │ │ │ ├── cell-content.component.scss │ │ │ │ │ │ │ │ │ │ ├── cell-content.component.html │ │ │ │ │ │ │ │ │ │ └── cell-content.component.spec.ts │ │ │ │ │ │ │ │ │ ├── cell-file │ │ │ │ │ │ │ │ │ │ ├── cell-file.component.html │ │ │ │ │ │ │ │ │ │ ├── cell-file.component.spec.ts │ │ │ │ │ │ │ │ │ │ └── cell-file.component.scss │ │ │ │ │ │ │ │ │ ├── close-input-cell │ │ │ │ │ │ │ │ │ │ ├── close-input-cell.component.html │ │ │ │ │ │ │ │ │ │ ├── close-input-cell.component.scss │ │ │ │ │ │ │ │ │ │ └── close-input-cell.component.spec.ts │ │ │ │ │ │ │ │ │ └── cell-file-text │ │ │ │ │ │ │ │ │ │ ├── cell-file-text.component.html │ │ │ │ │ │ │ │ │ │ ├── cell-file-text.component.spec.ts │ │ │ │ │ │ │ │ │ │ └── cell-file-text.component.scss │ │ │ │ │ │ │ │ ├── text-body │ │ │ │ │ │ │ │ │ ├── text-body.component.scss │ │ │ │ │ │ │ │ │ ├── text-body.component.html │ │ │ │ │ │ │ │ │ └── text-body.component.spec.ts │ │ │ │ │ │ │ │ ├── none-body │ │ │ │ │ │ │ │ │ ├── none-body.component.scss │ │ │ │ │ │ │ │ │ ├── none-body.component.html │ │ │ │ │ │ │ │ │ ├── none-body.component.ts │ │ │ │ │ │ │ │ │ └── none-body.component.spec.ts │ │ │ │ │ │ │ │ ├── graph-ql │ │ │ │ │ │ │ │ │ ├── graph-ql.component.scss │ │ │ │ │ │ │ │ │ ├── graph-ql.component.spec.ts │ │ │ │ │ │ │ │ │ └── graph-ql.component.html │ │ │ │ │ │ │ │ ├── request-tabs.component.spec.ts │ │ │ │ │ │ │ │ ├── body-container │ │ │ │ │ │ │ │ │ └── body-container.component.spec.ts │ │ │ │ │ │ │ │ └── request-tabs.component.scss │ │ │ │ │ │ │ ├── response-tabs │ │ │ │ │ │ │ │ ├── response-cookies │ │ │ │ │ │ │ │ │ ├── response-cookies.component.scss │ │ │ │ │ │ │ │ │ ├── response-cookies.component.html │ │ │ │ │ │ │ │ │ ├── response-cookies.component.ts │ │ │ │ │ │ │ │ │ └── response-cookies.component.spec.ts │ │ │ │ │ │ │ │ ├── response-headers │ │ │ │ │ │ │ │ │ ├── response-headers.component.scss │ │ │ │ │ │ │ │ │ ├── response-headers.component.html │ │ │ │ │ │ │ │ │ ├── response-headers.component.ts │ │ │ │ │ │ │ │ │ └── response-headers.component.spec.ts │ │ │ │ │ │ │ │ ├── response-key-value │ │ │ │ │ │ │ │ │ ├── response-key-value.component.scss │ │ │ │ │ │ │ │ │ ├── response-key-value.component.html │ │ │ │ │ │ │ │ │ ├── response-key-value.component.ts │ │ │ │ │ │ │ │ │ └── response-key-value.component.spec.ts │ │ │ │ │ │ │ │ ├── empty-response │ │ │ │ │ │ │ │ │ ├── empty-response.component.html │ │ │ │ │ │ │ │ │ ├── empty-response.component.ts │ │ │ │ │ │ │ │ │ ├── empty-response.component.spec.ts │ │ │ │ │ │ │ │ │ └── empty-response.component.scss │ │ │ │ │ │ │ │ ├── body-text │ │ │ │ │ │ │ │ │ ├── body-html │ │ │ │ │ │ │ │ │ │ ├── body-html.component.html │ │ │ │ │ │ │ │ │ │ ├── body-html.component.scss │ │ │ │ │ │ │ │ │ │ ├── body-html.component.ts │ │ │ │ │ │ │ │ │ │ └── body-html.component.spec.ts │ │ │ │ │ │ │ │ │ └── body-text.component.spec.ts │ │ │ │ │ │ │ │ └── response-tabs.component.spec.ts │ │ │ │ │ │ │ ├── json-table-editor │ │ │ │ │ │ │ │ ├── json-table-editor.component.scss │ │ │ │ │ │ │ │ ├── json-table-editor.component.html │ │ │ │ │ │ │ │ └── json-table-editor.component.spec.ts │ │ │ │ │ │ │ ├── http-work-bench.component.spec.ts │ │ │ │ │ │ │ └── tree-data-editor │ │ │ │ │ │ │ │ └── tree-data-editor.component.spec.ts │ │ │ │ │ │ └── collection-work-bench │ │ │ │ │ │ │ └── collection-work-bench.component.spec.ts │ │ │ │ │ ├── api-tree-menu │ │ │ │ │ │ ├── inner │ │ │ │ │ │ │ └── empty-tree │ │ │ │ │ │ │ │ ├── empty-tree.component.html │ │ │ │ │ │ │ │ ├── empty-tree.component.scss │ │ │ │ │ │ │ │ ├── empty-tree.component.ts │ │ │ │ │ │ │ │ └── empty-tree.component.spec.ts │ │ │ │ │ │ └── api-tree-menu.component.spec.ts │ │ │ │ │ ├── test-dashboard │ │ │ │ │ │ ├── test-dashboard.component.scss │ │ │ │ │ │ └── test-dashboard.component.spec.ts │ │ │ │ │ ├── right-panel │ │ │ │ │ │ ├── right-panel.component.scss │ │ │ │ │ │ ├── right-panel.component.spec.ts │ │ │ │ │ │ └── right-panel.component.html │ │ │ │ │ ├── nav │ │ │ │ │ │ └── nav.component.spec.ts │ │ │ │ │ └── api-header-operation │ │ │ │ │ │ └── api-header-operation.component.spec.ts │ │ │ │ ├── index.ts │ │ │ │ ├── developing │ │ │ │ │ ├── developing.component.html │ │ │ │ │ ├── developing.component.spec.ts │ │ │ │ │ └── developing.component.ts │ │ │ │ └── docs │ │ │ │ │ ├── http-api-doc │ │ │ │ │ ├── http-api-doc.component.scss │ │ │ │ │ ├── http-api-doc.component.spec.ts │ │ │ │ │ └── http-api-doc.component.html │ │ │ │ │ ├── i18n-title │ │ │ │ │ ├── i18n-title.component.scss │ │ │ │ │ ├── i18n-title.component.spec.ts │ │ │ │ │ └── i18n-title.component.ts │ │ │ │ │ ├── http-url-doc │ │ │ │ │ ├── http-url-doc.component.spec.ts │ │ │ │ │ └── http-url-doc.component.html │ │ │ │ │ └── raw-text-doc │ │ │ │ │ └── raw-text-doc.component.spec.ts │ │ │ ├── directives │ │ │ │ ├── index.ts │ │ │ │ └── webview │ │ │ │ │ ├── webview.directive.ts │ │ │ │ │ └── webview.directive.spec.ts │ │ │ ├── guard │ │ │ │ └── jwt.guard.spec.ts │ │ │ └── icon.ts │ │ ├── core │ │ │ ├── services │ │ │ │ ├── index.ts │ │ │ │ ├── entity │ │ │ │ │ └── ArrayData.ts │ │ │ │ ├── DataService.ts │ │ │ │ ├── utils │ │ │ │ │ └── Uuid.ts │ │ │ │ ├── ConfigService.ts │ │ │ │ ├── electron │ │ │ │ │ └── electron.service.spec.ts │ │ │ │ ├── close-icon-observable.service.ts │ │ │ │ ├── impl │ │ │ │ │ ├── electron │ │ │ │ │ │ ├── http-api-elec-impl.service.ts │ │ │ │ │ │ ├── database-data-service.service.ts │ │ │ │ │ │ └── nav-tab-elec-impl.service.ts │ │ │ │ │ ├── web │ │ │ │ │ │ ├── web-data.service.ts │ │ │ │ │ │ └── ConfigServiceWebImpl.ts │ │ │ │ │ └── http-api.service.ts │ │ │ │ ├── browser-open.service.ts │ │ │ │ ├── ServiceDefine.ts │ │ │ │ └── db.ts │ │ │ └── core.module.ts │ │ ├── passport │ │ │ ├── passport.module.ts │ │ │ ├── passport-routing.module.ts │ │ │ └── login │ │ │ │ ├── login.component.spec.ts │ │ │ │ └── login.component.ts │ │ ├── app.component.spec.ts │ │ └── app-routing.module.ts │ ├── polyfills-test.ts │ ├── favicon.ico │ ├── environments │ │ ├── environment.dev.ts │ │ ├── environment.prod.ts │ │ ├── environment.ts │ │ ├── environment.web.ts │ │ └── environment.web.prod.ts │ ├── typings.d.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ ├── main.ts │ └── test.ts ├── .npmrc ├── _config.yml ├── app │ ├── src │ │ ├── listeners │ │ │ ├── listener-handler.ts │ │ │ └── handler │ │ │ │ ├── analysis.ts │ │ │ │ └── item-listener.ts │ │ └── entity │ │ │ ├── Item.ts │ │ │ ├── Config.ts │ │ │ └── ApiMenuCollection.ts │ ├── test │ │ └── co.test.ts │ ├── jest.config.js │ ├── package.json │ └── tsconfig.json ├── e2e │ ├── tsconfig.e2e.json │ └── playwright.config.ts ├── .editorconfig ├── tsconfig.serve.json ├── electron-builder.json ├── .gitignore ├── tsconfig.json ├── LICENSE.md ├── angular.webpack.js ├── HOW_TO.md └── .eslintrc.json ├── document ├── docs │ ├── zh │ │ ├── guide │ │ │ ├── about.md │ │ │ ├── setting.md │ │ │ ├── memory-assistant.md │ │ │ ├── feature-design.md │ │ │ ├── making-friends.md │ │ │ └── business-ideal.md │ │ └── README.md │ ├── .vuepress │ │ └── public │ │ │ └── PluginRepo │ │ │ └── plugins.json │ ├── guide │ │ ├── about.md │ │ ├── document.md │ │ ├── core-principles.md │ │ ├── database.md │ │ ├── making-friends.md │ │ ├── setting.md │ │ ├── feature-design.md │ │ ├── README.md │ │ ├── memory-assistant.md │ │ └── getting-started.md │ └── README.md ├── package.json └── .gitignore ├── server ├── lombok.config ├── src │ ├── main │ │ ├── resources │ │ │ ├── application.yml │ │ │ ├── db │ │ │ │ └── migration │ │ │ │ │ ├── h2 │ │ │ │ │ └── V202208.17.0__API_DEFINE_ADD_COLUMN.sql │ │ │ │ │ └── postgresql │ │ │ │ │ └── V202208.17.0__API_DEFINE_ADD_COLUMN.sql │ │ │ ├── messages_zh_CN.properties │ │ │ ├── messages.properties │ │ │ ├── messages_en_US.properties │ │ │ ├── application-postgresql.yml │ │ │ ├── application-h2.yml │ │ │ └── application-test.yml │ │ └── java │ │ │ └── org │ │ │ └── adp │ │ │ └── gable │ │ │ ├── runner │ │ │ ├── ActionType.java │ │ │ ├── impl │ │ │ │ ├── HttpMethod.java │ │ │ │ ├── HttpResponseBodyType.java │ │ │ │ ├── HttpBodyType.java │ │ │ │ └── HttpResponseField.java │ │ │ └── Action.java │ │ │ ├── common │ │ │ ├── web │ │ │ │ ├── CommonErrorResult.java │ │ │ │ ├── ErrorResult.java │ │ │ │ ├── SampleResultCode.java │ │ │ │ └── SpringContextHolder.java │ │ │ ├── dto │ │ │ │ └── BaseDto.java │ │ │ ├── handler │ │ │ │ └── CustomExceptionResolver.java │ │ │ ├── utils │ │ │ │ └── I18nUtils.java │ │ │ └── beans │ │ │ │ └── Result.java │ │ │ ├── utils │ │ │ ├── JsonBuilderHolder.java │ │ │ └── BeanUtils.java │ │ │ ├── api │ │ │ ├── dao │ │ │ │ ├── DocDao.java │ │ │ │ ├── HttpApiDao.java │ │ │ │ ├── DocDefineDao.java │ │ │ │ ├── ApiCollectionDao.java │ │ │ │ ├── ApiMenuItemDao.java │ │ │ │ ├── DocMenuDao.java │ │ │ │ └── DocBlockDao.java │ │ │ ├── dto │ │ │ │ ├── doc │ │ │ │ │ ├── DocDto.java │ │ │ │ │ ├── DocDefineDto.java │ │ │ │ │ └── DocMenuDto.java │ │ │ │ ├── http │ │ │ │ │ ├── KeyValueDto.java │ │ │ │ │ ├── FormKeyValueDto.java │ │ │ │ │ ├── DocJsonNode.java │ │ │ │ │ └── DocJsonTableNode.java │ │ │ │ └── HttpApiDto.java │ │ │ ├── DocConst.java │ │ │ └── entity │ │ │ │ └── DocEntity.java │ │ │ ├── security │ │ │ ├── dao │ │ │ │ ├── UserRepository.java │ │ │ │ ├── RoleRepository.java │ │ │ │ └── RolePermissionRepository.java │ │ │ ├── config │ │ │ │ └── MethodSecurityConfig.java │ │ │ ├── utils │ │ │ │ ├── JwtConst.java │ │ │ │ ├── SecurityErrorResult.java │ │ │ │ ├── JwtUtils.java │ │ │ │ └── AuthoritiesSerializeUtil.java │ │ │ └── PermissionType.java │ │ │ └── GableApplication.java │ └── test │ │ ├── resources │ │ └── application.yml │ │ └── java │ │ └── org │ │ └── adp │ │ └── gable │ │ ├── SupperUser.java │ │ ├── security │ │ ├── PermissionTypeTest.java │ │ ├── TestTokenUtils.java │ │ ├── entity │ │ │ └── RoleEntityTest.java │ │ └── service │ │ │ └── JwtUserServiceImplTest.java │ │ ├── utils │ │ └── ResultUtils.java │ │ └── Controller │ │ └── TestUserController.java ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties └── .gitignore ├── assets ├── RunHttp.gif ├── StarMe.gif ├── DocFreeEdit.gif └── DocAutoGenerate.gif ├── .gitignore └── .github └── workflows └── vuepress-deploy.yml /client/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/.npmrc: -------------------------------------------------------------------------------- 1 | save=true 2 | save-exact=true 3 | -------------------------------------------------------------------------------- /client/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-architect -------------------------------------------------------------------------------- /client/src/app/home/diff/diff.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | 3 | } -------------------------------------------------------------------------------- /client/src/app/home/doc-page/doc-page.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/polyfills-test.ts: -------------------------------------------------------------------------------- 1 | import 'zone.js'; 2 | -------------------------------------------------------------------------------- /document/docs/zh/guide/about.md: -------------------------------------------------------------------------------- 1 | # 关于Gable 2 | 3 | 等待完善 -------------------------------------------------------------------------------- /client/src/app/detail/detail.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | 3 | } -------------------------------------------------------------------------------- /document/docs/.vuepress/public/PluginRepo/plugins.json: -------------------------------------------------------------------------------- 1 | [ 2 | ] -------------------------------------------------------------------------------- /server/lombok.config: -------------------------------------------------------------------------------- 1 | lombok.addLombokGeneratedAnnotation = true -------------------------------------------------------------------------------- /client/src/app/home/home/home.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /client/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /client/src/app/shared/components/page-not-found/page-not-found.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /document/docs/guide/about.md: -------------------------------------------------------------------------------- 1 | # About Gable 2 | 3 | Waiting for improvement -------------------------------------------------------------------------------- /server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: h2 -------------------------------------------------------------------------------- /client/src/app/core/services/index.ts: -------------------------------------------------------------------------------- 1 | export * from './electron/electron.service'; 2 | -------------------------------------------------------------------------------- /client/src/app/home/doc-page/doc-page.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /server/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: test -------------------------------------------------------------------------------- /client/src/app/shared/directives/index.ts: -------------------------------------------------------------------------------- 1 | export * from './webview/webview.directive'; 2 | -------------------------------------------------------------------------------- /document/docs/guide/document.md: -------------------------------------------------------------------------------- 1 | # Document 2 | 3 | 4 | Waiting for improvement 5 | 6 | 先看中文 -------------------------------------------------------------------------------- /assets/RunHttp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdvancedProductivity/Gable/HEAD/assets/RunHttp.gif -------------------------------------------------------------------------------- /assets/StarMe.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdvancedProductivity/Gable/HEAD/assets/StarMe.gif -------------------------------------------------------------------------------- /client/src/app/home/doc-page/doc-dash-board/doc-create-dialog/doc-create-dialog.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /document/docs/guide/core-principles.md: -------------------------------------------------------------------------------- 1 | # Core Principle 2 | 3 | Waiting for improvement 4 | 5 | 先看中文 -------------------------------------------------------------------------------- /document/docs/guide/database.md: -------------------------------------------------------------------------------- 1 | # Database Table Design 2 | 3 | Waiting for improvement 4 | 5 | 先看中文 -------------------------------------------------------------------------------- /assets/DocFreeEdit.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdvancedProductivity/Gable/HEAD/assets/DocFreeEdit.gif -------------------------------------------------------------------------------- /client/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdvancedProductivity/Gable/HEAD/client/src/favicon.ico -------------------------------------------------------------------------------- /document/docs/guide/making-friends.md: -------------------------------------------------------------------------------- 1 | # Notice for making friends 2 | 3 | Waiting for improvement 4 | 5 | 先看中文 -------------------------------------------------------------------------------- /assets/DocAutoGenerate.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdvancedProductivity/Gable/HEAD/assets/DocAutoGenerate.gif -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/form-editor/form-editor.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/query-table/query-table.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/app/shared/components/page-not-found/page-not-found.component.html: -------------------------------------------------------------------------------- 1 |

2 | page-not-found works! 3 |

4 | -------------------------------------------------------------------------------- /client/src/assets/img/doc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdvancedProductivity/Gable/HEAD/client/src/assets/img/doc.png -------------------------------------------------------------------------------- /client/app/src/listeners/listener-handler.ts: -------------------------------------------------------------------------------- 1 | 2 | export interface Handler { 3 | 4 | handle(args: any[]): any; 5 | 6 | } 7 | -------------------------------------------------------------------------------- /client/src/app/core/services/entity/ArrayData.ts: -------------------------------------------------------------------------------- 1 | export class ArrayData{ 2 | id: string; 3 | data: ArrayBuffer; 4 | } 5 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/inner/check-box-cell/check-box-cell.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/response-cookies/response-cookies.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/response-headers/response-headers.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdvancedProductivity/Gable/HEAD/client/src/assets/background.jpg -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/response-key-value/response-key-value.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdvancedProductivity/Gable/HEAD/client/src/assets/icons/favicon.ico -------------------------------------------------------------------------------- /client/src/assets/icons/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdvancedProductivity/Gable/HEAD/client/src/assets/icons/favicon.png -------------------------------------------------------------------------------- /client/src/environments/environment.dev.ts: -------------------------------------------------------------------------------- 1 | export const APP_CONFIG = { 2 | production: false, 3 | environment: 'DEV' 4 | }; 5 | -------------------------------------------------------------------------------- /client/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const APP_CONFIG = { 2 | production: true, 3 | environment: 'PROD' 4 | }; 5 | -------------------------------------------------------------------------------- /client/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | export const APP_CONFIG = { 2 | production: false, 3 | environment: 'LOCAL' 4 | }; 5 | -------------------------------------------------------------------------------- /client/src/environments/environment.web.ts: -------------------------------------------------------------------------------- 1 | export const APP_CONFIG = { 2 | production: false, 3 | environment: 'WEB' 4 | }; 5 | -------------------------------------------------------------------------------- /client/src/assets/icons/electron.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdvancedProductivity/Gable/HEAD/client/src/assets/icons/electron.bmp -------------------------------------------------------------------------------- /client/src/assets/icons/favicon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdvancedProductivity/Gable/HEAD/client/src/assets/icons/favicon.icns -------------------------------------------------------------------------------- /server/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdvancedProductivity/Gable/HEAD/server/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/inner/check-box-cell-editor/check-box-cell-editor.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/environments/environment.web.prod.ts: -------------------------------------------------------------------------------- 1 | export const APP_CONFIG = { 2 | production: true, 3 | environment: 'WEB-PROD' 4 | }; 5 | -------------------------------------------------------------------------------- /client/src/assets/icons/favicon.256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdvancedProductivity/Gable/HEAD/client/src/assets/icons/favicon.256x256.png -------------------------------------------------------------------------------- /client/src/assets/icons/favicon.512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdvancedProductivity/Gable/HEAD/client/src/assets/icons/favicon.512x512.png -------------------------------------------------------------------------------- /client/app/test/co.test.ts: -------------------------------------------------------------------------------- 1 | describe('test jest config', () => { 2 | test('is test path work', () => { 3 | expect(0).toBe(0); 4 | }); 5 | }); 6 | -------------------------------------------------------------------------------- /client/src/app/home/mock-page/mock-page.component.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | -------------------------------------------------------------------------------- /client/src/app/shared/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './page-not-found/page-not-found.component'; 2 | export * from './layout/basic-layout.component'; 3 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/inner/cell-content/cell-content.component.scss: -------------------------------------------------------------------------------- 1 | .hint-str{ 2 | color: #A6A6A6; 3 | } 4 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/response-key-value/response-key-value.component.html: -------------------------------------------------------------------------------- 1 |

response-key-value works!

2 | -------------------------------------------------------------------------------- /client/src/assets/svg/add.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/src/test/java/org/adp/gable/SupperUser.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable; 2 | 3 | public interface SupperUser { 4 | String USER_EMAIL = "default@app.com"; 5 | String PASSWORD = "123456"; 6 | } 7 | -------------------------------------------------------------------------------- /server/src/main/resources/db/migration/h2/V202208.17.0__API_DEFINE_ADD_COLUMN.sql: -------------------------------------------------------------------------------- 1 | alter table api_http 2 | add column body_text_doc text; 3 | alter table api_http 4 | add column resp_body_text_doc text; 5 | -------------------------------------------------------------------------------- /document/docs/guide/setting.md: -------------------------------------------------------------------------------- 1 | # Setting 2 | 3 | 4 | Waiting for improvement 5 | 6 | 先看中文 7 | 8 | 这里写设置相关的内容 9 | 10 | ## Gable Server Config 11 | 12 | 这里写Gable 服务地址 13 | 14 | ## Proxy Config 15 | 16 | 这里写 代理设置 -------------------------------------------------------------------------------- /server/src/main/resources/db/migration/postgresql/V202208.17.0__API_DEFINE_ADD_COLUMN.sql: -------------------------------------------------------------------------------- 1 | alter table api_http 2 | add column body_text_doc text; 3 | 4 | alter table api_http 5 | add column resp_body_text_doc text; 6 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/inner/cell-content/cell-content.component.html: -------------------------------------------------------------------------------- 1 |
{{hintStr}}
2 |
{{cellValue}}
3 | -------------------------------------------------------------------------------- /client/src/app/shared/directives/webview/webview.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive } from '@angular/core'; 2 | 3 | @Directive({ 4 | selector: 'webview' 5 | }) 6 | export class WebviewDirective { 7 | constructor() { } 8 | } 9 | -------------------------------------------------------------------------------- /client/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare const nodeModule: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | interface Window { 7 | process: any; 8 | require: any; 9 | } 10 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/inner/check-box-cell/check-box-cell.component.html: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/text-body/text-body.component.scss: -------------------------------------------------------------------------------- 1 | .http-body-container { 2 | width: 100%; 3 | height: 100%; 4 | border: 1px solid #E6E6E6; 5 | border-radius: 4px; 6 | } 7 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/none-body/none-body.component.scss: -------------------------------------------------------------------------------- 1 | .none-body-container{ 2 | justify-content: center; 3 | align-content: center; 4 | div { 5 | text-align: center; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/runner/ActionType.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.runner; 2 | 3 | /** 4 | * @author zzq 5 | */ 6 | public enum ActionType { 7 | 8 | /** 9 | * http type of Action 10 | */ 11 | HTTP 12 | } 13 | -------------------------------------------------------------------------------- /client/app/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: {'^.+\\.ts?$': 'ts-jest'}, 3 | testEnvironment: 'node', 4 | testRegex: '/test/.*\\.(test|spec)?\\.(ts|tsx)$', 5 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'] 6 | }; 7 | -------------------------------------------------------------------------------- /client/app/src/entity/Item.ts: -------------------------------------------------------------------------------- 1 | import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'; 2 | 3 | @Entity() 4 | export class Item 5 | { 6 | @PrimaryGeneratedColumn() 7 | id: number; 8 | 9 | @Column() 10 | name: string; 11 | } 12 | -------------------------------------------------------------------------------- /document/docs/guide/feature-design.md: -------------------------------------------------------------------------------- 1 | # Feature Design 2 | 3 | Waiting for improvement 4 | 5 | 先看中文 6 | 7 | ## Pre-Script 8 | 预执行脚本 9 | 10 | ## Post-Script 11 | 后执行脚本 12 | 13 | ## Post-Script-Response 14 | 后执行脚本 15 | 16 | ## Mock 17 | 后执行脚本 18 | -------------------------------------------------------------------------------- /client/src/app/core/services/DataService.ts: -------------------------------------------------------------------------------- 1 | import {Observable} from 'rxjs'; 2 | 3 | export interface DataService { 4 | getData: () => Observable; 5 | 6 | addItem: () => Observable; 7 | 8 | clearAll: () => Observable; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/common/web/CommonErrorResult.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.common.web; 2 | 3 | /** 4 | * @author zzq 5 | */ 6 | public interface CommonErrorResult { 7 | ErrorResult SYSTEM_NPE_ERROR = new SampleResultCode(500, "SYS.NPE_ERROR");; 8 | } 9 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/response-cookies/response-cookies.component.html: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/response-headers/response-headers.component.html: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/utils/JsonBuilderHolder.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.utils; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | 5 | public class JsonBuilderHolder { 6 | public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); 7 | } 8 | -------------------------------------------------------------------------------- /client/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "types": [ 7 | "node" 8 | ] 9 | }, 10 | "include": [ 11 | "**.spec.ts" 12 | ], 13 | } 14 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/none-body/none-body.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | {{'PAGES.API_TEST.REQ.NONE_BODY' | translate}} 4 |
5 |
6 | 7 | -------------------------------------------------------------------------------- /server/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.5/apache-maven-3.8.5-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar 3 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/api-tree-menu/inner/empty-tree/empty-tree.component.html: -------------------------------------------------------------------------------- 1 |
2 |

{{ 'PAGES.API_TEST.TREE_MENU.EMPTY_TREE' | translate }}

3 |

{{ 'PAGES.API_TEST.TREE_MENU.EMPTY_TREE_ADVICE' | translate }}

4 |
5 | -------------------------------------------------------------------------------- /document/docs/guide/README.md: -------------------------------------------------------------------------------- 1 | # Instruction 2 | 3 | Waiting for improvement 4 | 5 | 先看中文 6 | 7 | `Gable` is an open source API collaboration tool,you can use it like `Postman`。 8 | 9 | ## How It Works 10 | 11 | `Gable` is a common `SpringBoot` service. Its code is very simple. 12 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/test-dashboard/test-dashboard.component.scss: -------------------------------------------------------------------------------- 1 | .dashboard { 2 | width: 100%; 3 | height: 100%; 4 | 5 | .http{ 6 | width: 100%; 7 | height: 100%; 8 | } 9 | 10 | .collection{ 11 | width: 100%; 12 | height: 100%; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /client/src/app/core/core.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | @NgModule({ 5 | declarations: [ 6 | ], 7 | exports: [ 8 | ], 9 | imports: [ 10 | CommonModule 11 | ] 12 | }) 13 | export class CoreModule { } 14 | -------------------------------------------------------------------------------- /server/src/main/resources/messages_zh_CN.properties: -------------------------------------------------------------------------------- 1 | SEC.USER_NOT_EXIST=账号不存在 2 | SEC.PASSWORD_ERROR=密码错误 3 | SEC.LOGIN_EXPIRED=登录已过期 4 | SEC.ACCESS_DENIED=没有访问该资源的权限 5 | SEC.NO_TOKEN_PROVIDED=请求体中没有携带 Token 6 | SEC.TOKEN_INVALID=Token 不合法 7 | SEC.JWT_UNKNOWN_ERROR=解析 Token 时出现未知错误 8 | SYS.NPE_ERROR=系统错误,错误代码NPE -------------------------------------------------------------------------------- /client/src/app/core/services/utils/Uuid.ts: -------------------------------------------------------------------------------- 1 | export const randomString = (e) => { 2 | e = e || 32; 3 | const t = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz12345678_'; 4 | const a = t.length; 5 | let n = ''; 6 | for (let i = 0; i < e; i++) {n += t.charAt(Math.floor(Math.random() * a));} 7 | return n; 8 | }; 9 | -------------------------------------------------------------------------------- /client/src/app/core/services/ConfigService.ts: -------------------------------------------------------------------------------- 1 | import {Observable} from 'rxjs'; 2 | 3 | export interface ConfigService { 4 | getConfig: (key: string) => Observable; 5 | 6 | updateOrCreateConfig: (key: string, value: string) => Observable; 7 | 8 | getConfigSync(key: string); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /client/src/app/shared/directives/webview/webview.directive.spec.ts: -------------------------------------------------------------------------------- 1 | import { WebviewDirective } from './webview.directive'; 2 | 3 | describe('WebviewDirective', () => { 4 | it('should create an instance', () => { 5 | const directive = new WebviewDirective(); 6 | expect(directive).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/api/dao/DocDao.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.api.dao; 2 | 3 | import org.adp.gable.api.entity.DocEntity; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | /** 7 | * @author zzq 8 | */ 9 | public interface DocDao extends JpaRepository { 10 | } 11 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/api/dao/HttpApiDao.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.api.dao; 2 | 3 | 4 | import org.adp.gable.api.entity.HttpApi; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | 7 | /** 8 | * @author zzq 9 | */ 10 | public interface HttpApiDao extends JpaRepository { 11 | } 12 | -------------------------------------------------------------------------------- /client/app/src/entity/Config.ts: -------------------------------------------------------------------------------- 1 | import {Entity, PrimaryGeneratedColumn, Column, Unique, PrimaryColumn} from 'typeorm'; 2 | 3 | @Entity() 4 | export class Config{ 5 | 6 | @Column({ 7 | unique: true, 8 | nullable: false 9 | }) 10 | @PrimaryColumn() 11 | key: string; 12 | 13 | @Column() 14 | value: string; 15 | } 16 | -------------------------------------------------------------------------------- /client/src/app/detail/detail.component.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | {{ 'PAGES.DETAIL.TITLE' | translate }} 4 |

5 |

6 | {{ info.id + ' - ' + info.name }} 7 |

8 | {{ 'PAGES.DETAIL.BACK_TO_HOME' | translate }} 9 |
10 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/api/dao/DocDefineDao.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.api.dao; 2 | 3 | import org.adp.gable.api.entity.DocDefine; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | /** 7 | * @author zzq 8 | */ 9 | public interface DocDefineDao extends JpaRepository { 10 | } 11 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/api/dto/doc/DocDto.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.api.dto.doc; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.Date; 6 | 7 | /** 8 | * @author zzq 9 | */ 10 | @Data 11 | public class DocDto { 12 | private Long id; 13 | private String name; 14 | private Date dateCreated; 15 | } 16 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/empty-response/empty-response.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | {{header | translate}} 5 |

6 |
7 |
8 | {{tip | translate}} 9 |
10 |
11 | -------------------------------------------------------------------------------- /client/src/app/home/doc-page/doc-page.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-doc-page', 5 | templateUrl: './doc-page.component.html', 6 | styleUrls: ['./doc-page.component.scss'] 7 | }) 8 | export class DocPageComponent implements OnInit { 9 | ngOnInit(): void { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/api-tree-menu/inner/empty-tree/empty-tree.component.scss: -------------------------------------------------------------------------------- 1 | .empty-tree-container { 2 | width: 100%; 3 | height: 500px; 4 | display: flex; 5 | flex-direction: column; 6 | align-items: center; 7 | align-content: center; 8 | justify-content: center; 9 | font-family: Roboto, "Helvetica Neue", sans-serif; 10 | } 11 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/api/DocConst.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.api; 2 | 3 | /** 4 | * @author zzq 5 | */ 6 | public interface DocConst { 7 | Long DEFAULT_DOC_ID = 1L; 8 | Integer COLLECTION_LEVEL = 0; 9 | Integer API_LEVEL = 1; 10 | Long DEFAULT_ROOT_PARENT_ID = 0L; 11 | String DEFAULT_EDITOR_VERSION = "2.25.0"; 12 | } 13 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/security/dao/UserRepository.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.security.dao; 2 | 3 | import org.adp.gable.security.entity.UserEntity; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | /** 7 | * @author zzq 8 | */ 9 | public interface UserRepository extends JpaRepository { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /client/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /document/docs/zh/guide/setting.md: -------------------------------------------------------------------------------- 1 | # 设置 2 | 3 | 这里写设置相关的内容 4 | 5 | ## Gable 服务地址 6 | 7 | 将数据存储在 远程服务器上而不是本机,需要输入一个 `URL` 链接。。 8 | 9 | 不能以 `/` 结尾。 10 | - `http://localhost:2208` 可以 11 | - `http://localhost:2208/` 不可以 12 | 13 | ## 代理设置 14 | 15 | 将API 委托给代理执行,需要输入一个 `URL` 链接。 16 | 17 | 不能以 `/` 结尾。 18 | - `http://localhost:2208` 可以 19 | - `http://localhost:2208/` 不可以 -------------------------------------------------------------------------------- /document/docs/zh/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroText: Gable 4 | tagline: API 协作工具 5 | actionText: 快速上手 → 6 | actionLink: /zh/guide/ 7 | features: 8 | - title: 开源 9 | details: 自由获取全部代码 10 | - title: API 文档设计 11 | details: 自动生成文档, 自由撰写文档 12 | - title: API 调试 13 | details: 测试 Http 接口,多个环境管理 14 | footer: MIT Licensed | Copyright © 2018-present Evan You 15 | --- 16 | -------------------------------------------------------------------------------- /client/src/app/home/setting/setting.component.scss: -------------------------------------------------------------------------------- 1 | .setting-container { 2 | padding: 24px; 3 | display: flex; 4 | flex-direction: row; 5 | 6 | .setting-box { 7 | width: 400px; 8 | margin: 20px; 9 | 10 | .form-field{ 11 | width: 100%; 12 | } 13 | } 14 | 15 | .border { 16 | border: 1px solid #E6E6E6; 17 | border-radius: 4px; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/body-text/body-html/body-html.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | -------------------------------------------------------------------------------- /client/src/app/home/mock-page/mock-page.component.scss: -------------------------------------------------------------------------------- 1 | .t-container { 2 | width: 100%; 3 | height: 100%; 4 | display: flex; 5 | flex-direction: row; 6 | 7 | .left { 8 | width: 500px; 9 | height: 100%; 10 | background-color: pink; 11 | } 12 | 13 | .right { 14 | flex: 1; 15 | height: 100%; 16 | background-color: #3a5e77; 17 | 18 | 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /client/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "baseUrl": "", 6 | "types": [ 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "main.ts", 12 | "polyfills.ts" 13 | ], 14 | "include": [ 15 | "**/*.d.ts" 16 | ], 17 | "exclude": [ 18 | "**/*.spec.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /document/docs/zh/guide/memory-assistant.md: -------------------------------------------------------------------------------- 1 | # 记忆助手 2 | 3 | 主要是帮助开发人员速查一些东西,对非开发人员不重要。 4 | 5 | ## PostgreSql 相关 6 | 7 | #### 启动 8 | ```shell 9 | pg_ctl start -D ../data -l logfile 10 | ``` 11 | #### 登录数据库 12 | ```shell 13 | # psql -U [用户名] 14 | 15 | psql -U postgres 16 | ``` 17 | #### 查看数据库 18 | ```shell 19 | \l 20 | ``` 21 | #### 选择数据库 22 | ```shell 23 | \c [数据库名] 24 | 25 | \c gable 26 | ``` -------------------------------------------------------------------------------- /client/app/src/listeners/handler/analysis.ts: -------------------------------------------------------------------------------- 1 | import {Handler} from "../listener-handler"; 2 | 3 | const ua = require("universal-analytics"); 4 | export const visitor = ua('UA-235247128-1'); 5 | 6 | 7 | export class AnalysisHandler implements Handler { 8 | 9 | handle(args: any[]): any { 10 | visitor.event(args[0]).send(); 11 | console.log('send args', args); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /server/src/main/resources/messages.properties: -------------------------------------------------------------------------------- 1 | SEC.USER_NOT_EXIST=Username Not Exist 2 | SEC.PASSWORD_ERROR=Password Not Correct 3 | SEC.LOGIN_EXPIRED=Login Expired 4 | SEC.ACCESS_DENIED=Have No Permission Access The Resource 5 | SEC.NO_TOKEN_PROVIDED=No Token Provide 6 | SEC.TOKEN_INVALID=Token Invalid 7 | SEC.JWT_UNKNOWN_ERROR=Unknown Error Happens While Parser Token 8 | SYS.NPE_ERROR=System Error, Error Code: NPE -------------------------------------------------------------------------------- /server/src/main/resources/messages_en_US.properties: -------------------------------------------------------------------------------- 1 | SEC.USER_NOT_EXIST=Username Not Exist 2 | SEC.PASSWORD_ERROR=Password Not Correct 3 | SEC.LOGIN_EXPIRED=Login Expired 4 | SEC.ACCESS_DENIED=Have No Permission Access The Resource 5 | SEC.NO_TOKEN_PROVIDED=No Token Provide 6 | SEC.TOKEN_INVALID=Token Invalid 7 | SEC.JWT_UNKNOWN_ERROR=Unknown Error Happens While Parser Token 8 | SYS.NPE_ERROR=System Error, Error Code: NPE -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/api/dto/doc/DocDefineDto.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.api.dto.doc; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author zzq 9 | */ 10 | @Data 11 | public class DocDefineDto { 12 | private Long id; 13 | private String name; 14 | private String version; 15 | private Long time; 16 | private List blocks; 17 | } 18 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/api/dao/ApiCollectionDao.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.api.dao; 2 | 3 | import org.adp.gable.api.entity.ApiCollection; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | /** 8 | * @author 16943 9 | */ 10 | @Repository 11 | public interface ApiCollectionDao extends JpaRepository { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/inner/check-box-cell-editor/check-box-cell-editor.component.html: -------------------------------------------------------------------------------- 1 |
2 | 8 |
9 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/api/dto/doc/DocMenuDto.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.api.dto.doc; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @author zzq 7 | */ 8 | @Data 9 | public class DocMenuDto { 10 | private Long id; 11 | private String name; 12 | private Long docId; 13 | private Integer level; 14 | private Integer itemCount; 15 | private Long parentId; 16 | private String apiKey; 17 | } 18 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/api-tree-menu/inner/empty-tree/empty-tree.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-empty-tree', 5 | templateUrl: './empty-tree.component.html', 6 | styleUrls: ['./empty-tree.component.scss'] 7 | }) 8 | export class EmptyTreeComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/common/dto/BaseDto.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.common.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.Date; 6 | 7 | @Data 8 | public class BaseDto { 9 | private Long tenantId; 10 | private Long createdBy; 11 | private Date dateCreated; 12 | private Long modifiedBy; 13 | private Date dateModified; 14 | private String operationUrl; 15 | private String dataFrom; 16 | } 17 | -------------------------------------------------------------------------------- /client/src/app/shared/guard/jwt.guard.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { JwtGuard } from './jwt-guard.guard'; 4 | 5 | describe('JwtGuardGuard', () => { 6 | let guard: JwtGuard; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | guard = TestBed.inject(JwtGuard); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(guard).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /client/src/app/core/services/electron/electron.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { ElectronService } from './electron.service'; 4 | 5 | describe('ElectronService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: ElectronService = TestBed.get(ElectronService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/runner/impl/HttpMethod.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.runner.impl; 2 | 3 | /** 4 | * @author zzq 5 | */ 6 | public enum HttpMethod { 7 | 8 | /** 9 | * get method 10 | */ 11 | GET, 12 | 13 | /** 14 | * post method 15 | */ 16 | POST, 17 | 18 | /** 19 | * delete method 20 | */ 21 | DELETE, 22 | 23 | /** 24 | * put method 25 | */ 26 | PUT, 27 | } 28 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/none-body/none-body.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-none-body', 5 | templateUrl: './none-body.component.html', 6 | styleUrls: ['./none-body.component.scss'] 7 | }) 8 | export class NoneBodyComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /client/src/assets/svg/closeNav.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /client/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "test.ts", 12 | "polyfills-test.ts" 13 | ], 14 | "include": [ 15 | "**/*.spec.ts", 16 | "**/*.d.ts" 17 | ], 18 | "exclude": [ 19 | "dist", 20 | "release", 21 | "node_modules" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/runner/impl/HttpResponseBodyType.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.runner.impl; 2 | 3 | /** 4 | * @author zzq 5 | */ 6 | public enum HttpResponseBodyType { 7 | /** 8 | * text plain 9 | */ 10 | TEXT, 11 | 12 | /** 13 | * json plain 14 | */ 15 | JSON, 16 | 17 | /** 18 | * xml plain 19 | */ 20 | XML, 21 | 22 | /** 23 | * html plain 24 | */ 25 | HTML, 26 | } 27 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/json-table-editor/json-table-editor.component.scss: -------------------------------------------------------------------------------- 1 | .doc-json-tree-container { 2 | position: relative; 3 | width: 100%; 4 | height: auto; 5 | min-height: 100% !important; 6 | border: 1px solid #bbb; 7 | background-color: #fff; 8 | -webkit-box-sizing: border-box; 9 | box-sizing: border-box; 10 | 11 | .is-scroll { 12 | position: absolute; 13 | margin-top: 2px; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /client/src/assets/svg/doc.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/app/shared/components/page-not-found/page-not-found.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-page-not-found', 5 | templateUrl: './page-not-found.component.html', 6 | styleUrls: ['./page-not-found.component.scss'] 7 | }) 8 | export class PageNotFoundComponent implements OnInit { 9 | constructor() {} 10 | 11 | ngOnInit(): void { 12 | console.log('PageNotFoundComponent INIT'); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /client/e2e/playwright.config.ts: -------------------------------------------------------------------------------- 1 | /** @type {import('@playwright/test').PlaywrightTestConfig} */ 2 | const config = { 3 | testDir: '.', 4 | timeout: 45000, 5 | outputDir: './screenshots', 6 | use: { 7 | headless: false, 8 | viewport: { width: 1280, height: 720 }, 9 | launchOptions: { 10 | slowMo: 1000, 11 | }, 12 | trace: 'on', 13 | }, 14 | expect: { 15 | toMatchSnapshot: { threshold: 0.2 }, 16 | }, 17 | }; 18 | 19 | module.exports = config; 20 | -------------------------------------------------------------------------------- /client/src/assets/svg/comment.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/common/web/ErrorResult.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.common.web; 2 | 3 | /** 4 | * @author zzq 5 | */ 6 | public interface ErrorResult { 7 | Integer SUCCESS_CODE = 100; 8 | 9 | /** 10 | * return the error code 11 | * 12 | * @return code 13 | */ 14 | int getErrorCode(); 15 | 16 | /** 17 | * return the error message tip 18 | * 19 | * @return i18n 20 | */ 21 | String getMessageI18nKey(); 22 | } 23 | -------------------------------------------------------------------------------- /client/src/app/detail/detail.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | import { DetailRoutingModule } from './detail-routing.module'; 5 | 6 | import { DetailComponent } from './detail.component'; 7 | import { SharedModule } from '../shared/shared.module'; 8 | 9 | @NgModule({ 10 | declarations: [DetailComponent], 11 | imports: [CommonModule, SharedModule, DetailRoutingModule] 12 | }) 13 | export class DetailModule {} 14 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/response-cookies/response-cookies.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-response-cookies', 5 | templateUrl: './response-cookies.component.html', 6 | styleUrls: ['./response-cookies.component.scss'] 7 | }) 8 | export class ResponseCookiesComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/response-headers/response-headers.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-response-headers', 5 | templateUrl: './response-headers.component.html', 6 | styleUrls: ['./response-headers.component.scss'] 7 | }) 8 | export class ResponseHeadersComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /document/docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroText: Gable 4 | tagline: API Collaboration Tools 5 | actionText: Fast On → 6 | actionLink: /guide/ 7 | features: 8 | - title: Open Source 9 | details: Free access to all codes 10 | - title: API Document Design 11 | details: Automatically generate documents and write documents freely 12 | - title: API Test 13 | details: Test HTTP interface, multiple environment management 14 | footer: MIT Licensed | Copyright © 2018-present Evan You 15 | --- 16 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/response-key-value/response-key-value.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-response-key-value', 5 | templateUrl: './response-key-value.component.html', 6 | styleUrls: ['./response-key-value.component.scss'] 7 | }) 8 | export class ResponseKeyValueComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /document/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "doc", 3 | "version": "1.0.0", 4 | "description": "Gable Document", 5 | "main": "index.js", 6 | "repository": "https://github.com/AdvancedProductivity/Gable", 7 | "author": "zzq", 8 | "license": "Apache-2.0 License", 9 | "scripts": { 10 | "docs:dev": "vuepress dev docs", 11 | "docs:build": "vuepress build docs" 12 | }, 13 | "devDependencies": { 14 | "@vuepress/plugin-google-analytics": "^1.9.7", 15 | "vuepress": "^1.9.7" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /client/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | import 'ag-grid-enterprise'; 4 | import { AppModule } from './app/app.module'; 5 | import { APP_CONFIG } from './environments/environment'; 6 | 7 | if (APP_CONFIG.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic() 12 | .bootstrapModule(AppModule, { 13 | preserveWhitespaces: false 14 | }) 15 | .catch(err => console.error(err)); 16 | -------------------------------------------------------------------------------- /document/docs/zh/guide/feature-design.md: -------------------------------------------------------------------------------- 1 | # 功能设计 2 | 3 | ## Pre-Script 4 | 如果您看过 **核心原理** 章节,就可以想到,所谓的预执行脚本,就是通过脚本修改输入的 `Json`。 5 | 6 | 可能会在脚本中执行一些校验的操作。 7 | 8 | 我们计划支持 两种脚本。 9 | 10 | - JS脚本 11 | - Groovy脚本 12 | 13 | ## Post-Script 14 | 如果您看过 **核心原理** 章节,就可以想到,所谓的后执行脚本,就是通过脚本修改输出的 `Json`。 15 | 16 | 可能会在脚本中执行一些对请求结果的校验。 17 | 18 | 我们计划支持 两种脚本。 19 | 20 | - JS脚本 21 | - Groovy脚本 22 | 23 | ## Post-Script-Response 24 | 25 | 展示后执行脚本的测试结果。 26 | 27 | ## Mock 28 | 29 | Mock一个请求,该功能可能只能针对 Http 类型的请求,我们还在思考该功能的设计。 30 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/body-text/body-html/body-html.component.scss: -------------------------------------------------------------------------------- 1 | .body-html-container { 2 | width: 100%; 3 | height: 100%; 4 | display: flex; 5 | flex-direction: row; 6 | 7 | .body-html-content { 8 | width: 100%; 9 | flex: 1; 10 | align-items: stretch; 11 | position: relative; 12 | display: flex; 13 | flex-direction: column; 14 | overflow-y: auto; 15 | border: 1px solid #E6E6E6; 16 | border-radius: 4px; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /client/src/app/shared/icon.ts: -------------------------------------------------------------------------------- 1 | export const iconArray = [ 2 | {name: 'menu-add', file: 'add.svg'} 3 | , {name: 'document', file: 'doc.svg'} 4 | , {name: 'comment', file: 'comment.svg'} 5 | , {name: 'apiSaveAs', file: 'save_api_as.svg'} 6 | , {name: 'api_link', file: 'api_link.svg'} 7 | , {name: 'closeNav', file: 'closeNav.svg'} 8 | , {name: 'copyI', file: 'copyI.svg'} 9 | , {name: 'searchI', file: 'searchI.svg'} 10 | , {name: 'newWork', file: 'newWork.svg'} 11 | , {name: 'editApi', file: 'editApi.svg'} 12 | ]; 13 | 14 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/runner/impl/HttpBodyType.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.runner.impl; 2 | 3 | /** 4 | * @author zzq 5 | */ 6 | public enum HttpBodyType { 7 | 8 | /** 9 | * type none 10 | */ 11 | NONE, 12 | 13 | /** 14 | * type form 15 | */ 16 | FORM_DATA, 17 | 18 | /** 19 | * type url encoded 20 | */ 21 | URLENCODED, 22 | 23 | /** 24 | * raw text 25 | */ 26 | RAW, 27 | 28 | /** 29 | * type graph ql 30 | */ 31 | GRAPHQL, 32 | } 33 | -------------------------------------------------------------------------------- /client/src/app/passport/passport.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import {SharedModule} from '../shared/shared.module'; 4 | import { LoginComponent } from './login/login.component'; 5 | import {PassportRoutingModule} from './passport-routing.module'; 6 | 7 | @NgModule({ 8 | declarations: [ 9 | LoginComponent 10 | ], 11 | imports: [ 12 | CommonModule, 13 | SharedModule, 14 | PassportRoutingModule 15 | ] 16 | }) 17 | export class PassportModule { } 18 | -------------------------------------------------------------------------------- /client/src/app/shared/components/developing/developing.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | {{'MESSAGE.DEVELOPING' | translate}} 4 | {{'OPERATION.COME_ON' | translate}} 5 |
6 |
7 | {{'MESSAGE.FEATURE_HELPER' | translate}} 8 | {{'OPERATION.LEARN_MORE' | translate}} 9 |
10 |
11 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/empty-response/empty-response.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-empty-response', 5 | templateUrl: './empty-response.component.html', 6 | styleUrls: ['./empty-response.component.scss'] 7 | }) 8 | export class EmptyResponseComponent implements OnInit { 9 | @Input() 10 | header: string; 11 | @Input() 12 | tip: string; 13 | constructor() { } 14 | 15 | ngOnInit(): void { 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/runner/impl/HttpResponseField.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.runner.impl; 2 | 3 | /** 4 | * @author zzq 5 | */ 6 | public interface HttpResponseField { 7 | String START_AT = "startAt"; 8 | String END_AT = "endAt"; 9 | String TIME_TAKES = "timeTakes"; 10 | String CONTENT_TYPE = "contentType"; 11 | String CONTENT = "content"; 12 | String SIZE = "size"; 13 | String CODE = "code"; 14 | String MESSAGE = "message"; 15 | String HEADERS = "headers"; 16 | String COOKIE = "cookie"; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /client/src/app/detail/detail-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { Routes, RouterModule } from '@angular/router'; 4 | import { DetailComponent } from './detail.component'; 5 | 6 | const routes: Routes = [ 7 | { 8 | path: 'detail', 9 | component: DetailComponent 10 | } 11 | ]; 12 | 13 | @NgModule({ 14 | declarations: [], 15 | imports: [CommonModule, RouterModule.forChild(routes)], 16 | exports: [RouterModule] 17 | }) 18 | export class DetailRoutingModule {} 19 | -------------------------------------------------------------------------------- /client/src/app/passport/passport-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { Routes, RouterModule } from '@angular/router'; 4 | import {LoginComponent} from './login/login.component'; 5 | 6 | const routes: Routes = [ 7 | { 8 | path: 'login', 9 | component: LoginComponent 10 | } 11 | ]; 12 | 13 | @NgModule({ 14 | declarations: [], 15 | imports: [CommonModule, RouterModule.forChild(routes)], 16 | exports: [RouterModule] 17 | }) 18 | export class PassportRoutingModule {} 19 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/body-text/body-html/body-html.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-body-html', 5 | templateUrl: './body-html.component.html', 6 | styleUrls: ['./body-html.component.scss'] 7 | }) 8 | export class BodyHtmlComponent implements OnInit { 9 | content = ''; 10 | 11 | constructor() { } 12 | 13 | ngOnInit(): void { 14 | } 15 | 16 | public setContent(c: string): void { 17 | this.content = c; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /client/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-electron", 3 | "version": "10.5.2", 4 | "main": "main.js", 5 | "private": true, 6 | "scripts": { 7 | "electron-test": "jest", 8 | "electron-test-coverage": "jest --coverage" 9 | }, 10 | "dependencies": { 11 | "axios": "^0.27.2", 12 | "form-data": "^4.0.0", 13 | "sqlite3": "^5.0.11", 14 | "typeorm": "^0.3.6", 15 | "universal-analytics": "^0.5.3" 16 | }, 17 | "devDependencies": { 18 | "@types/jest": "^28.1.2", 19 | "jest": "^28.1.1", 20 | "ts-jest": "^28.0.5" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/inner/cell-file/cell-file.component.html: -------------------------------------------------------------------------------- 1 |
2 |
{{hintStr}}
3 |
{{cellValue}}
4 |
5 |
6 | 12 |
13 | -------------------------------------------------------------------------------- /client/tsconfig.serve.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "sourceMap": true, 4 | "declaration": false, 5 | "moduleResolution": "node", 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "module": "commonjs", 9 | "target": "es5", 10 | "types": [ 11 | "node" 12 | ], 13 | "lib": [ 14 | "es2017", 15 | "es2016", 16 | "es2015", 17 | "dom" 18 | ] 19 | }, 20 | "files": [ 21 | "app/main.ts" 22 | ], 23 | "exclude": [ 24 | "node_modules", 25 | "**/*.spec.ts" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/GableApplication.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable; 2 | 3 | 4 | import lombok.Generated; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.scheduling.annotation.EnableAsync; 8 | 9 | /** 10 | * @author zzq 11 | */ 12 | @SpringBootApplication 13 | @EnableAsync 14 | public class GableApplication { 15 | 16 | @Generated 17 | public static void main(String[] args) { 18 | SpringApplication.run(GableApplication.class, args); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/api/dao/ApiMenuItemDao.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.api.dao; 2 | 3 | import org.adp.gable.api.entity.ApiMenuItem; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | /** 7 | * @author zzq 8 | */ 9 | public interface ApiMenuItemDao extends JpaRepository { 10 | 11 | /** 12 | * get menu by api id 13 | * 14 | * @param defineId api id 15 | * @return menu 16 | */ 17 | ApiMenuItem findFirstByDefineId(Long defineId); 18 | 19 | Integer countByCollectionId(Long collectionId); 20 | } 21 | -------------------------------------------------------------------------------- /client/src/app/core/services/close-icon-observable.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import {Observable, Subject} from 'rxjs'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class CloseIconObservableService { 8 | private showSubject = new Subject<{ key: string; v: boolean }>(); 9 | constructor() { } 10 | 11 | getShowingStatus(): Observable<{ key: string; v: boolean }> { 12 | return this.showSubject.asObservable(); 13 | } 14 | 15 | public emit(v: { key: string; v: boolean }) { 16 | this.showSubject.next(v); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /document/docs/guide/memory-assistant.md: -------------------------------------------------------------------------------- 1 | # Memory Assistant 2 | 3 | 4 | Waiting for improvement 5 | 6 | 先看中文 7 | 8 | This page is mainly used to help developers quickly check some things, which is not important to non developers. 9 | 10 | ## About PostgreSql 11 | 12 | #### Start 13 | ```shell 14 | pg_ctl start -D ../data -l logfile 15 | ``` 16 | #### login database 17 | ```shell 18 | # psql -U [user name] 19 | 20 | psql -U postgres 21 | ``` 22 | #### show all database 23 | ```shell 24 | \l 25 | ``` 26 | #### select database 27 | ```shell 28 | \c [database name] 29 | 30 | \c gable 31 | ``` 32 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/runner/Action.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.runner; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import com.fasterxml.jackson.databind.node.ObjectNode; 5 | 6 | /** 7 | * @author zzq 8 | */ 9 | public interface Action { 10 | 11 | /** 12 | * execute unit test 13 | * 14 | * @param in in param 15 | * @param out out param 16 | * @param instance instance var 17 | * @param global global var 18 | */ 19 | void execute(JsonNode in, JsonNode out, ObjectNode instance, ObjectNode global); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /server/src/test/java/org/adp/gable/security/PermissionTypeTest.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.security; 2 | 3 | import org.junit.jupiter.api.DisplayName; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import static org.junit.jupiter.api.Assertions.*; 7 | 8 | class PermissionTypeTest { 9 | 10 | @Test 11 | @DisplayName("test load permission enum") 12 | public void testLoadPermissionEnum(){ 13 | assertDoesNotThrow(() -> { 14 | for (PermissionType value : PermissionType.values()) { 15 | assertNotNull(value); 16 | } 17 | }); 18 | } 19 | } -------------------------------------------------------------------------------- /client/src/app/shared/components/api/right-panel/right-panel.component.scss: -------------------------------------------------------------------------------- 1 | .right-panel-container { 2 | width: 100%; 3 | height: 100%; 4 | display: flex; 5 | .left { 6 | width: 32px; 7 | height: 100%; 8 | 9 | .icon-btn { 10 | cursor: pointer; 11 | width: 32px; 12 | height: 32px; 13 | padding-left: 4px; 14 | padding-right: 4px; 15 | margin-top: 10px; 16 | } 17 | } 18 | 19 | .right { 20 | flex: 1; 21 | height: 100%; 22 | 23 | .content { 24 | width: 100%; 25 | height: calc(100% - 44px); 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /.github/workflows/vuepress-deploy.yml: -------------------------------------------------------------------------------- 1 | name: document 2 | on: 3 | push: 4 | branches: 5 | - docs 6 | jobs: 7 | build-and-deploy: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@master 12 | 13 | - name: vuepress-deploy 14 | uses: jenkey2011/vuepress-deploy@master 15 | env: 16 | ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }} 17 | TARGET_REPO: AdvancedProductivity/Gable 18 | TARGET_BRANCH: gh-pages 19 | BUILD_SCRIPT: cd ./document && yarn && yarn docs:build 20 | BUILD_DIR: docs/.vuepress/dist/ -------------------------------------------------------------------------------- /client/app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "module": "es2020", 6 | "sourceMap": true, 7 | "esModuleInterop": true, 8 | "declaration": false, 9 | "moduleResolution": "node", 10 | "emitDecoratorMetadata": true, 11 | "experimentalDecorators": true, 12 | "allowJs": true, 13 | "target": "es5", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2017", 19 | "es2016", 20 | "es2015", 21 | "dom" 22 | ] 23 | }, 24 | "exclude": [ 25 | "node_modules" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/graph-ql/graph-ql.component.scss: -------------------------------------------------------------------------------- 1 | .graph-ql-container { 2 | width: 100%; 3 | height: 100%; 4 | 5 | .text { 6 | padding-left: 10px; 7 | padding-right: 10px; 8 | height: 20px; 9 | width: 100%; 10 | font-size: 11px; 11 | color: #212121; 12 | font-weight: 500; 13 | } 14 | 15 | .mr { 16 | margin-right: 10px; 17 | } 18 | 19 | .ml { 20 | margin-left: 10px; 21 | } 22 | 23 | 24 | .editor-body { 25 | flex: 1; 26 | } 27 | .con-border{ 28 | border: 1px solid #E6E6E6; 29 | border-radius: 4px; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /client/src/assets/svg/save_api_as.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/app/home/home/home.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

5 | {{ 'PAGES.HOME.TITLE' | translate }} 6 |

7 | 8 | {{ 'PAGES.HOME.GO_TO_DETAIL' | translate }} 9 | 10 | 11 |
12 | 13 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/api/dto/http/KeyValueDto.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.api.dto.http; 2 | 3 | import lombok.Data; 4 | import org.apache.commons.lang3.StringUtils; 5 | 6 | import java.beans.Transient; 7 | 8 | /** 9 | * @author zzq 10 | */ 11 | @Data 12 | public class KeyValueDto { 13 | private Boolean using; 14 | private String key; 15 | private String value; 16 | private String desc; 17 | 18 | @Transient 19 | public boolean isNotIgnore() { 20 | if (!using) { 21 | return false; 22 | } 23 | return StringUtils.isNotEmpty(key) || StringUtils.isNotEmpty(value); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/inner/close-input-cell/close-input-cell.component.html: -------------------------------------------------------------------------------- 1 |
4 |
5 | 6 | {{ cellValue }} 7 | 8 | 9 | description 10 | 11 |
12 | 13 |
19 | 20 |
21 |
22 | -------------------------------------------------------------------------------- /client/src/app/shared/components/docs/http-api-doc/http-api-doc.component.scss: -------------------------------------------------------------------------------- 1 | .container-doc-http { 2 | width: 100%; 3 | height: 850px; 4 | display: flex; 5 | border: solid 1px #ddd; 6 | border-radius: 5px; 7 | flex-direction: column; 8 | 9 | .header-select-area { 10 | width: 100%; 11 | height: 50px; 12 | display: flex; 13 | flex-direction: row; 14 | 15 | .sele-c { 16 | margin-left: 10px; 17 | width: 200px; 18 | margin-top: 7px; 19 | } 20 | 21 | .apply-btn { 22 | width: 80px; 23 | margin-top: 7px; 24 | } 25 | } 26 | 27 | .http-area { 28 | flex: 1; 29 | background-color: #FFF; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /document/docs/zh/guide/making-friends.md: -------------------------------------------------------------------------------- 1 | # 交友启事 2 | 3 | 挺喜欢交朋友的,我的微信号:`TEdEODI1OTI0` (需要 base 64 转码) 4 | 5 | 发申请时注意标明: `Gable`。 6 | 7 | 另外,我还是一个自媒体创作者,如果大家喜欢刷B站可以关注我。 8 | 9 | #### 我曾经做过一个视频展示 `Gable` 的用法: 10 | 11 | 12 | 13 | 14 | 15 | #### 我还做过一个视频 `Gable` 的下一步要集中力量要做的事情: 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/security/config/MethodSecurityConfig.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.security.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 5 | import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration; 6 | 7 | /** 8 | * @author zzq 9 | */ 10 | @Configuration 11 | @EnableGlobalMethodSecurity( 12 | prePostEnabled = true, 13 | securedEnabled = true, 14 | jsr250Enabled = true) 15 | public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration { 16 | } 17 | -------------------------------------------------------------------------------- /client/src/app/core/services/impl/electron/http-api-elec-impl.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import {HttpApiHistoryCache} from '../../entity/HttpApi'; 3 | import {Observable} from 'rxjs'; 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class HttpApiElecImplService { 9 | 10 | constructor() { } 11 | 12 | public addApiDefine(data: HttpApiHistoryCache): void { 13 | } 14 | 15 | public updateCache(data: HttpApiHistoryCache): void { 16 | } 17 | 18 | public getCache(id: number): Observable { 19 | return undefined; 20 | } 21 | 22 | public removeCache(id: number): Promise { 23 | return null; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /client/src/assets/svg/copyI.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /client/src/app/core/services/impl/web/web-data.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import {DataService} from '../../DataService'; 3 | import {Observable, of} from 'rxjs'; 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class WebDataService implements DataService{ 8 | 9 | constructor() { } 10 | 11 | clearAll(): Observable { 12 | return of('zzq see get data in web'); 13 | }; 14 | 15 | getData(): Observable { 16 | return of([{id: -1, name: 'zzq see get data in web'}]); 17 | } 18 | 19 | addItem(): Observable { 20 | console.log('run add item in web'); 21 | return of([{id: -1, name: 'zzq see get data in web'}]); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/security/utils/JwtConst.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.security.utils; 2 | 3 | import java.nio.charset.StandardCharsets; 4 | import java.util.UUID; 5 | 6 | /** 7 | * @author zzq 8 | */ 9 | public interface JwtConst { 10 | String TOKEN_HEADER = "Authorization"; 11 | String TOKEN_PREFIX = "Bearer "; 12 | byte[] SECURITY_ARRAY = UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8); 13 | long ONLINE_TIME = 1000L * 60 * 60 * 21 * 10; 14 | String ISSUER_PREFIX = "Gable Server---"; 15 | 16 | String CLAIM_KEY = "user"; 17 | String AUTH = "authorities"; 18 | String ROLE_PREFIX = "ROLE_"; 19 | String LOGIN_PATH = "/api/user/login"; 20 | } 21 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/common/web/SampleResultCode.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.common.web; 2 | 3 | /** 4 | * @author zzq 5 | */ 6 | public class SampleResultCode implements ErrorResult { 7 | 8 | private final int errorCode; 9 | private final String errorMessageI18nKey; 10 | 11 | 12 | public SampleResultCode(int errorCode, String errorMessageI18nKey) { 13 | this.errorCode = errorCode; 14 | this.errorMessageI18nKey = errorMessageI18nKey; 15 | } 16 | 17 | @Override 18 | public int getErrorCode() { 19 | return errorCode; 20 | } 21 | 22 | @Override 23 | public String getMessageI18nKey() { 24 | return errorMessageI18nKey; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /server/src/main/resources/application-postgresql.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | servlet: 3 | multipart: 4 | max-request-size: 100MB 5 | max-file-size: 100MB 6 | datasource: 7 | url: jdbc:postgresql://localhost:5432/gable 8 | username: app 9 | password: 12345678 10 | driver-class-name: org.postgresql.Driver 11 | jpa: 12 | hibernate: 13 | ddl-auto: none 14 | show-sql: true 15 | properties: 16 | hibernate: 17 | dialect: org.hibernate.dialect.PostgreSQLDialect 18 | format_sql: true 19 | open-in-view: false 20 | flyway: 21 | enabled: true 22 | locations: classpath:db/migration/{vendor} 23 | local: 24 | filepath: ${user.home}/.gable/resource/ 25 | server: 26 | port: 2208 -------------------------------------------------------------------------------- /client/src/app/home/doc-page/doc-dash-board/doc-create-dialog/doc-create-dialog.component.html: -------------------------------------------------------------------------------- 1 |

2 | {{ 'PAGES.DOCS.CREATE' | translate }} 3 |

4 |
5 | 6 | 7 | {{ 'PAGES.DOCS.DOC_NAME' | translate }} 8 | 9 | 10 | 11 |
12 |
13 | 16 | 19 |
20 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/api/dto/http/FormKeyValueDto.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.api.dto.http; 2 | 3 | import lombok.Data; 4 | import org.apache.commons.lang3.StringUtils; 5 | 6 | import java.beans.Transient; 7 | 8 | /** 9 | * @author zzq 10 | */ 11 | @Data 12 | public class FormKeyValueDto extends KeyValueDto { 13 | private String type; 14 | private String fileName; 15 | private String filePath; 16 | private String fileUrl; 17 | private String fileId; 18 | 19 | @Override 20 | @Transient 21 | public boolean isNotIgnore() { 22 | if (!getUsing()) { 23 | return false; 24 | } 25 | return StringUtils.isNotEmpty(getKey()) || StringUtils.isNotEmpty(getFilePath()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /client/src/app/home/diff/diff.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DiffComponent } from './diff.component'; 4 | 5 | describe('DiffComponent', () => { 6 | let component: DiffComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ DiffComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(DiffComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/nav/nav.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { NavComponent } from './nav.component'; 4 | 5 | describe('NavComponent', () => { 6 | let component: NavComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ NavComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(NavComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/passport/login/login.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LoginComponent } from './login.component'; 4 | 5 | describe('LoginComponent', () => { 6 | let component: LoginComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ LoginComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LoginComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/home/api-test/api-test.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 8 |

9 | {{ 'PAGES.API_TEST.TREE_MENU.LOAD_MENU' | translate }} 10 |

11 |
12 | 15 | 16 |
17 | 18 |
19 | 20 | 21 |
22 | 23 |
24 |
25 |
26 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/utils/BeanUtils.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.utils; 2 | 3 | import org.springframework.beans.BeanWrapper; 4 | import org.springframework.beans.BeanWrapperImpl; 5 | 6 | import java.beans.FeatureDescriptor; 7 | import java.util.stream.Stream; 8 | 9 | /** 10 | * @author zzq 11 | */ 12 | public class BeanUtils { 13 | 14 | public static String[] getNullPropertyNames(Object source) { 15 | final BeanWrapper wrappedSource = new BeanWrapperImpl(source); 16 | return Stream.of(wrappedSource.getPropertyDescriptors()) 17 | .map(FeatureDescriptor::getName) 18 | .filter(propertyName -> wrappedSource.getPropertyValue(propertyName) == null) 19 | .toArray(String[]::new); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/text-body/text-body.component.html: -------------------------------------------------------------------------------- 1 |
2 | 6 | 7 | 12 | 13 | 14 | 19 | 22 | 23 | 24 |
25 | -------------------------------------------------------------------------------- /client/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting(), { 16 | teardown: { destroyAfterEach: false } 17 | } 18 | ); 19 | // Then we find all the tests. 20 | const context = require.context('./', true, /\.spec\.ts$/); 21 | // And load the modules. 22 | context.keys().map(context); 23 | -------------------------------------------------------------------------------- /server/src/main/resources/application-h2.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | servlet: 3 | multipart: 4 | max-request-size: 100MB 5 | max-file-size: 100MB 6 | datasource: 7 | url: jdbc:h2:file:${user.home}/.gable/gable-server;DB_CLOSE_ON_EXIT=FALSE;IFEXISTS=FALSE;DB_CLOSE_DELAY=-1; 8 | username: app 9 | password: 12345678 10 | driver-class-name: org.h2.Driver 11 | jpa: 12 | hibernate: 13 | ddl-auto: none 14 | show-sql: true 15 | properties: 16 | hibernate: 17 | dialect: org.hibernate.dialect.H2Dialect 18 | format_sql: true 19 | open-in-view: false 20 | flyway: 21 | enabled: true 22 | locations: classpath:db/migration/{vendor} 23 | local: 24 | filepath: ${user.home}/.gable/resource/ 25 | 26 | server: 27 | port: 2208 -------------------------------------------------------------------------------- /client/src/app/home/setting/setting.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SettingComponent } from './setting.component'; 4 | 5 | describe('SettingComponent', () => { 6 | let component: SettingComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ SettingComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SettingComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/home/api-test/api-test.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ApiTestComponent } from './api-test.component'; 4 | 5 | describe('ApiTestComponent', () => { 6 | let component: ApiTestComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ ApiTestComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ApiTestComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/home/diff/diff.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 |
14 | -------------------------------------------------------------------------------- /client/src/app/home/doc-page/doc-page.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DocPageComponent } from './doc-page.component'; 4 | 5 | describe('DocPageComponent', () => { 6 | let component: DocPageComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ DocPageComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(DocPageComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/assets/svg/editApi.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /client/src/app/home/mock-page/mock-page.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { MockPageComponent } from './mock-page.component'; 4 | 5 | describe('MockPageComponent', () => { 6 | let component: MockPageComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ MockPageComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(MockPageComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/inner/cell-file-text/cell-file-text.component.html: -------------------------------------------------------------------------------- 1 |
5 |
6 |
{{hintStr}}
7 |
{{cellValue}}
8 |
9 |
13 | 21 |
22 |
23 | -------------------------------------------------------------------------------- /client/src/app/home/doc-page/doc-dash-board/doc-create-dialog/doc-create-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Inject, OnInit} from '@angular/core'; 2 | import {DocDashBoardComponent} from '../doc-dash-board.component'; 3 | import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; 4 | 5 | @Component({ 6 | selector: 'app-doc-create-dialog', 7 | templateUrl: './doc-create-dialog.component.html', 8 | styleUrls: ['./doc-create-dialog.component.scss'] 9 | }) 10 | export class DocCreateDialogComponent implements OnInit { 11 | newName = ''; 12 | constructor( 13 | public dialogRef: MatDialogRef 14 | ) {} 15 | 16 | onNoClick(): void { 17 | this.dialogRef.close(); 18 | } 19 | 20 | ngOnInit(): void { 21 | this.newName = ''; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/security/dao/RoleRepository.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.security.dao; 2 | 3 | import org.adp.gable.security.entity.RoleEntity; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.Query; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * @author zzq 11 | */ 12 | public interface RoleRepository extends JpaRepository { 13 | 14 | /** 15 | * get all roles by user's id 16 | * 17 | * @param userId 18 | * @return role collections 19 | */ 20 | @Query(value = "SELECT sr.* FROM sec_role_user_relation srur left join sec_role sr on sr.id = srur.role_id where user_id = ?1", nativeQuery = true) 21 | List getRoleByUserId(Long userId); 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /client/src/app/shared/components/docs/i18n-title/i18n-title.component.scss: -------------------------------------------------------------------------------- 1 | .i18n-doc-container { 2 | width: 100%; 3 | background-color: #fff; 4 | display: flex; 5 | flex-direction: column; 6 | margin-left: 10px; 7 | 8 | .i18n-doc-opera-bar { 9 | width: 100%; 10 | height: 38px; 11 | display: flex; 12 | flex-direction: row; 13 | border-bottom: 1px solid #bbb; 14 | margin-bottom: 10px; 15 | 16 | .left-select { 17 | flex: 1; 18 | height: 100%; 19 | } 20 | .i18n-doc-btn { 21 | width: 80px; 22 | height: 100%; 23 | text-align: center; 24 | margin-top: 4px; 25 | } 26 | } 27 | 28 | .i18n-t-doc-content { 29 | width: 100%; 30 | 31 | h3 { 32 | margin-top: 8px; 33 | margin-bottom: 8px; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /client/src/app/home/doc-page/doc-detail/doc-detail.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DocDetailComponent } from './doc-detail.component'; 4 | 5 | describe('DocDetailComponent', () => { 6 | let component: DocDetailComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ DocDetailComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(DocDetailComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/home/doc-page/doc-editor/doc-editor.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DocEditorComponent } from './doc-editor.component'; 4 | 5 | describe('DocEditorComponent', () => { 6 | let component: DocEditorComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ DocEditorComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(DocEditorComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /server/src/main/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | # copy from h2 config 2 | spring: 3 | servlet: 4 | multipart: 5 | max-request-size: 100MB 6 | max-file-size: 100MB 7 | datasource: 8 | url: jdbc:h2:file:${user.home}/.gable/gable-server-test;DB_CLOSE_ON_EXIT=FALSE;IFEXISTS=FALSE;DB_CLOSE_DELAY=-1; 9 | username: app 10 | password: 12345678 11 | driver-class-name: org.h2.Driver 12 | jpa: 13 | hibernate: 14 | ddl-auto: none 15 | show-sql: true 16 | properties: 17 | hibernate: 18 | dialect: org.hibernate.dialect.H2Dialect 19 | format_sql: true 20 | open-in-view: false 21 | flyway: 22 | enabled: true 23 | locations: classpath:db/migration/{vendor} 24 | local: 25 | filepath: ${user.home}/.gable/resource/ 26 | 27 | server: 28 | port: 2208 -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/inner/close-input-cell/close-input-cell.component.scss: -------------------------------------------------------------------------------- 1 | 2 | .cell-container { 3 | width: 100%; 4 | height: 100%; 5 | position: relative; 6 | 7 | .cell-content { 8 | width: 100%; 9 | height: 100%; 10 | 11 | .cell-hint { 12 | color: #A6A6A6; 13 | } 14 | } 15 | 16 | 17 | .input-con-cell:hover { 18 | cursor: pointer; 19 | background-color: rgba(0, 0, 0, 0.2); 20 | } 21 | 22 | .input-con-cell { 23 | position: absolute; 24 | right: 10px; 25 | top: 8px; 26 | width: 20px; 27 | height: 20px; 28 | line-height: 20px; 29 | color: #000; 30 | align-content: center; 31 | 32 | .input-con-cell-icon { 33 | width: 20px; 34 | height: 20px; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/json-table-editor/json-table-editor.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
7 | 22 |
23 |
24 | -------------------------------------------------------------------------------- /client/src/app/shared/components/developing/developing.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DevelopingComponent } from './developing.component'; 4 | 5 | describe('DevelopingComponent', () => { 6 | let component: DevelopingComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ DevelopingComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(DevelopingComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/docs/i18n-title/i18n-title.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { I18nTitleComponent } from './i18n-title.component'; 4 | 5 | describe('I18nTitleComponent', () => { 6 | let component: I18nTitleComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ I18nTitleComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(I18nTitleComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /document/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events*.json 15 | 16 | # IDEs and editors 17 | /.idea 18 | .project 19 | .classpath 20 | .c9/ 21 | *.launch 22 | .settings/ 23 | *.sublime-workspace 24 | 25 | # IDE - VSCode 26 | .vscode/* 27 | !.vscode/settings.json 28 | !.vscode/tasks.json 29 | !.vscode/launch.json 30 | !.vscode/extensions.json 31 | .history/* 32 | 33 | # misc 34 | /.sass-cache 35 | /connect.lock 36 | /coverage 37 | /libpeerconnection.log 38 | npm-debug.log 39 | yarn-error.log 40 | testem.log 41 | /typings 42 | 43 | # System Files 44 | .DS_Store 45 | Thumbs.db 46 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/right-panel/right-panel.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RightPanelComponent } from './right-panel.component'; 4 | 5 | describe('RightPanelComponent', () => { 6 | let component: RightPanelComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ RightPanelComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RightPanelComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/docs/http-api-doc/http-api-doc.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HttpApiDocComponent } from './http-api-doc.component'; 4 | 5 | describe('HttpApiDocComponent', () => { 6 | let component: HttpApiDocComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ HttpApiDocComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(HttpApiDocComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/docs/http-url-doc/http-url-doc.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HttpUrlDocComponent } from './http-url-doc.component'; 4 | 5 | describe('HttpUrlDocComponent', () => { 6 | let component: HttpUrlDocComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ HttpUrlDocComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(HttpUrlDocComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/docs/raw-text-doc/raw-text-doc.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RawTextDocComponent } from './raw-text-doc.component'; 4 | 5 | describe('RawTextDocComponent', () => { 6 | let component: RawTextDocComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ RawTextDocComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RawTextDocComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/app/src/entity/ApiMenuCollection.ts: -------------------------------------------------------------------------------- 1 | import {Column, Entity, PrimaryGeneratedColumn} from "typeorm"; 2 | 3 | @Entity('api_menu_collection') 4 | export class ApiMenuCollection { 5 | 6 | @PrimaryGeneratedColumn() 7 | id: number; 8 | 9 | @Column({ 10 | length: 255 11 | }) 12 | name: string; 13 | 14 | @Column({ 15 | length: 16 16 | }) 17 | type: string; 18 | 19 | @Column({type: 'int', nullable: true}) 20 | apiCount: number; 21 | } 22 | 23 | 24 | @Entity('api_menu_item') 25 | export class ApiMenuItem extends ApiMenuCollection { 26 | 27 | @Column({ 28 | length: 16 29 | }) 30 | tag: string; 31 | 32 | @Column({type: 'bigint'}) 33 | version: number; 34 | 35 | @Column({type: 'bigint'}) 36 | collectionId: number; 37 | 38 | @Column({type: 'bigint'}) 39 | defineId: number; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /client/src/app/home/doc-page/doc-dash-board/doc-dash-board.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DocDashBoardComponent } from './doc-dash-board.component'; 4 | 5 | describe('DocDashBoardComponent', () => { 6 | let component: DocDashBoardComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ DocDashBoardComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(DocDashBoardComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/api-tree-menu/api-tree-menu.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ApiTreeMenuComponent } from './api-tree-menu.component'; 4 | 5 | describe('ApiTreeMenuComponent', () => { 6 | let component: ApiTreeMenuComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ ApiTreeMenuComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ApiTreeMenuComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/api-tree-menu/inner/empty-tree/empty-tree.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { EmptyTreeComponent } from './empty-tree.component'; 4 | 5 | describe('EmptyTreeComponent', () => { 6 | let component: EmptyTreeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ EmptyTreeComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(EmptyTreeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/graph-ql/graph-ql.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { GraphQLComponent } from './graph-ql.component'; 4 | 5 | describe('GraphQLComponent', () => { 6 | let component: GraphQLComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ GraphQLComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(GraphQLComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/electron-builder.json: -------------------------------------------------------------------------------- 1 | { 2 | "asar": false, 3 | "directories": { 4 | "output": "release/" 5 | }, 6 | "files": [ 7 | "**/*", 8 | "!**/*.ts", 9 | "!*.map", 10 | "!package.json", 11 | "!package-lock.json" 12 | ], 13 | "extraResources": [ 14 | { 15 | "from": "dist", 16 | "to": "app", 17 | "filter": [ 18 | "**/*" 19 | ] 20 | } 21 | ], 22 | "win": { 23 | "icon": "dist/assets/icons", 24 | "target": [ 25 | "portable" 26 | ] 27 | }, 28 | "portable": { 29 | "splashImage": "dist/assets/icons/electron.bmp" 30 | }, 31 | "mac": { 32 | "icon": "dist/assets/icons", 33 | "target": [ 34 | "dmg" 35 | ] 36 | }, 37 | "linux": { 38 | "icon": "dist/assets/icons", 39 | "target": [ 40 | "AppImage" 41 | ] 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /client/src/app/home/doc-page/doc-detail/doc-menu-tree/doc-menu-tree.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DocMenuTreeComponent } from './doc-menu-tree.component'; 4 | 5 | describe('DocMenuTreeComponent', () => { 6 | let component: DocMenuTreeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ DocMenuTreeComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(DocMenuTreeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/none-body/none-body.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { NoneBodyComponent } from './none-body.component'; 4 | 5 | describe('NoneBodyComponent', () => { 6 | let component: NoneBodyComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ NoneBodyComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(NoneBodyComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/text-body/text-body.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { TextBodyComponent } from './text-body.component'; 4 | 5 | describe('TextBodyComponent', () => { 6 | let component: TextBodyComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ TextBodyComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(TextBodyComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/body-text/body-text.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { BodyTextComponent } from './body-text.component'; 4 | 5 | describe('BodyTextComponent', () => { 6 | let component: BodyTextComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ BodyTextComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(BodyTextComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/test-dashboard/test-dashboard.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { TestDashboardComponent } from './test-dashboard.component'; 4 | 5 | describe('TestDashboardComponent', () => { 6 | let component: TestDashboardComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ TestDashboardComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(TestDashboardComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/inner/cell-file/cell-file.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CellFileComponent } from './cell-file.component'; 4 | 5 | describe('CellFileComponent', () => { 6 | let component: CellFileComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ CellFileComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CellFileComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/body-text/body-html/body-html.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { BodyHtmlComponent } from './body-html.component'; 4 | 5 | describe('BodyHtmlComponent', () => { 6 | let component: BodyHtmlComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ BodyHtmlComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(BodyHtmlComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/page-not-found/page-not-found.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import { PageNotFoundComponent } from './page-not-found.component'; 4 | 5 | describe('PageNotFoundComponent', () => { 6 | let component: PageNotFoundComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [PageNotFoundComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PageNotFoundComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/request-tabs.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RequestTabsComponent } from './request-tabs.component'; 4 | 5 | describe('RequestTabsComponent', () => { 6 | let component: RequestTabsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ RequestTabsComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RequestTabsComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/home/doc-page/doc-detail/doc-detail.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import {ActivatedRoute, ParamMap, Router} from '@angular/router'; 3 | import {BrowserOpenService} from '../../../core/services/browser-open.service'; 4 | 5 | @Component({ 6 | selector: 'app-doc-detail', 7 | templateUrl: './doc-detail.component.html', 8 | styleUrls: ['./doc-detail.component.scss'] 9 | }) 10 | export class DocDetailComponent implements OnInit { 11 | docId: number; 12 | showing: number; 13 | isEdit = false; 14 | constructor( 15 | private route: ActivatedRoute, 16 | public browserOpenService: BrowserOpenService, 17 | private router: Router 18 | ) { } 19 | 20 | ngOnInit(): void { 21 | this.route.paramMap.subscribe((res: ParamMap) => { 22 | this.docId = Number(res.get('docId')); 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/http-work-bench.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HttpWorkBenchComponent } from './http-work-bench.component'; 4 | 5 | describe('HttpWorkBenchComponent', () => { 6 | let component: HttpWorkBenchComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ HttpWorkBenchComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(HttpWorkBenchComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/form-editor/form-editor.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FormEditorComponent } from './form-editor.component'; 4 | 5 | describe('FormEditorComponent', () => { 6 | let component: FormEditorComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ FormEditorComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(FormEditorComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/query-table/query-table.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { QueryTableComponent } from './query-table.component'; 4 | 5 | describe('QueryTableComponent', () => { 6 | let component: QueryTableComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ QueryTableComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(QueryTableComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, waitForAsync } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | import { TranslateModule } from '@ngx-translate/core'; 5 | import { ElectronService } from './core/services'; 6 | 7 | describe('AppComponent', () => { 8 | beforeEach(waitForAsync(() => { 9 | TestBed.configureTestingModule({ 10 | declarations: [AppComponent], 11 | providers: [ElectronService], 12 | imports: [RouterTestingModule, TranslateModule.forRoot()] 13 | }).compileComponents(); 14 | })); 15 | 16 | it('should create the app', waitForAsync(() => { 17 | const fixture = TestBed.createComponent(AppComponent); 18 | const app = fixture.debugElement.componentInstance; 19 | expect(app).toBeTruthy(); 20 | })); 21 | }); 22 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/response-tabs.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ResponseTabsComponent } from './response-tabs.component'; 4 | 5 | describe('ResponseTabsComponent', () => { 6 | let component: ResponseTabsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ ResponseTabsComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ResponseTabsComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/home/doc-page/doc-dash-board/doc-create-dialog/doc-create-dialog.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DocCreateDialogComponent } from './doc-create-dialog.component'; 4 | 5 | describe('DocCreateDialogComponent', () => { 6 | let component: DocCreateDialogComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ DocCreateDialogComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(DocCreateDialogComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/inner/cell-content/cell-content.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CellContentComponent } from './cell-content.component'; 4 | 5 | describe('CellContentComponent', () => { 6 | let component: CellContentComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ CellContentComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CellContentComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/right-panel/right-panel.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 | 8 |
9 |
10 | 11 |
12 |
13 |
14 | 17 |
18 |
19 |
20 | 24 | 25 |
26 |
27 |
28 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/body-container/body-container.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { BodyContainerComponent } from './body-container.component'; 4 | 5 | describe('BodyContainerComponent', () => { 6 | let component: BodyContainerComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ BodyContainerComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(BodyContainerComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/inner/cell-file-text/cell-file-text.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CellFileTextComponent } from './cell-file-text.component'; 4 | 5 | describe('CellFileTextComponent', () => { 6 | let component: CellFileTextComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ CellFileTextComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CellFileTextComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/inner/check-box-cell/check-box-cell.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CheckBoxCellComponent } from './check-box-cell.component'; 4 | 5 | describe('CheckBoxCellComponent', () => { 6 | let component: CheckBoxCellComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ CheckBoxCellComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CheckBoxCellComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/empty-response/empty-response.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { EmptyResponseComponent } from './empty-response.component'; 4 | 5 | describe('EmptyResponseComponent', () => { 6 | let component: EmptyResponseComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ EmptyResponseComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(EmptyResponseComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/tree-data-editor/tree-data-editor.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { TreeDataEditorComponent } from './tree-data-editor.component'; 4 | 5 | describe('TreeDataEditorComponent', () => { 6 | let component: TreeDataEditorComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ TreeDataEditorComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(TreeDataEditorComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/security/dao/RolePermissionRepository.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.security.dao; 2 | 3 | import org.adp.gable.security.entity.RolePermissionRelation; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.Query; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * @author zzq 11 | */ 12 | public interface RolePermissionRepository extends JpaRepository { 13 | 14 | /** 15 | * get all role’s permission code 16 | * 17 | * @param roleIds role collections 18 | * @return all permission code 19 | * */ 20 | @Query(value = "SELECT srpr.permission_code FROM sec_role_permission_relation srpr left join sec_role sr on srpr.role_id = sr.id where sr.id IN ?1", nativeQuery = true) 21 | List getPermissionsByRoleIds(List roleIds); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /client/src/assets/svg/api_link.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /server/src/test/java/org/adp/gable/utils/ResultUtils.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.utils; 2 | 3 | import com.fasterxml.jackson.core.type.TypeReference; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import org.adp.gable.common.beans.Result; 6 | import org.springframework.test.web.servlet.MvcResult; 7 | 8 | import java.io.IOException; 9 | 10 | public class ResultUtils { 11 | 12 | private static ObjectMapper MAPPER = new ObjectMapper(); 13 | 14 | public static Result readResult(MvcResult res, ObjectMapper objectMapper) throws IOException { 15 | return objectMapper.readValue(res.getResponse().getContentAsByteArray(), 16 | new TypeReference>() { 17 | } 18 | ); 19 | } 20 | 21 | public static Result readResult(MvcResult res) throws IOException { 22 | return readResult(res, MAPPER); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/api-header-operation/api-header-operation.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ApiHeaderOperationComponent } from './api-header-operation.component'; 4 | 5 | describe('ApiHeaderOperationComponent', () => { 6 | let component: ApiHeaderOperationComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ ApiHeaderOperationComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ApiHeaderOperationComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/json-table-editor/json-table-editor.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { JsonTableEditorComponent } from './json-table-editor.component'; 4 | 5 | describe('JsonTableEditorComponent', () => { 6 | let component: JsonTableEditorComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ JsonTableEditorComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(JsonTableEditorComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/form-editor/form-editor.component.html: -------------------------------------------------------------------------------- 1 |
2 | 21 | 22 |
23 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/query-table/query-table.component.html: -------------------------------------------------------------------------------- 1 |
2 | 21 | 22 |
23 | -------------------------------------------------------------------------------- /client/src/app/shared/components/docs/i18n-title/i18n-title.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; 2 | import {I18nDocNode} from '../../../../core/services/entity/Docs'; 3 | 4 | @Component({ 5 | selector: 'app-i18n-title', 6 | templateUrl: './i18n-title.component.html', 7 | styleUrls: ['./i18n-title.component.scss'] 8 | }) 9 | export class I18nTitleComponent implements OnInit, OnChanges { 10 | @Input() data: I18nDocNode; 11 | @Input() readonly = false; 12 | 13 | constructor() { } 14 | 15 | @Input() get getData(): any { 16 | return this.data; 17 | } 18 | 19 | ngOnInit(): void { 20 | if (!this.data || !this.data.i18n) { 21 | this.data = new I18nDocNode(); 22 | this.data.i18n = 'PAGES.DOCS.DOC_URL'; 23 | this.data.level = 3; 24 | } 25 | } 26 | 27 | ngOnChanges(changes: SimpleChanges): void { 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/inner/close-input-cell/close-input-cell.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CloseInputCellComponent } from './close-input-cell.component'; 4 | 5 | describe('CloseInputCellComponent', () => { 6 | let component: CloseInputCellComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ CloseInputCellComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CloseInputCellComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/response-cookies/response-cookies.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ResponseCookiesComponent } from './response-cookies.component'; 4 | 5 | describe('ResponseCookiesComponent', () => { 6 | let component: ResponseCookiesComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ ResponseCookiesComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ResponseCookiesComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/response-headers/response-headers.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ResponseHeadersComponent } from './response-headers.component'; 4 | 5 | describe('ResponseHeadersComponent', () => { 6 | let component: ResponseHeadersComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ ResponseHeadersComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ResponseHeadersComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/security/utils/SecurityErrorResult.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.security.utils; 2 | 3 | import org.adp.gable.common.web.ErrorResult; 4 | import org.adp.gable.common.web.SampleResultCode; 5 | 6 | /** 7 | * @author zzq 8 | */ 9 | public interface SecurityErrorResult { 10 | 11 | ErrorResult USER_NOT_EXIST = new SampleResultCode(200, "SEC.USER_NOT_EXIST"); 12 | ErrorResult PASSWORD_ERROR = new SampleResultCode(300, "SEC.PASSWORD_ERROR"); 13 | ErrorResult LOGIN_EXPIRED = new SampleResultCode(400, "SEC.LOGIN_EXPIRED"); 14 | ErrorResult ACCESS_DENIED = new SampleResultCode(403, "SEC.ACCESS_DENIED"); 15 | ErrorResult NO_TOKEN_PROVIDED = new SampleResultCode(405, "SEC.NO_TOKEN_PROVIDED"); 16 | ErrorResult TOKEN_INVALID = new SampleResultCode(406, "SEC.TOKEN_INVALID"); 17 | ErrorResult JWT_UNKNOWN_ERROR = new SampleResultCode(407, "SEC.JWT_UNKNOWN_ERROR"); 18 | } 19 | -------------------------------------------------------------------------------- /client/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | /app-builds 8 | /release 9 | main.js 10 | src/**/*.js 11 | !src/karma.conf.js 12 | *.js.map 13 | 14 | # dependencies 15 | node_modules 16 | 17 | # IDEs and editors 18 | .idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | .vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | 33 | # misc 34 | /.angular/cache 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /app/coverage 39 | /libpeerconnection.log 40 | npm-debug.log 41 | testem.log 42 | /typings 43 | 44 | # e2e 45 | /e2e/*.js 46 | !/e2e/protractor.conf.js 47 | /e2e/*.map 48 | /e2e/tracing 49 | /e2e/screenshots 50 | 51 | # System Files 52 | .DS_Store 53 | Thumbs.db 54 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/collection-work-bench/collection-work-bench.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CollectionWorkBenchComponent } from './collection-work-bench.component'; 4 | 5 | describe('CollectionWorkBenchComponent', () => { 6 | let component: CollectionWorkBenchComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ CollectionWorkBenchComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CollectionWorkBenchComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/response-key-value/response-key-value.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ResponseKeyValueComponent } from './response-key-value.component'; 4 | 5 | describe('ResponseKeyValueComponent', () => { 6 | let component: ResponseKeyValueComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ ResponseKeyValueComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ResponseKeyValueComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/src/app/core/services/browser-open.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import {ElectronService} from './electron/electron.service'; 3 | import {TranslateService} from '@ngx-translate/core'; 4 | import {AnalysisService} from './analysis.service'; 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class BrowserOpenService { 10 | 11 | constructor( 12 | private electronService: ElectronService, 13 | private analysisService: AnalysisService, 14 | private trans: TranslateService 15 | ) { 16 | } 17 | 18 | public open(url: string) { 19 | this.trans.get([url]).subscribe(msg => { 20 | const u = msg[url]; 21 | this.analysisService.openLink(u).then(r => {}); 22 | if (this.electronService.isElectron) { 23 | this.electronService.ipcRenderer.sendSync('openBrowser', u); 24 | } else { 25 | window.open(u, '_blank'); 26 | } 27 | }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/inner/check-box-cell-editor/check-box-cell-editor.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CheckBoxCellEditorComponent } from './check-box-cell-editor.component'; 4 | 5 | describe('CheckBoxCellEditorComponent', () => { 6 | let component: CheckBoxCellEditorComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ CheckBoxCellEditorComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CheckBoxCellEditorComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "module": "es2020", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "allowJs": true, 12 | "target": "es5", 13 | "typeRoots": [ 14 | "node_modules/@types" 15 | ], 16 | "lib": [ 17 | "es2017", 18 | "es2016", 19 | "es2015", 20 | "dom" 21 | ] 22 | }, 23 | "exclude": [ 24 | "node_modules" 25 | ], 26 | "angularCompilerOptions": { 27 | "strictTemplates": true, 28 | "fullTemplateTypeCheck": true, 29 | "annotateForClosureCompiler": true, 30 | "strictInjectionParameters": true, 31 | "skipTemplateCodegen": false, 32 | "preserveWhitespaces": true, 33 | "skipMetadataEmit": false, 34 | "disableTypeScriptVersionCheck": true 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/api/dto/http/DocJsonNode.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.api.dto.http; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.Collections; 6 | import java.util.List; 7 | 8 | /** 9 | * @author zzq 10 | */ 11 | @Data 12 | public class DocJsonNode { 13 | private String id; 14 | private Boolean canDelete; 15 | private Boolean canEditName; 16 | private Integer level; 17 | private String name; 18 | private String type; 19 | private String desc; 20 | private Object sample; 21 | private List children; 22 | 23 | public static DocJsonNode getRoot() { 24 | DocJsonNode root= new DocJsonNode(); 25 | root.canDelete = false; 26 | root.type = "object"; 27 | root.children = Collections.emptyList(); 28 | root.canEditName = false; 29 | root.level = 0; 30 | root.name = "root"; 31 | root.sample = ""; 32 | return root; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /document/docs/guide/getting-started.md: -------------------------------------------------------------------------------- 1 | # Get Started 2 | 3 | Waiting for improvement 4 | 5 | 先看中文 6 | 7 | Before the `Gable` starts, you need to prepare the environment. 8 | `Gable` does not have too many requirements for the running machine. It only needs to install a jdk8 environment. 9 | 10 | 11 | ## Database 12 | 13 | 14 | `Gable` is developed based on the popular `Postgresql` by default,Therefore, before running the program, you need to prepare the database related environment. 15 | 16 | Execute the following `sql`: 17 | ```sql 18 | -- Create a database named app 19 | create database gable with owner postgres; 20 | 21 | -- Create an account and password to connect to the database 22 | -- (corresponding to the configuration in the code) 23 | create user app with password '12345678'; 24 | 25 | -- Assign access 26 | grant connect, create, temporary on database gable to app; 27 | 28 | ``` 29 | As for other database tables and indexes, they will be created automatically when the program starts. 30 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/common/handler/CustomExceptionResolver.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.common.handler; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.adp.gable.common.beans.Result; 5 | import org.adp.gable.common.web.CommonErrorResult; 6 | import org.springframework.web.bind.annotation.ControllerAdvice; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | import org.springframework.web.bind.annotation.ResponseBody; 9 | import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; 10 | 11 | /** 12 | * @author zzq 13 | */ 14 | @ControllerAdvice 15 | @Slf4j 16 | public class CustomExceptionResolver extends ResponseEntityExceptionHandler { 17 | 18 | @ExceptionHandler(value = NullPointerException.class) 19 | @ResponseBody 20 | public Result handleAuthenticationError(Exception e) { 21 | log.error("NPE error happens", e); 22 | return Result.failure(CommonErrorResult.SYSTEM_NPE_ERROR); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/common/web/SpringContextHolder.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.common.web; 2 | 3 | import org.springframework.beans.factory.DisposableBean; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.context.ApplicationContextAware; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * @author zzq 10 | */ 11 | @Component 12 | public class SpringContextHolder implements ApplicationContextAware, DisposableBean { 13 | 14 | private static ApplicationContext applicationContext = null; 15 | 16 | public static ApplicationContext getApplicationContext() { 17 | return applicationContext; 18 | } 19 | 20 | @Override 21 | public void setApplicationContext(ApplicationContext applicationContext) { 22 | SpringContextHolder.applicationContext = applicationContext; 23 | } 24 | 25 | @Override 26 | public void destroy() throws Exception { 27 | applicationContext = null; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /client/src/app/home/api-test/api-test.component.scss: -------------------------------------------------------------------------------- 1 | .api-container { 2 | display: flex; 3 | flex-direction: row; 4 | width: 100%; 5 | height: 100%; 6 | max-height: 100%; 7 | max-width: 100%; 8 | 9 | .left { 10 | max-width: 300px; 11 | min-width: 300px; 12 | position: relative; 13 | width: 300px; 14 | } 15 | 16 | .loading-container { 17 | height: 100%; 18 | width: 100%; 19 | position: absolute; 20 | } 21 | 22 | .right { 23 | border-right-color: #bbb; 24 | border-right-width: 1px; 25 | border-right-style: solid; 26 | flex: 1 1 auto; 27 | width: 0; 28 | min-height: 0; 29 | 30 | .main-test { 31 | height: calc(100% - 50px); 32 | width: 100%; 33 | } 34 | } 35 | } 36 | .tree { 37 | padding: 3px; 38 | background-color: beige; 39 | } 40 | 41 | .main { 42 | padding: 33px; 43 | background-color: cadetblue; 44 | } 45 | 46 | .loading{ 47 | color: white; 48 | padding-top: 50px; 49 | width: 200px; 50 | text-align: center; 51 | } 52 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/inner/check-box-cell/check-box-cell.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import {ICellRendererAngularComp} from 'ag-grid-angular-legacy'; 3 | import {ICellRendererParams} from 'ag-grid-community'; 4 | 5 | @Component({ 6 | selector: 'app-check-box-cell', 7 | templateUrl: './check-box-cell.component.html', 8 | styleUrls: ['./check-box-cell.component.scss'] 9 | }) 10 | export class CheckBoxCellComponent implements OnInit, ICellRendererAngularComp { 11 | params: any; 12 | constructor() { 13 | } 14 | 15 | ngOnInit(): void { 16 | } 17 | 18 | agInit(params: any): void { 19 | this.params = params; 20 | } 21 | 22 | checkedHandler(event) { 23 | const checked = event.target.checked; 24 | const colId = this.params.column.colId; 25 | this.params.node.setDataValue(colId, checked); 26 | } 27 | 28 | refresh(params: ICellRendererParams): boolean { 29 | return false; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /server/src/test/java/org/adp/gable/security/TestTokenUtils.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.security; 2 | 3 | import org.adp.gable.SupperUser; 4 | import org.adp.gable.security.utils.JwtConst; 5 | import org.springframework.test.web.servlet.MockMvc; 6 | import org.springframework.test.web.servlet.MvcResult; 7 | import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; 8 | 9 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 10 | 11 | public class TestTokenUtils { 12 | 13 | public static String getToken(String email, String password, MockMvc mvc) throws Exception { 14 | MvcResult mvcResult = mvc 15 | .perform(MockMvcRequestBuilders.get(JwtConst.LOGIN_PATH) 16 | .queryParam("username", SupperUser.USER_EMAIL) 17 | .queryParam("password", "123456") 18 | ).andExpect(status().isOk()).andReturn(); 19 | return mvcResult.getResponse().getHeader(JwtConst.TOKEN_HEADER); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/api/dao/DocMenuDao.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.api.dao; 2 | 3 | import org.adp.gable.api.entity.DocMenu; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author zzq 10 | */ 11 | public interface DocMenuDao extends JpaRepository { 12 | 13 | /** 14 | * get a doc‘s menu by level 15 | * @param docId doc id 16 | * @param level menu level 17 | * @return menu list 18 | * */ 19 | List findByDocIdAndLevelOrderById(Long docId, Integer level); 20 | 21 | /** 22 | * find all sub menu by parent id 23 | * 24 | * @param parentId menu id 25 | * @return submenu list 26 | */ 27 | List findByParentIdOrderById(Long parentId); 28 | 29 | /** 30 | * get menu by api key. for api auto generated 31 | * 32 | * @param apiKey generated by id + apiType 33 | * @return menu 34 | */ 35 | DocMenu findFirstByApiKey(String apiKey); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /client/src/app/home/doc-page/doc-editor/doc-editor.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |
6 | 11 |

12 | {{ 'PAGES.DOCS.LOADING_BLOCK' | translate }} 13 |

14 |
15 |
16 | 17 | {{ 'PAGES.DOCS.SELECT_A_DOC' | translate }} 18 | 19 |
20 |
21 |
22 |
23 | 24 |
25 | 26 |
27 |
28 |
29 |
30 |
31 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/inner/cell-file/cell-file.component.scss: -------------------------------------------------------------------------------- 1 | .hint-str{ 2 | color: #A6A6A6; 3 | } 4 | .file-input { 5 | height: 100%; 6 | display: inline-block; 7 | width: 100%; 8 | white-space: nowrap; 9 | overflow: hidden; 10 | text-overflow: ellipsis; 11 | 12 | .file-btn { 13 | box-sizing: border-box; 14 | border-radius: 4px; 15 | display: inline; 16 | height: 20px; 17 | padding: 4px 6px; 18 | font-size: 12px; 19 | font-weight: 600; 20 | font-family: "Inter", system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica, Arial, sans-serif; 21 | line-height: 16px; 22 | color: #6B6B6B; 23 | -webkit-user-select: none; 24 | user-select: none; 25 | cursor: pointer; 26 | background-color: #F2F2F2; 27 | } 28 | 29 | .file-btn:hover { 30 | background-color: #E6E6E6; 31 | color: #212121;; 32 | } 33 | 34 | .in { 35 | display: none; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /client/src/app/home/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | import {DataServiceImplService} from '../../core/services/impl/data-service-impl.service'; 4 | 5 | @Component({ 6 | selector: 'app-home', 7 | templateUrl: './home.component.html', 8 | styleUrls: ['./home.component.scss'] 9 | }) 10 | export class HomeComponent implements OnInit { 11 | editorOptions = {theme: 'vs-dark', language: 'javascript'}; 12 | code = 'function x() {\nconsole.log("Hello world!");\n}'; 13 | 14 | constructor(private router: Router, 15 | private dataServiceImplService: DataServiceImplService) { 16 | } 17 | 18 | ngOnInit(): void { 19 | } 20 | 21 | addItem() { 22 | this.dataServiceImplService.addItem().subscribe((v) => { 23 | console.log('zzq see add data', v); 24 | }); 25 | } 26 | 27 | clearItem() { 28 | this.dataServiceImplService.clearAll().subscribe((v) => { 29 | console.log('zzq see clear data', v); 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /client/src/assets/svg/searchI.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /client/src/app/home/doc-page/doc-detail/doc-menu-tree/doc-menu-tree.component.scss: -------------------------------------------------------------------------------- 1 | .doc-menu-item { 2 | cursor: pointer; 3 | width: 100%; 4 | height: 40px; 5 | line-height: 40px; 6 | position: relative; 7 | display: inline-block; 8 | white-space: nowrap; 9 | overflow: hidden; 10 | text-overflow: ellipsis; 11 | -moz-user-select: none; 12 | -webkit-user-select: none; 13 | -ms-user-select: none; 14 | user-select: none; 15 | 16 | .status-bar { 17 | position: absolute; 18 | bottom: 0; 19 | width: 100%; 20 | } 21 | 22 | .doc-btn-gro { 23 | position: absolute; 24 | right: 10px; 25 | -moz-user-select: none; 26 | -webkit-user-select: none; 27 | -ms-user-select: none; 28 | user-select: none; 29 | text-decoration: none; 30 | background-color: #F2F2F2; 31 | } 32 | } 33 | mat-tree-node:hover { 34 | background-color: rgba(107, 107, 107, 0.2); 35 | } 36 | mat-tree-node{ 37 | cursor: pointer; 38 | } 39 | 40 | 41 | .doc-menu-selected { 42 | background-color: rgba(107, 107, 107, 0.4); 43 | } 44 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/security/utils/JwtUtils.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.security.utils; 2 | 3 | import com.auth0.jwt.JWT; 4 | import com.auth0.jwt.algorithms.Algorithm; 5 | import com.fasterxml.jackson.core.JsonProcessingException; 6 | import com.fasterxml.jackson.databind.ObjectMapper; 7 | import org.adp.gable.security.dtos.UserDto; 8 | 9 | import java.util.Date; 10 | 11 | /** 12 | * @author zzq 13 | */ 14 | public class JwtUtils { 15 | 16 | public static String generateToken(long l, UserDto userDto, String uri, ObjectMapper objectMapper) throws JsonProcessingException { 17 | Algorithm algorithm = Algorithm.HMAC256(JwtConst.SECURITY_ARRAY); 18 | return JWT.create() 19 | .withSubject(userDto.getEmail()) 20 | .withExpiresAt(new Date(l)) 21 | .withIssuer(JwtConst.ISSUER_PREFIX + uri) 22 | .withIssuedAt(new Date()) 23 | .withClaim(JwtConst.CLAIM_KEY, objectMapper.writeValueAsString(userDto)) 24 | .sign(algorithm); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /client/LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2020 - Maxime GRIS 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /client/angular.webpack.js: -------------------------------------------------------------------------------- 1 | //Polyfill Node.js core modules in Webpack. This module is only needed for webpack 5+. 2 | const NodePolyfillPlugin = require("node-polyfill-webpack-plugin"); 3 | 4 | /** 5 | * Custom angular webpack configuration 6 | */ 7 | module.exports = (config, options) => { 8 | config.target = 'electron-renderer'; 9 | 10 | if (options.fileReplacements) { 11 | for(let fileReplacement of options.fileReplacements) { 12 | if (fileReplacement.replace !== 'src/environments/environment.ts') { 13 | continue; 14 | } 15 | 16 | let fileReplacementParts = fileReplacement['with'].split('.'); 17 | if (fileReplacementParts.length > 1 && ['web'].indexOf(fileReplacementParts[1]) >= 0) { 18 | config.target = 'web'; 19 | } 20 | break; 21 | } 22 | } 23 | 24 | config.plugins = [ 25 | ...config.plugins, 26 | new NodePolyfillPlugin({ 27 | excludeAliases: ["console"] 28 | }) 29 | ]; 30 | 31 | return config; 32 | } 33 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/inner/cell-file-text/cell-file-text.component.scss: -------------------------------------------------------------------------------- 1 | .cell-container { 2 | width: 100%; 3 | height: 100%; 4 | position: relative; 5 | 6 | .left { 7 | width: 100%; 8 | height: 100%; 9 | 10 | .hint-str { 11 | color: #A6A6A6; 12 | } 13 | 14 | } 15 | 16 | .right-select { 17 | height: 100%; 18 | position: absolute; 19 | top: 0; 20 | right: 0; 21 | 22 | select { 23 | outline: none; 24 | border: none; 25 | } 26 | 27 | .file-select-item { 28 | position: relative; 29 | box-sizing: border-box; 30 | height: 32px; 31 | padding: 0px 16px; 32 | color: #212121; 33 | font-size: 12px; 34 | font-family: "Inter",system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica,Arial,sans-serif; 35 | display: flex; 36 | align-items: center; 37 | -webkit-user-select: none; 38 | user-select: none; 39 | cursor: pointer; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/request-tabs.component.scss: -------------------------------------------------------------------------------- 1 | .req-container { 2 | width: 100%; 3 | height: 100%; 4 | display: flex; 5 | flex-direction: column; 6 | 7 | .tabs-container{ 8 | display: flex; 9 | flex-direction: row; 10 | 11 | .tabs-nav{ 12 | flex: 1; 13 | .tab{ 14 | min-width: 60px; 15 | height: 32px; 16 | 17 | .request-editor-tabs-badge { 18 | width: 8px; 19 | height: 8px; 20 | background-color: #0cbb52; 21 | border-radius: 8px; 22 | margin-left: 5px; 23 | } 24 | } 25 | 26 | .active{ 27 | font-weight: 600; 28 | } 29 | } 30 | 31 | .operation-hub { 32 | height: 32px; 33 | width: 100px; 34 | border-bottom-color: rgba(0, 0, 0, 0.12); 35 | border-bottom-style: solid; 36 | border-bottom-width: 1px; 37 | } 38 | } 39 | 40 | 41 | .body{ 42 | flex: 1; 43 | 44 | .content { 45 | width: 100%; 46 | height: 100%; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/security/utils/AuthoritiesSerializeUtil.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.security.utils; 2 | 3 | import com.fasterxml.jackson.core.JacksonException; 4 | import com.fasterxml.jackson.core.JsonParser; 5 | import com.fasterxml.jackson.databind.DeserializationContext; 6 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer; 7 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 8 | 9 | import java.io.IOException; 10 | import java.util.Collections; 11 | import java.util.Set; 12 | 13 | /** 14 | * @author zzq 15 | */ 16 | public class AuthoritiesSerializeUtil extends StdDeserializer> { 17 | public AuthoritiesSerializeUtil() { 18 | this(null); 19 | } 20 | protected AuthoritiesSerializeUtil(Class vc) { 21 | super(vc); 22 | } 23 | 24 | @Override 25 | public Set deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException { 26 | return Collections.emptySet(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/security/PermissionType.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.security; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * the permission's define 8 | * 9 | * @author zzq 10 | */ 11 | 12 | @Getter 13 | @AllArgsConstructor 14 | public enum PermissionType { 15 | 16 | /** 17 | * permission of create user 18 | */ 19 | SEC_CREATE_USER("sec_createUser", "SEC_CREATE_USER"), 20 | 21 | /** 22 | * permission of create role 23 | * */ 24 | SEC_CREATE_ROLE("sec_createRole", "SEC_CREATE_USER"), 25 | 26 | /** 27 | * permission of modify role’s permission 28 | * */ 29 | SEC_MODIFY_ROLE("sec_modifyRole", "SEC_CREATE_USER"), 30 | 31 | /** 32 | * permission of delete the role 33 | * */ 34 | SEC_DELETE_ROLE("sec_deleteRole", "SEC_DELETE_ROLE"), 35 | 36 | 37 | /** 38 | * permission of modify user‘s password 39 | */ 40 | SEC_MODIFY_PWD("sec_modifyPwd", "SEC_CREATE_USER"), 41 | 42 | ; 43 | 44 | private String code; 45 | private String i18nKey; 46 | } 47 | -------------------------------------------------------------------------------- /client/src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | import { PageNotFoundComponent } from './shared/components'; 4 | 5 | import {BasicLayoutComponent} from './shared/components/layout/basic-layout.component'; 6 | 7 | const routes: Routes = [ 8 | { 9 | path: '', 10 | component: BasicLayoutComponent, 11 | data: {}, 12 | children: [ 13 | { path: '', redirectTo: 'dashboard', pathMatch: 'full' }, 14 | { 15 | path: 'dashboard', 16 | loadChildren: () => import('./home/home.module').then(m => m.HomeModule) 17 | } 18 | ] 19 | }, 20 | { 21 | path: '', 22 | loadChildren: () => import('./passport/passport.module').then(m => m.PassportModule), 23 | data: {preload: true} 24 | }, 25 | { 26 | path: '**', 27 | component: PageNotFoundComponent 28 | } 29 | ]; 30 | 31 | @NgModule({ 32 | imports: [ 33 | RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' }) 34 | ], 35 | exports: [RouterModule] 36 | }) 37 | export class AppRoutingModule { } 38 | -------------------------------------------------------------------------------- /client/src/app/detail/detail.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import {DataServiceImplService} from '../core/services/impl/data-service-impl.service'; 3 | 4 | @Component({ 5 | selector: 'app-detail', 6 | templateUrl: './detail.component.html', 7 | styleUrls: ['./detail.component.scss'] 8 | }) 9 | export class DetailComponent implements OnInit { 10 | infos: any[] = []; 11 | constructor(private dataServiceImplService: DataServiceImplService) { } 12 | 13 | ngOnInit(): void { 14 | console.log('DetailComponent INIT', this.infos); 15 | this.dataServiceImplService.getData().subscribe({ 16 | next: value => { 17 | if (value instanceof Array) { 18 | this.infos = value; 19 | }else { 20 | console.log('receive data not array', value); 21 | } 22 | console.log('DetailComponent INIT', this.infos); 23 | }, 24 | error: err => { 25 | console.log('error happens', err); 26 | }, 27 | complete: () => { 28 | console.log('after subscribe'); 29 | } 30 | }); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/response-tabs/empty-response/empty-response.component.scss: -------------------------------------------------------------------------------- 1 | .resp-empty-container { 2 | width: 100%; 3 | height: 100%; 4 | display: flex; 5 | flex-direction: column; 6 | justify-content: center; 7 | align-items: center; 8 | 9 | .tip-text { 10 | font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica, Arial, sans-serif; 11 | color: rgb(107, 107, 107); 12 | margin-top: 10px; 13 | max-width: 80ch; 14 | font-size: 12px; 15 | overflow-wrap: break-word; 16 | word-break: break-word; 17 | line-height: 1.6; 18 | } 19 | 20 | .tip-header{ 21 | margin: 0px; 22 | font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", Helvetica, Arial, sans-serif; 23 | font-weight: 600; 24 | word-break: normal; 25 | font-size: 16px; 26 | line-height: 1.44; 27 | color: rgb(33, 33, 33); 28 | letter-spacing: -0.12px; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /client/src/app/home/diff/diff.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {MonacoStandaloneDiffEditor} from "@materia-ui/ngx-monaco-editor"; 3 | 4 | @Component({ 5 | selector: 'app-diff', 6 | templateUrl: './diff.component.html', 7 | styleUrls: ['./diff.component.scss'] 8 | }) 9 | export class DiffComponent implements OnInit { 10 | lc = ''; 11 | rc = ''; 12 | 13 | editorOptions = {theme: 'vs-light', language: 'json'}; 14 | code: string = '[1, 2, 3, 4]'; 15 | originalCode: string = '[1, 2, 5, 4]'; 16 | editor: any; 17 | constructor() { } 18 | 19 | ngOnInit(): void { 20 | } 21 | 22 | setLeft() { 23 | this.originalCode = JSON.stringify(JSON.parse(this.lc), null, 2); 24 | var model = this.editor.getModel(); 25 | model.original.setValue(this.originalCode); 26 | } 27 | 28 | setRight() { 29 | this.code = JSON.stringify(JSON.parse(this.rc), null, 2); 30 | var model = this.editor.getModel(); 31 | model.modified.setValue(this.code) 32 | } 33 | 34 | down(editor: MonacoStandaloneDiffEditor) { 35 | this.editor = editor; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/api/dao/DocBlockDao.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.api.dao; 2 | 3 | import org.adp.gable.api.entity.DocBlock; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author zzq 10 | */ 11 | public interface DocBlockDao extends JpaRepository { 12 | 13 | /** 14 | * get all blocks by doc define id 15 | * 16 | * @param docDefineId doc define id 17 | * @return doc blocks 18 | * */ 19 | List findByDocDefineIdOrderByOrder(Long docDefineId); 20 | 21 | 22 | /** 23 | * delete all blocks by doc define id 24 | * 25 | * @param docDefineId doc define id 26 | * @return delete count 27 | */ 28 | int deleteByDocDefineId(Long docDefineId); 29 | 30 | 31 | /** 32 | * delete all blocks by doc define id 33 | * 34 | * @param order the max order remained 35 | * @param docDefineId doc define id 36 | * @return delete count 37 | */ 38 | int deleteByDocDefineIdAndOrderGreaterThanEqual(Long docDefineId, Integer order); 39 | } 40 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/api/dto/http/DocJsonTableNode.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.api.dto.http; 2 | 3 | import lombok.Data; 4 | import org.apache.commons.lang3.RandomStringUtils; 5 | 6 | import java.lang.reflect.Array; 7 | import java.util.Arrays; 8 | import java.util.Collections; 9 | import java.util.List; 10 | 11 | @Data 12 | public class DocJsonTableNode { 13 | private String id; 14 | private Boolean canDelete; 15 | private Boolean canEditName; 16 | private String name; 17 | private String type; 18 | private String desc; 19 | private Object sample; 20 | private List location; 21 | 22 | public static List getRoot() { 23 | DocJsonTableNode root = new DocJsonTableNode(); 24 | root.id = RandomStringUtils.random(5, true, false); 25 | root.canDelete = false; 26 | root.type = "object"; 27 | root.canEditName = false; 28 | root.name = "root"; 29 | root.sample = ""; 30 | root.location = Collections.singletonList(root.id); 31 | return Collections.singletonList(root); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /client/app/src/listeners/handler/item-listener.ts: -------------------------------------------------------------------------------- 1 | import {Handler} from "../listener-handler"; 2 | import {getItemRepository} from "../../config/init-datasource"; 3 | import {Repository} from "typeorm/repository/Repository"; 4 | import {Item} from "../../entity/Item"; 5 | 6 | export class OnItemGetAllHandler implements Handler { 7 | 8 | async handle(args: any[]) { 9 | const itemRepo = await getItemRepository(); 10 | return await itemRepo.find(); 11 | } 12 | 13 | } 14 | export class OnItemAddHandler implements Handler{ 15 | async handle(args: any[]) { 16 | const itemRepo = await getItemRepository(); 17 | const item = itemRepo.create({ name: new Date().toString()}); 18 | await itemRepo.save(item); 19 | return item; 20 | } 21 | 22 | } 23 | export class OnItemClearHandler implements Handler{ 24 | async handle(args: any[]) { 25 | const itemRepo: Repository = await getItemRepository(); 26 | const allData = await itemRepo.find(); 27 | let s = ''; 28 | for (const item of allData) { 29 | s += item.id + '.'; 30 | await itemRepo.remove(item); 31 | } 32 | return s; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /client/src/app/core/services/impl/electron/database-data-service.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import {DataService} from '../../DataService'; 3 | import {ElectronService} from '../../electron/electron.service'; 4 | import {catchError, Observable, of} from 'rxjs'; 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class DatabaseDataServiceService implements DataService{ 10 | 11 | constructor(private electronService: ElectronService) { 12 | } 13 | 14 | clearAll(): Observable { 15 | return of(this.electronService.ipcRenderer.sendSync('clear-data')).pipe( 16 | catchError((error: any) => new Observable(error.json)) 17 | ); 18 | } 19 | 20 | getData(): Observable { 21 | return of(this.electronService.ipcRenderer.sendSync('get-data')).pipe( 22 | catchError((error: any) => new Observable(error.json)) 23 | ); 24 | } 25 | 26 | addItem(): Observable { 27 | console.log('run add item in database'); 28 | return of(this.electronService.ipcRenderer.sendSync('add-data')).pipe( 29 | catchError((error: any) => new Observable(error.json)) 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /client/src/app/core/services/impl/electron/nav-tab-elec-impl.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import {NavTabService} from '../../ServiceDefine'; 3 | import {Observable} from 'rxjs'; 4 | import {DashBoardShowingMetadata, MenuSelectedEvent, OpeningNavTab} from '../../entity/ApiMenu'; 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class NavTabElecImplService implements NavTabService{ 10 | 11 | constructor() { } 12 | 13 | getOpeningTab(): Observable { 14 | return undefined; 15 | } 16 | 17 | getTabsData(): Observable { 18 | return undefined; 19 | } 20 | 21 | openTabs(tab: OpeningNavTab, fromMenu: boolean, created?: boolean): void { 22 | } 23 | 24 | closeTab(id: string): void { 25 | } 26 | 27 | closeAllTab(): void { 28 | } 29 | 30 | getShowingTab(): Observable { 31 | return undefined; 32 | } 33 | 34 | updateTabName(id: number, type: string, newName: string) { 35 | } 36 | 37 | getFocusMenu(): Observable { 38 | return undefined; 39 | } 40 | 41 | changeTab(type: string, id: number, newTag: string): void { 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /document/docs/zh/guide/business-ideal.md: -------------------------------------------------------------------------------- 1 | # 商业理想 2 | 3 | ## 市场格局 4 | 5 | 在 API 协作这个赛道,最大的玩家是 `PostMan`,其已经市值56亿美金 6 | 7 | 您可以点击此处查看:[链接](https://zhuanlan.zhihu.com/p/483788526) 8 | 9 | 在开源领域,曾经的 `PostWomen`,如今叫 `hoppscotch` 也获得了三百万美元的投资: 10 | 11 | ![hoppscotch投资](https://s3.bmp.ovh/imgs/2022/09/01/b477fee4f376052f.png) 12 | 13 | 您可以点击此处查看:[链接](https://github.com/liyasthomas) 14 | 15 | 在国内,该赛道主要有两大玩家,分别是: 16 | 17 | API Post 获得的融资: 18 | 19 | ![](https://s3.bmp.ovh/imgs/2022/09/01/3ba942016fa32aa4.png) 20 | 21 | 22 | 您可以点击此处查看:[链接](https://new.qq.com/rain/a/20211201A02O8600) 23 | 24 | API Fox 获得的融资: 25 | 26 | ![](https://s3.bmp.ovh/imgs/2022/09/01/a65a24a91f87d975.png) 27 | 28 | 29 | 您可以点击此处查看:[链接](https://new.qq.com/rain/a/20220105A030CF00) 30 | 31 | **我们的商业理想是,`Gable` 将为 API 协作 这个赛道提供一个开源的解决方案。** 32 | 33 | **我们的目标是,做出一款全世界最好用的API 协作工具。** 34 | 35 | ## 为什么我们会认为这是一个好的机会 36 | 37 | - 第一,这个赛道并不拥挤,我们看过很多别的赛道,比这个赛道更拥挤的有太多了。 38 | - 第二,API协作的产品,在技术上有一定的壁垒,但是我们的能力还是可以突破这个技术壁垒的。 39 | - 第三,作为一个工具类的产品,它没有太多的定制化需求,但是要做好产品体验。 40 | 41 | ## 如何竞争 42 | 43 | 三大法宝 44 | 45 | - 产品体验 46 | - 免费 47 | - 开源 48 | 49 | 我们没有办法打败他们,只能做到不被他们搞死,或者自己不放弃就是胜利。 50 | 51 | 把他们的商业前途都熬光,我们的商业前途就来了。 52 | 53 | 我们还是挺有韧性,挺能坚持的。 -------------------------------------------------------------------------------- /server/src/test/java/org/adp/gable/security/entity/RoleEntityTest.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.security.entity; 2 | 3 | import org.junit.jupiter.api.DisplayName; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import static org.junit.jupiter.api.Assertions.*; 7 | 8 | class RoleEntityTest { 9 | 10 | @Test 11 | @DisplayName("test role type default of update") 12 | public void testInitUpdate(){ 13 | RoleEntity entit = new RoleEntity(); 14 | entit.initBeforeUpdate(); 15 | assertNotNull(entit.getDateModified()); 16 | assertEquals(Boolean.FALSE, entit.getAdminRole()); 17 | entit.setAdminRole(Boolean.TRUE); 18 | entit.initBeforeUpdate(); 19 | assertEquals(Boolean.TRUE, entit.getAdminRole()); 20 | assertNotNull(entit.getDateModified()); 21 | 22 | } 23 | 24 | @Test 25 | @DisplayName("test role type default of create") 26 | public void testInitCreated(){ 27 | RoleEntity entit = new RoleEntity(); 28 | entit.setAdminRole(Boolean.TRUE); 29 | entit.initBeforeSave(); 30 | assertEquals(Boolean.FALSE, entit.getAdminRole()); 31 | assertNotNull(entit.getDateModified()); 32 | 33 | } 34 | } -------------------------------------------------------------------------------- /client/src/app/home/home/home.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import { HomeComponent } from './home.component'; 4 | import { TranslateModule } from '@ngx-translate/core'; 5 | import { RouterTestingModule } from '@angular/router/testing'; 6 | 7 | describe('HomeComponent', () => { 8 | let component: HomeComponent; 9 | let fixture: ComponentFixture; 10 | 11 | beforeEach(waitForAsync(() => { 12 | TestBed.configureTestingModule({ 13 | declarations: [HomeComponent], 14 | imports: [TranslateModule.forRoot(), RouterTestingModule] 15 | }).compileComponents(); 16 | })); 17 | 18 | beforeEach(() => { 19 | fixture = TestBed.createComponent(HomeComponent); 20 | component = fixture.componentInstance; 21 | fixture.detectChanges(); 22 | }); 23 | 24 | it('should create', () => { 25 | expect(component).toBeTruthy(); 26 | }); 27 | 28 | it('should render title in a h1 tag', waitForAsync(() => { 29 | const compiled = fixture.debugElement.nativeElement; 30 | expect(compiled.querySelector('h1').textContent).toContain( 31 | 'PAGES.HOME.TITLE' 32 | ); 33 | })); 34 | }); 35 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/api/dto/HttpApiDto.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.api.dto; 2 | 3 | import lombok.Data; 4 | import org.adp.gable.api.dto.http.DocJsonTableNode; 5 | import org.adp.gable.api.dto.http.FormKeyValueDto; 6 | import org.adp.gable.api.dto.http.KeyValueDto; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author zzq 12 | */ 13 | @Data 14 | public class HttpApiDto { 15 | private Long id; 16 | private String protocol; 17 | private String method; 18 | private String host; 19 | private List hostArr; 20 | private String port; 21 | private String path; 22 | private List pathArray; 23 | 24 | private String url; 25 | 26 | private List query; 27 | private List header; 28 | 29 | private String bodyType; 30 | 31 | private List bodyForm; 32 | private List bodyUrlEncoded; 33 | private String bodyText; 34 | private String bodyTextType; 35 | private String bodyGraphQlQuery; 36 | private String bodyGraphQlVar; 37 | private List bodyTextDoc; 38 | private List respBodyTextDoc; 39 | private Long version; 40 | } 41 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/common/utils/I18nUtils.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.common.utils; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.adp.gable.common.web.SpringContextHolder; 5 | import org.springframework.context.NoSuchMessageException; 6 | import org.springframework.context.i18n.LocaleContextHolder; 7 | 8 | import java.util.Arrays; 9 | import java.util.Locale; 10 | 11 | /** 12 | * @author zzq 13 | */ 14 | @Slf4j 15 | public class I18nUtils { 16 | 17 | public static String getMessage(String placeHolder, Object[] args) { 18 | final Locale locale = LocaleContextHolder.getLocale(); 19 | return getMessage(placeHolder, args, locale); 20 | } 21 | 22 | public static String getMessage(String placeHolder, Object[] args, Locale locale) { 23 | String message = null; 24 | try { 25 | message = SpringContextHolder.getApplicationContext().getMessage(placeHolder, args, locale); 26 | } catch (NoSuchMessageException ex) { 27 | log.warn("i18n key:{} is missing. locale = {}, args = {}", placeHolder, locale, Arrays.toString(args), ex); 28 | return placeHolder; 29 | } 30 | return message; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /client/src/app/detail/detail.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import { DetailComponent } from './detail.component'; 4 | import { TranslateModule } from '@ngx-translate/core'; 5 | 6 | import { RouterTestingModule } from '@angular/router/testing'; 7 | 8 | describe('DetailComponent', () => { 9 | let component: DetailComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(waitForAsync(() => { 13 | TestBed.configureTestingModule({ 14 | declarations: [DetailComponent], 15 | imports: [TranslateModule.forRoot(), RouterTestingModule] 16 | }).compileComponents(); 17 | })); 18 | 19 | beforeEach(() => { 20 | fixture = TestBed.createComponent(DetailComponent); 21 | component = fixture.componentInstance; 22 | fixture.detectChanges(); 23 | }); 24 | 25 | it('should create', () => { 26 | expect(component).toBeTruthy(); 27 | }); 28 | 29 | it('should render title in a h1 tag', waitForAsync(() => { 30 | const compiled = fixture.debugElement.nativeElement; 31 | expect(compiled.querySelector('h1').textContent).toContain( 32 | 'PAGES.DETAIL.TITLE' 33 | ); 34 | })); 35 | }); 36 | -------------------------------------------------------------------------------- /client/src/app/core/services/impl/web/ConfigServiceWebImpl.ts: -------------------------------------------------------------------------------- 1 | import {ConfigService} from '../../ConfigService'; 2 | import {Observable, of} from 'rxjs'; 3 | import {Injectable} from '@angular/core'; 4 | 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class ConfigServiceWebImpl implements ConfigService { 10 | private cache: Map; 11 | 12 | constructor() { 13 | this.cache = new Map(); 14 | } 15 | 16 | getConfig(key: string): Observable { 17 | let value = this.cache.get(key); 18 | if (value) { 19 | return of(value); 20 | } 21 | value = localStorage.getItem(key); 22 | if (value) { 23 | this.cache.set(key, value); 24 | } 25 | return of(value); 26 | } 27 | 28 | updateOrCreateConfig(key: string, value: string): Observable { 29 | localStorage.setItem(key, value); 30 | this.cache.set(key, value); 31 | return of(value); 32 | } 33 | 34 | getConfigSync(key: string) { 35 | let value = this.cache.get(key); 36 | if (value) { 37 | return value; 38 | } 39 | value = localStorage.getItem(key); 40 | if (value) { 41 | this.cache.set(key, value); 42 | } 43 | return value; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /client/src/app/home/api-test/api-test.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit, ViewChild} from '@angular/core'; 2 | import {NgxSpinnerService} from 'ngx-spinner'; 3 | import {TestDashboardComponent} from '../../shared/components/api/test-dashboard/test-dashboard.component'; 4 | import {NavTabImplService} from '../../core/services/impl/nav-tab-impl.service'; 5 | 6 | @Component({ 7 | selector: 'app-api-test', 8 | templateUrl: './api-test.component.html', 9 | styleUrls: ['./api-test.component.scss'] 10 | }) 11 | export class ApiTestComponent implements OnInit { 12 | @ViewChild('dashboardComponent', {static: true}) dashboardComponent: TestDashboardComponent; 13 | 14 | constructor( 15 | private spinner: NgxSpinnerService, 16 | private navTabImplService: NavTabImplService 17 | ) { } 18 | 19 | ngOnInit(): void { 20 | this.spinner.show(); 21 | } 22 | 23 | onMenuReady(data: any) { 24 | this.spinner.hide(); 25 | } 26 | 27 | // onMenuSelected(data: NavChangeEvent) { 28 | // let openTab: OpeningNavTab; 29 | // 30 | // const da = { 31 | // name: data.name, 32 | // type: data.type, 33 | // id: data.id, 34 | // }; 35 | // this.navTabImplService.openTabs(openTab, data.isCreated); 36 | // } 37 | } 38 | -------------------------------------------------------------------------------- /client/src/app/core/services/ServiceDefine.ts: -------------------------------------------------------------------------------- 1 | import {Observable} from 'rxjs'; 2 | import { 3 | ApiMenuCollection, 4 | ApiMenuItem, 5 | DashBoardShowingMetadata, 6 | MenuEvent, 7 | MenuSelectedEvent, 8 | OpeningNavTab 9 | } from './entity/ApiMenu'; 10 | 11 | export interface ApiMenuService{ 12 | 13 | getMenus: () => Observable; 14 | 15 | addCollection: (collectionName) => Observable; 16 | 17 | actions: () => Observable; 18 | 19 | getCollectionData(id: number): Observable; 20 | 21 | getApiData(id: number): Observable; 22 | 23 | addHttp(apiName: string, collectionId: number): Observable; 24 | 25 | updateCollectionName(id: number, newName: string); 26 | 27 | updateApiName(id: number, collectionId: number, newName: string); 28 | } 29 | 30 | export interface NavTabService { 31 | openTabs(tab: OpeningNavTab, fromMenu: boolean): void; 32 | 33 | getTabsData(): Observable; 34 | 35 | getShowingTab(): Observable; 36 | 37 | getFocusMenu(): Observable; 38 | 39 | updateTabName(id: number, type: string, newName: string); 40 | 41 | closeTab(id: string): void; 42 | closeAllTab(): void; 43 | } 44 | -------------------------------------------------------------------------------- /client/src/app/core/services/impl/http-api.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import {ElectronService} from '../electron/electron.service'; 3 | import {HttpApiElecImplService} from './electron/http-api-elec-impl.service'; 4 | import {HttpApiWebImplService} from './web/http-api-web-impl.service'; 5 | import {HttpApiHistoryCache} from '../entity/HttpApi'; 6 | import {Observable} from 'rxjs'; 7 | 8 | @Injectable({ 9 | providedIn: 'root' 10 | }) 11 | export class HttpApiService { 12 | 13 | constructor( 14 | private electronService: ElectronService, 15 | private electronImpl: HttpApiElecImplService, 16 | private webImpl: HttpApiWebImplService 17 | ) { } 18 | 19 | public clearAllCache(){ 20 | return this.webImpl.clearAllCache(); 21 | } 22 | 23 | public addApiDefine(data: HttpApiHistoryCache): void { 24 | return this.webImpl.addApiDefine(data); 25 | } 26 | 27 | public updateCache(data: HttpApiHistoryCache): void { 28 | return this.webImpl.updateCache(data); 29 | } 30 | 31 | public getCache(id: number): Observable { 32 | return this.webImpl.getCache(id); 33 | } 34 | 35 | removeCache(id: number): Promise { 36 | return this.webImpl.removeCache(id); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/api/entity/DocEntity.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.api.entity; 2 | 3 | import lombok.Data; 4 | import org.adp.gable.common.entity.BaseEntity; 5 | import org.hibernate.annotations.Comment; 6 | 7 | import javax.persistence.*; 8 | 9 | /** 10 | * @author zzq 11 | */ 12 | @Data 13 | @Entity(name = "doc") 14 | @org.hibernate.annotations.Table(appliesTo = "doc", comment = "doc table.文档表") 15 | @javax.persistence.Table(name = "doc", indexes = { 16 | @Index(name = "idx_doc_dateCreated", columnList = "date_created", unique = false), 17 | @Index(name = "idx_doc_name", columnList = "name", unique = false) 18 | }) 19 | public class DocEntity extends BaseEntity { 20 | 21 | @Id 22 | @SequenceGenerator( 23 | name = "api_doc_sequence" 24 | , sequenceName = "api_doc_sequence" 25 | , allocationSize = 1 26 | ) 27 | @GeneratedValue( 28 | strategy = GenerationType.SEQUENCE, 29 | generator = "api_doc_sequence" 30 | ) 31 | private Long id; 32 | 33 | @Column( 34 | name = "name", 35 | columnDefinition = "varchar(128)", 36 | nullable = false 37 | ) 38 | @Comment("doc name") 39 | private String name; 40 | } 41 | -------------------------------------------------------------------------------- /client/src/app/home/doc-page/doc-dash-board/doc-dash-board.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
8 |
9 | 10 |
11 | 12 | {{ doc.name }} 13 | 14 |
15 |
16 |
17 |
18 |
19 | 20 | 21 | 22 |
23 |
24 | 25 | {{ 'PAGES.DOCS.CREATE' | translate }} 26 | 27 |
28 |
29 |
30 | -------------------------------------------------------------------------------- /client/src/app/shared/components/docs/http-url-doc/http-url-doc.component.html: -------------------------------------------------------------------------------- 1 |
2 |
4 |
5 | 6 |
7 |
8 | 11 |
12 |
13 |
18 |
21 | 22 | {{url.url}} 23 | 24 |
25 |
27 | 30 | 33 | 36 |
37 |
38 |
39 | -------------------------------------------------------------------------------- /server/src/main/java/org/adp/gable/common/beans/Result.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.common.beans; 2 | 3 | import lombok.Data; 4 | import org.adp.gable.common.utils.I18nUtils; 5 | import org.adp.gable.common.web.ErrorResult; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * @author zzq 11 | */ 12 | @Data 13 | public class Result implements Serializable { 14 | private boolean result; 15 | private int code; 16 | private String message; 17 | private T data; 18 | 19 | public static Result failure(ErrorResult errorResult) { 20 | return failure(errorResult, null); 21 | } 22 | 23 | public static Result failure(ErrorResult errorResult, Object[] args) { 24 | Result result = new Result<>(); 25 | result.setResult(false); 26 | result.setData(null); 27 | result.setCode(errorResult.getErrorCode()); 28 | result.setMessage(I18nUtils.getMessage(errorResult.getMessageI18nKey(), args)); 29 | return result; 30 | } 31 | 32 | public static Result success(S data) { 33 | Result result = new Result<>(); 34 | result.setResult(true); 35 | result.setData(data); 36 | result.setCode(ErrorResult.SUCCESS_CODE); 37 | return result; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /client/HOW_TO.md: -------------------------------------------------------------------------------- 1 | ###*First check it exists a version of your library compatible with the version of Angular defined in package.json.* 2 | 3 | ### How to install ng-bootstrap 4 | 5 | ``` bash 6 | ng add @ng-bootstrap/ng-bootstrap 7 | ``` 8 | 9 | ### How to install ngx-bootstrap 10 | 11 | ``` bash 12 | ng add ngx-bootstrap 13 | ``` 14 | 15 | ### How to install Angular Material 16 | 17 | Add Angular Material using `ng add` command: 18 | 19 | ``` bash 20 | ng add @angular/material 21 | ``` 22 | You will get the following questions: 23 | 24 | ``` bash 25 | ? Choose a prebuilt theme name, or "custom" for a custom theme: *Choose any theme you like here* 26 | ? Set up global Angular Material typography styles? *Yes* 27 | ? Set up browser animations for Angular Material? *Yes* 28 | ``` 29 | Angular Material will start installing, but you will get the following error after installation: 30 | 31 | ``` bash 32 | Your project is not using the default builders for "build". The Angular Material schematics cannot add a theme to the workspace configuration if the builder has been changed. 33 | ``` 34 | *No need to Panic!* Just add your desired theme in style.scss: 35 | 36 | ``` bash 37 | @import '@angular/material/prebuilt-themes/indigo-pink.css' 38 | ``` 39 | Angular Material Library is now installed in your project. 40 | -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/graph-ql/graph-ql.component.html: -------------------------------------------------------------------------------- 1 |
2 | 5 | 6 |
7 |
8 | {{'PAGES.API_TEST.REQ.GRAPHQL_QUERY' | translate}} 9 |
10 |
11 | 16 | 17 |
18 |
19 |
20 | 24 |
25 |
26 | {{'PAGES.API_TEST.REQ.GRAPHQL_VAR' | translate}} 27 |
28 |
29 | 34 | 35 |
36 |
37 |
38 |
39 |
40 | -------------------------------------------------------------------------------- /client/src/app/passport/login/login.component.ts: -------------------------------------------------------------------------------- 1 | import {AfterViewInit, Component, OnInit} from '@angular/core'; 2 | import {Router} from '@angular/router'; 3 | import {DataServiceImplService} from '../../core/services/impl/data-service-impl.service'; 4 | import '../../../assets/login-animation.js'; 5 | 6 | @Component({ 7 | selector: 'app-login', 8 | templateUrl: './login.component.html', 9 | styleUrls: ['./login.component.scss'] 10 | }) 11 | export class LoginComponent implements OnInit, AfterViewInit { 12 | email: string; 13 | password: string; 14 | 15 | constructor(private router: Router, 16 | private dataServiceImplService: DataServiceImplService) { 17 | } 18 | 19 | ngOnInit(): void { 20 | } 21 | 22 | ngAfterViewInit() { 23 | (window as any).loginInitialize(); 24 | } 25 | 26 | addItem() { 27 | this.dataServiceImplService.addItem().subscribe((v) => { 28 | console.log('zzq see add data', v); 29 | }); 30 | } 31 | 32 | clearItem() { 33 | this.dataServiceImplService.clearAll().subscribe((v) => { 34 | console.log('zzq see clear data', v); 35 | }); 36 | } 37 | 38 | login() { 39 | 40 | console.log(`email: ${this.email} password: ${this.password}`); 41 | alert(`Email: ${this.email} Password: ${this.password}`); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /client/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "ignorePatterns": [ 4 | "app/**/*", // ignore nodeJs files 5 | "dist/**/*", 6 | "release/**/*" 7 | ], 8 | "overrides": [ 9 | { 10 | "files": [ 11 | "*.ts" 12 | ], 13 | "parserOptions": { 14 | "project": [ 15 | "./tsconfig.serve.json", 16 | "./src/tsconfig.app.json", 17 | "./src/tsconfig.spec.json", 18 | "./e2e/tsconfig.e2e.json" 19 | ], 20 | "createDefaultProgram": true 21 | }, 22 | "extends": [ 23 | "plugin:@angular-eslint/ng-cli-compat", 24 | "plugin:@angular-eslint/ng-cli-compat--formatting-add-on", 25 | "plugin:@angular-eslint/template/process-inline-templates" 26 | ], 27 | "rules": { 28 | "prefer-arrow/prefer-arrow-functions": 0, 29 | "@angular-eslint/directive-selector": 0, 30 | "@angular-eslint/component-selector": [ 31 | "error", 32 | { 33 | "type": "element", 34 | "prefix": "app", 35 | "style": "kebab-case" 36 | } 37 | ] 38 | } 39 | }, 40 | { 41 | "files": [ 42 | "*.html" 43 | ], 44 | "extends": [ 45 | "plugin:@angular-eslint/template/recommended" 46 | ], 47 | "rules": { 48 | } 49 | } 50 | ] 51 | } -------------------------------------------------------------------------------- /client/src/app/shared/components/api/work-bench/http-work-bench/request-tabs/inner/check-box-cell-editor/check-box-cell-editor.component.ts: -------------------------------------------------------------------------------- 1 | import {AfterViewInit, Component, OnInit, ViewChild, ViewContainerRef} from '@angular/core'; 2 | import {ICellEditorAngularComp} from 'ag-grid-angular-legacy'; 3 | import {ICellEditorParams} from 'ag-grid-community'; 4 | 5 | @Component({ 6 | selector: 'app-check-box-cell-editor', 7 | templateUrl: './check-box-cell-editor.component.html', 8 | styleUrls: ['./check-box-cell-editor.component.scss'] 9 | }) 10 | export class CheckBoxCellEditorComponent implements OnInit, ICellEditorAngularComp, AfterViewInit { 11 | 12 | @ViewChild('container', {read: ViewContainerRef}) 13 | public container!: ViewContainerRef; 14 | 15 | params: any; 16 | vvvv: boolean; 17 | 18 | constructor() { 19 | } 20 | 21 | ngOnInit(): void { 22 | } 23 | 24 | agInit(params: ICellEditorParams): void { 25 | this.params = params; 26 | this.vvvv = params.value; 27 | } 28 | 29 | getValue(): any { 30 | return this.vvvv; 31 | } 32 | 33 | ngAfterViewInit(): void { 34 | setTimeout(() => { 35 | this.container.element.nativeElement.focus(); 36 | }, 10); 37 | } 38 | 39 | onKeyDown(event: any): void { 40 | const key = event.key; 41 | if (key === 'Enter') { 42 | this.vvvv = !this.vvvv; 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /client/src/app/shared/components/developing/developing.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input, OnInit} from '@angular/core'; 2 | import {MatSnackBar} from '@angular/material/snack-bar'; 3 | import {TranslateService} from '@ngx-translate/core'; 4 | import {AnalysisService} from '../../../core/services/analysis.service'; 5 | import {BrowserOpenService} from '../../../core/services/browser-open.service'; 6 | 7 | @Component({ 8 | selector: 'app-developing', 9 | templateUrl: './developing.component.html', 10 | styleUrls: ['./developing.component.scss'] 11 | }) 12 | export class DevelopingComponent implements OnInit { 13 | @Input() link: string; 14 | @Input() location: string; 15 | constructor( 16 | private snackBar: MatSnackBar, 17 | private analysisService: AnalysisService, 18 | private browserOpenService: BrowserOpenService, 19 | private trans: TranslateService 20 | ) { } 21 | 22 | ngOnInit(): void { 23 | } 24 | 25 | onComeOnClick(): void { 26 | this.analysisService.comeOn(this.location).then(r => {}); 27 | this.trans.get(['MESSAGE.THANKS_FOR_COME_ON','MESSAGE.I_KNOW']).subscribe(res => { 28 | this.snackBar.open(res['MESSAGE.THANKS_FOR_COME_ON'], res['MESSAGE.I_KNOW'], { 29 | duration: 5 * 1000, 30 | }); 31 | }); 32 | } 33 | 34 | onLearnMoreClick(): void { 35 | this.browserOpenService.open(this.link); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /client/src/app/home/mock-page/mock-page.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit, ViewChild} from '@angular/core'; 2 | import { 3 | JsonTableEditorComponent 4 | } from '../../shared/components/api/work-bench/http-work-bench/json-table-editor/json-table-editor.component'; 5 | import {DocJsonTableNode} from "../../core/services/entity/Docs"; 6 | 7 | @Component({ 8 | selector: 'app-mock-page', 9 | templateUrl: './mock-page.component.html', 10 | styleUrls: ['./mock-page.component.scss'] 11 | }) 12 | export class MockPageComponent implements OnInit { 13 | @ViewChild('treeDataEditorComponent', {static: true}) vi: JsonTableEditorComponent; 14 | code = ` 15 | { 16 | "a":"123", 17 | "b":123, 18 | "c": true, 19 | "d": { 20 | "e": "sd", 21 | "f": 123 22 | }, 23 | "g": [ 24 | { 25 | "h": "123", 26 | "i": 89 27 | } 28 | ], 29 | "j":[ 30 | 1,2,3 31 | ], 32 | "k":[ 33 | { 34 | "l":123, 35 | "m": true 36 | } 37 | ] 38 | } 39 | `; 40 | editorOptions = {theme: 'vs-light', language: 'json'}; 41 | readonly = false; 42 | 43 | ngOnInit(): void { 44 | } 45 | 46 | gen() { 47 | this.vi.gen(JSON.parse(this.code)); 48 | } 49 | 50 | onDataC(data: DocJsonTableNode[]) { 51 | console.log('zzq see doc updated', data); 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /server/src/test/java/org/adp/gable/security/service/JwtUserServiceImplTest.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.security.service; 2 | 3 | import org.adp.gable.SupperUser; 4 | import org.junit.jupiter.api.DisplayName; 5 | import org.junit.jupiter.api.Test; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.springframework.security.core.userdetails.UserDetails; 8 | 9 | import javax.annotation.Resource; 10 | import java.util.UUID; 11 | 12 | import static org.junit.jupiter.api.Assertions.*; 13 | 14 | @SpringBootTest 15 | class JwtUserServiceImplTest { 16 | 17 | @Resource 18 | private JwtUserServiceImpl jwtUserService; 19 | 20 | @Test 21 | @DisplayName("test load the user info while login") 22 | public void testLoadUserByEmail() { 23 | final UserDetails userDetails = jwtUserService.loadUserByUsername(SupperUser.USER_EMAIL); 24 | assertNotNull(userDetails); 25 | assertNotNull(userDetails.getAuthorities()); 26 | assertNotEquals(userDetails.getAuthorities(), 0); 27 | assertTrue(userDetails.isAccountNonExpired()); 28 | assertTrue(userDetails.isAccountNonLocked()); 29 | assertTrue(userDetails.isCredentialsNonExpired()); 30 | assertTrue(userDetails.isEnabled()); 31 | final UserDetails user = jwtUserService.loadUserByUsername(UUID.randomUUID().toString()); 32 | assertNull(user); 33 | } 34 | } -------------------------------------------------------------------------------- /server/src/test/java/org/adp/gable/Controller/TestUserController.java: -------------------------------------------------------------------------------- 1 | package org.adp.gable.Controller; 2 | 3 | 4 | import org.springframework.context.annotation.Profile; 5 | import org.springframework.security.access.prepost.PreAuthorize; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | import javax.annotation.security.PermitAll; 11 | 12 | /** 13 | * write for test 14 | * */ 15 | @RestController 16 | @RequestMapping("/api/user") 17 | @Profile("test") 18 | public class TestUserController { 19 | 20 | @GetMapping("testConfigP") 21 | public String testConfigP(){ 22 | return "testConfigP ok"; 23 | } 24 | 25 | @GetMapping("testConfigR") 26 | public String testConfigR(){ 27 | return "testConfigR ok"; 28 | } 29 | 30 | @GetMapping("testAnoP") 31 | @PreAuthorize("hasAuthority('sec_createUser')") 32 | public String testAno(){ 33 | return "testAnoP ok"; 34 | } 35 | 36 | @GetMapping("testAnoR") 37 | @PreAuthorize("hasRole('SUPPER_ROLE')") 38 | public String testAnoR(){ 39 | return "testAnoR ok"; 40 | } 41 | 42 | @GetMapping("testNPE") 43 | @PermitAll 44 | public String testNPE() { 45 | throw new NullPointerException("random"); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /client/src/app/shared/components/docs/http-api-doc/http-api-doc.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 10 | {{ c.name }} 11 | 12 |
13 |
14 | 20 | {{ c.name }} 21 | 22 |
23 |
24 |
25 | 28 |
29 |
30 |
31 |
32 | 33 |
34 |
35 |
36 | -------------------------------------------------------------------------------- /client/src/app/core/services/db.ts: -------------------------------------------------------------------------------- 1 | import Dexie, { Table } from 'dexie'; 2 | import {ApiMenuCollection, ApiMenuItem, OpeningNavTab} from './entity/ApiMenu'; 3 | import {HttpApi} from './entity/HttpApi'; 4 | import {Doc, DocBlock, DocDefine, DocMenu} from './entity/Docs'; 5 | import {ArrayData} from './entity/ArrayData'; 6 | 7 | 8 | export class AppDB extends Dexie { 9 | apiMenus!: Table; 10 | apiMenuItems!: Table; 11 | openingTabs!: Table; 12 | httpApi!: Table; 13 | httpApiCache!: Table; 14 | docs!: Table; 15 | docsMenu!: Table; 16 | docBlocks!: Table; 17 | docDefines!: Table; 18 | arrayData!: Table; 19 | 20 | constructor() { 21 | super('gable'); 22 | this.version(15).stores({ 23 | apiMenus: '++id', 24 | docs: '++id', 25 | apiDefines: '++id', 26 | httpApi: '++id', 27 | httpApiCache: '++id', 28 | docDefines: '++id', 29 | openingTabs: 'tabId', 30 | arrayData: 'id', 31 | docBlocks: '++i,docDefineId', 32 | docsMenu: '++id,docId,level,parentId,apiKey', 33 | apiMenuItems: '++id, collectionId,defineId', 34 | }); 35 | this.on('ready', () => { 36 | console.log('index db load success'); 37 | }); 38 | } 39 | 40 | } 41 | 42 | export const db = new AppDB(); 43 | --------------------------------------------------------------------------------