From 6e1827c793e4700c5f23c77b42f34d6d2e44b550 Mon Sep 17 00:00:00 2001 From: Maxime Bajeux Date: Thu, 17 Oct 2024 09:06:19 +0200 Subject: [PATCH] feat(billing): init the application Signed-off-by: Maxime Bajeux --- packages/manager/apps/billing/.eslintrc.json | 6 + packages/manager/apps/billing/README.md | 0 packages/manager/apps/billing/package.json | 72 ++++++++ .../manager/apps/billing/src/app.module.js | 154 ++++++++++++++++++ .../apps/billing/src/error/error.module.js | 9 + .../apps/billing/src/error/error.routing.js | 17 ++ .../manager/apps/billing/src/error/index.js | 22 +++ packages/manager/apps/billing/src/index.html | 16 ++ packages/manager/apps/billing/src/index.js | 29 ++++ .../src/tracking/at-internet.constants.js | 12 ++ .../manager/apps/billing/webpack.config.js | 73 +++++++++ 11 files changed, 410 insertions(+) create mode 100644 packages/manager/apps/billing/.eslintrc.json create mode 100644 packages/manager/apps/billing/README.md create mode 100644 packages/manager/apps/billing/package.json create mode 100644 packages/manager/apps/billing/src/app.module.js create mode 100644 packages/manager/apps/billing/src/error/error.module.js create mode 100644 packages/manager/apps/billing/src/error/error.routing.js create mode 100644 packages/manager/apps/billing/src/error/index.js create mode 100644 packages/manager/apps/billing/src/index.html create mode 100644 packages/manager/apps/billing/src/index.js create mode 100644 packages/manager/apps/billing/src/tracking/at-internet.constants.js create mode 100644 packages/manager/apps/billing/webpack.config.js diff --git a/packages/manager/apps/billing/.eslintrc.json b/packages/manager/apps/billing/.eslintrc.json new file mode 100644 index 000000000000..383e2831c19a --- /dev/null +++ b/packages/manager/apps/billing/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "globals": { + "__VERSION__": true, + "__NG_APP_INJECTIONS__": true + } +} diff --git a/packages/manager/apps/billing/README.md b/packages/manager/apps/billing/README.md new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/manager/apps/billing/package.json b/packages/manager/apps/billing/package.json new file mode 100644 index 000000000000..dabedf703b83 --- /dev/null +++ b/packages/manager/apps/billing/package.json @@ -0,0 +1,72 @@ +{ + "name": "@ovh-ux/manager-billing-app", + "version": "0.0.0", + "private": true, + "description": "OVHcloud Billing app", + "repository": { + "type": "git", + "url": "git+https://github.com/ovh/manager.git", + "directory": "packages/manager/apps/billing" + }, + "license": "BSD-3-Clause", + "author": "OVH SAS", + "scripts": { + "build": "webpack --env production", + "dev": "webpack-dev-server", + "dev:watch": "yarn run dev", + "start": "lerna exec --stream --scope='@ovh-ux/manager-billing-app' --include-dependencies -- npm run build --if-present", + "start:dev": "lerna exec --stream --scope='@ovh-ux/manager-billing-app' --include-dependencies -- npm run dev --if-present", + "start:watch": "lerna exec --stream --parallel --scope='@ovh-ux/manager-billing-app' --include-dependencies -- npm run dev:watch --if-present" + }, + "dependencies": { + "@ovh-ux/manager-at-internet-configuration": "^1.5.0", + "@ovh-ux/manager-billing": "^0.20.0-alpha.45", + "@ovh-ux/manager-config": "^7.0.0", + "@ovh-ux/manager-core": "^12.0.0 || ^13.0.0", + "@ovh-ux/manager-error-page": "^2.3.1", + "@ovh-ux/manager-ng-layout-helpers": "^2.6.1", + "@ovh-ux/ng-at-internet": "^5.11.13", + "@ovh-ux/ng-at-internet-ui-router-plugin": "^3.5.0", + "@ovh-ux/ng-ovh-api-wrappers": "^5.0.0", + "@ovh-ux/ng-ovh-http": "^5.0.0", + "@ovh-ux/ng-ovh-request-tagger": "^1.1.7", + "@ovh-ux/ng-ovh-sso-auth": "^4.6.3", + "@ovh-ux/ng-ovh-swimming-poll": "^5.0.6", + "@ovh-ux/ng-shell-tracking": "^0.2.1", + "@ovh-ux/ng-translate-async-loader": "^2.1.5", + "@ovh-ux/ng-ui-router-breadcrumb": "^1.1.7", + "@ovh-ux/request-tagger": "^0.1.1", + "@ovh-ux/shell": "^2.0.0", + "@ovh-ux/ui-kit": "^6.5.1", + "@uirouter/angularjs": "^1.0.23", + "angular": "^1.7.5", + "angular-aria": "^1.7.8", + "angular-cookies": "^1.7.8", + "angular-dynamic-locale": "^0.1.37", + "angular-i18n": "^1.7.8", + "angular-resource": "^1.7.8", + "angular-sanitize": "^1.7.8", + "angular-translate": "^2.18.1", + "angular-translate-loader-pluggable": "^1.3.1", + "core-js": "^3.6.5", + "flatpickr": "~4.6.3", + "jquery": "^2.1.3", + "lodash-es": "^4.17.15", + "oclazyload": "^1.1.0", + "ovh-api-services": "^16.0.0", + "regenerator-runtime": "^0.13.7", + "whatwg-fetch": "^3.5.0" + }, + "devDependencies": { + "@ovh-ux/manager-webpack-config": "^6.1.1", + "glob": "^7.1.6", + "lodash": "^4.17.15", + "webpack": "^4.44.2", + "webpack-merge": "^4.2.2" + }, + "regions": [ + "CA", + "EU", + "US" + ] +} diff --git a/packages/manager/apps/billing/src/app.module.js b/packages/manager/apps/billing/src/app.module.js new file mode 100644 index 000000000000..1f04acdfee9a --- /dev/null +++ b/packages/manager/apps/billing/src/app.module.js @@ -0,0 +1,154 @@ +import angular from 'angular'; +import get from 'lodash/get'; +import has from 'lodash/has'; +import isString from 'lodash/isString'; +import uiRouter, { RejectType } from '@uirouter/angularjs'; +import '@ovh-ux/ui-kit'; +import '@ovh-ux/ng-at-internet'; +import { isTopLevelApplication } from '@ovh-ux/manager-config'; +import { registerCoreModule } from '@ovh-ux/manager-core'; +import ngOvhSsoAuth from '@ovh-ux/ng-ovh-sso-auth'; +import ngUiRouterBreadcrumb from '@ovh-ux/ng-ui-router-breadcrumb'; +import ovhManagerAtInternetConfiguration from '@ovh-ux/manager-at-internet-configuration'; +import { registerAtInternet } from '@ovh-ux/ng-shell-tracking'; +// TODO: Change to '@ovh-ux/manager-billing' when module is deployed +// import Billing from '@ovh-ux/manager-billing'; +import Billing from '../../../modules/billing/src'; +import errorPage from './error'; + +import TRACKING from './tracking/at-internet.constants'; +import '@ovh-ux/ui-kit/dist/css/oui.css'; + +export default async (containerEl, shellClient) => { + const moduleName = 'BillingApp'; + + const routingConfig = /* @ngInject */ ($urlRouterProvider) => { + $urlRouterProvider.otherwise('/billing'); + }; + + const trackingConfig = /* @ngInject */ (atInternetConfigurationProvider) => { + atInternetConfigurationProvider.setSkipInit(true); + atInternetConfigurationProvider.setPrefix('BillingApp'); + }; + + const [environment, locale] = await Promise.all([ + shellClient.environment.getEnvironment(), + shellClient.i18n.getLocale(), + ]); + + const coreCallbacks = { + onLocaleChange: (lang) => { + shellClient.i18n.setLocale(lang); + }, + }; + + const ssoAuthConfig = /* @ngInject */ (ssoAuthenticationProvider) => { + ssoAuthenticationProvider.setOnLogin(() => { + shellClient.auth.login(); + }); + ssoAuthenticationProvider.setOnLogout(() => { + shellClient.auth.logout(); + }); + }; + + const calendarConfigProvider = /* @ngInject */ ( + ouiCalendarConfigurationProvider, + ) => { + const [lang] = locale.split('_'); + return import(`flatpickr/dist/l10n/${lang}.js`) + .then((module) => { + ouiCalendarConfigurationProvider.setLocale(module.default[lang]); + }) + .catch(() => {}); + }; + + const broadcastAppStarted = /* @ngInject */ ($rootScope, $transitions) => { + const unregisterHook = $transitions.onSuccess({}, async () => { + if (!isTopLevelApplication()) { + await shellClient.ux.hidePreloader(); + } + $rootScope.$broadcast('app:started'); + unregisterHook(); + }); + }; + + const transitionsConfig = /* @ngInject */ ($transitions) => { + if (!isTopLevelApplication()) { + $transitions.onBefore({}, (transition) => { + if ( + !transition.ignored() && + transition.from().name !== '' && + transition.entering().length > 0 + ) { + shellClient.ux.startProgress(); + } + }); + + $transitions.onSuccess({}, () => { + shellClient.ux.stopProgress(); + }); + + $transitions.onError({}, (transition) => { + if (!transition.error().redirected) { + shellClient.ux.stopProgress(); + } + }); + } + }; + + const defaultErrorHandler = /* @ngInject */ ($state) => { + $state.defaultErrorHandler((error) => { + if (error.type === RejectType.ERROR) { + $state.go( + 'error', + { + detail: { + message: get(error.detail, 'data.message'), + code: has(error.detail, 'headers') + ? error.detail.headers('x-ovh-queryId') + : null, + }, + }, + { location: false }, + ); + } + }); + }; + + angular + .module( + moduleName, + [ + registerCoreModule(environment, coreCallbacks), + registerAtInternet(shellClient.tracking), + ovhManagerAtInternetConfiguration, + ngOvhSsoAuth, + ngUiRouterBreadcrumb, + 'oui', + uiRouter, + errorPage, + Billing, + ...get(__NG_APP_INJECTIONS__, environment.getRegion(), []), + ].filter(isString), + ) + .constant('shellClient', shellClient) + .config( + /* @ngInject */ ($locationProvider) => $locationProvider.hashPrefix(''), + ) + .config(routingConfig) + .config(ssoAuthConfig) + .config(async () => { + await shellClient.tracking.setConfig(environment.getRegion(), TRACKING); + }) + .config(trackingConfig) + .config(calendarConfigProvider) + .run(broadcastAppStarted) + .run(transitionsConfig) + .run(defaultErrorHandler); + + angular.bootstrap(containerEl, [moduleName], { + strictDi: true, + }); + + return moduleName; +}; diff --git a/packages/manager/apps/billing/src/error/error.module.js b/packages/manager/apps/billing/src/error/error.module.js new file mode 100644 index 000000000000..acc727b16dd4 --- /dev/null +++ b/packages/manager/apps/billing/src/error/error.module.js @@ -0,0 +1,9 @@ +import managerErrorPage from '@ovh-ux/manager-error-page'; + +import routing from './error.routing'; + +const moduleName = 'ovhManagerBillingError'; + +angular.module(moduleName, [managerErrorPage]).config(routing); + +export default moduleName; diff --git a/packages/manager/apps/billing/src/error/error.routing.js b/packages/manager/apps/billing/src/error/error.routing.js new file mode 100644 index 000000000000..45bb318d8ac9 --- /dev/null +++ b/packages/manager/apps/billing/src/error/error.routing.js @@ -0,0 +1,17 @@ +export default /* @ngInject */ ($stateProvider) => { + $stateProvider.state('error', { + params: { + detail: null, + }, + url: '/error', + component: 'managerErrorPage', + resolve: { + cancelLink: /* @ngInject */ ($state) => $state.href('app'), + error: /* @ngInject */ ($transition$) => $transition$.params(), + submitAction: /* @ngInject */ ($window) => () => + $window.location.reload(), + translationsRefresh: /* @ngInject */ ($translate) => $translate.refresh(), + breadcrumb: () => null, + }, + }); +}; diff --git a/packages/manager/apps/billing/src/error/index.js b/packages/manager/apps/billing/src/error/index.js new file mode 100644 index 000000000000..331942589301 --- /dev/null +++ b/packages/manager/apps/billing/src/error/index.js @@ -0,0 +1,22 @@ +import angular from 'angular'; +import '@uirouter/angularjs'; +import 'oclazyload'; + +const moduleName = 'ovhManagerBillingErrorPageLazyLoading'; + +angular.module(moduleName, ['ui.router', 'oc.lazyLoad']).config( + /* @ngInject */ ($stateProvider) => { + $stateProvider.state('error.**', { + url: '/error', + lazyLoad: ($transition$) => { + const $ocLazyLoad = $transition$.injector().get('$ocLazyLoad'); + + return import('./error.module').then((mod) => + $ocLazyLoad.inject(mod.default || mod), + ); + }, + }); + }, +); + +export default moduleName; diff --git a/packages/manager/apps/billing/src/index.html b/packages/manager/apps/billing/src/index.html new file mode 100644 index 000000000000..d4ba5a63fae9 --- /dev/null +++ b/packages/manager/apps/billing/src/index.html @@ -0,0 +1,16 @@ + + + + + Billing App + + + + +
+ + diff --git a/packages/manager/apps/billing/src/index.js b/packages/manager/apps/billing/src/index.js new file mode 100644 index 000000000000..dd90a62dbd64 --- /dev/null +++ b/packages/manager/apps/billing/src/index.js @@ -0,0 +1,29 @@ +import 'script-loader!jquery'; // eslint-disable-line +import 'core-js/stable'; +import 'whatwg-fetch'; +import 'regenerator-runtime/runtime'; + +import { isTopLevelApplication } from '@ovh-ux/manager-config'; +import { defineApplicationVersion } from '@ovh-ux/request-tagger'; + +import { initShellClient } from '@ovh-ux/shell'; + +defineApplicationVersion(__VERSION__); + +initShellClient('billing').then((shellClient) => { + if (!isTopLevelApplication()) { + shellClient.ux.startProgress(); + } + shellClient.i18n.onLocaleChange(() => { + window.top.location.reload(); + }); + shellClient.environment.getEnvironment().then((environment) => { + environment.setVersion(__VERSION__); + import(`./config-${environment.getRegion()}`) + .catch(() => {}) + .then(() => import('./app.module')) + .then(({ default: startApplication }) => { + startApplication(document.body, shellClient); + }); + }); +}); diff --git a/packages/manager/apps/billing/src/tracking/at-internet.constants.js b/packages/manager/apps/billing/src/tracking/at-internet.constants.js new file mode 100644 index 000000000000..891c58d1be61 --- /dev/null +++ b/packages/manager/apps/billing/src/tracking/at-internet.constants.js @@ -0,0 +1,12 @@ +export default { + EU: { + config: { + level2: '', + }, + }, + CA: { + config: { + level2: '', + }, + }, +}; diff --git a/packages/manager/apps/billing/webpack.config.js b/packages/manager/apps/billing/webpack.config.js new file mode 100644 index 000000000000..c94ca66e47c7 --- /dev/null +++ b/packages/manager/apps/billing/webpack.config.js @@ -0,0 +1,73 @@ +const fs = require('fs'); +const glob = require('glob'); +const path = require('path'); +const webpack = require('webpack'); // eslint-disable-line +const merge = require('webpack-merge'); +const webpackConfig = require('@ovh-ux/manager-webpack-config'); + +function readNgAppInjections(file) { + let injections = []; + if (fs.existsSync(file)) { + injections = fs + .readFileSync(file, 'utf8') + .split('\n') + .filter((value) => value !== ''); + } + return injections; +} + +function getNgAppInjections(regions) { + return regions.reduce((ngAppInjections, region) => { + const injections = [ + ...readNgAppInjections(`./.extras-${region}/ng-app-injections`), + ...readNgAppInjections('./.extras/ng-app-injections'), + ]; + + return { + ...ngAppInjections, + [region]: JSON.stringify(injections), + }; + }, {}); +} + +module.exports = (env = {}) => { + const { config } = webpackConfig( + { + template: './src/index.html', + basePath: './src', + lessPath: ['./node_modules'], + root: path.resolve(__dirname, './src'), + }, + env, + ); + + // Extra config files + const extras = glob.sync(`./.extras/**/*.js`); + + return merge(config, { + entry: { + main: path.resolve('./src/index.js'), + ...(extras.length > 0 ? { extras } : {}), + }, + output: { + path: path.join(__dirname, 'dist'), + filename: '[name].[chunkhash].bundle.js', + }, + resolve: { + modules: [ + './node_modules', + path.resolve(__dirname, 'node_modules'), + path.resolve(__dirname, '../../../node_modules'), + ], + mainFields: ['module', 'browser', 'main'], + }, + plugins: [ + new webpack.DefinePlugin({ + __NODE_ENV__: process.env.NODE_ENV + ? `'${process.env.NODE_ENV}'` + : '"development"', + __NG_APP_INJECTIONS__: getNgAppInjections(['EU', 'CA', 'US']), + }), + ], + }); +};