diff --git a/Dockerfile b/Dockerfile index 20c554c..d16d6f2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM cloudblueconnect/connect-extension-runner:28.8 +FROM cloudblueconnect/connect-extension-runner:28.9 COPY pyproject.toml /install_temp/. COPY poetry.* /install_temp/. diff --git a/connect_ext_ppr/filters.py b/connect_ext_ppr/filters.py index fdc6301..1224f6a 100644 --- a/connect_ext_ppr/filters.py +++ b/connect_ext_ppr/filters.py @@ -1,5 +1,7 @@ from typing import List, Optional + +from pydantic import BaseModel from fastapi_filter import FilterDepends, with_prefix from fastapi_filter.contrib.sqlalchemy import Filter @@ -60,3 +62,7 @@ class DeploymentRequestExtendedFilter(DeploymentRequestFilter): class Constants(Filter.Constants): model = DeploymentRequest + + +class PricingBatchFilter(BaseModel): + marketplace_id: Optional[str] diff --git a/connect_ext_ppr/schemas.py b/connect_ext_ppr/schemas.py index e408603..aa72ed5 100644 --- a/connect_ext_ppr/schemas.py +++ b/connect_ext_ppr/schemas.py @@ -63,6 +63,12 @@ class PrimaryKeyReference(BaseModel): id: str +class ReferenceSchema(NonNullSchema): + id: str + name: Optional[str] + icon: Optional[str] + + class ChoicesSchema(BaseModel): choices: Optional[List[PrimaryKeyReference]] = [] all: bool @@ -74,23 +80,11 @@ def check_choices_exists_if_all_is_false(cls, values): return values -class VendorSchema(NonNullSchema): - id: str - name: str - icon: Optional[str] - - -class ProductReferenceSchema(NonNullSchema): - id: str - name: str - icon: Optional[str] - - class ProductSchema(NonNullSchema): id: str name: str icon: Optional[str] - owner: VendorSchema + owner: ReferenceSchema class HubReferenceSchema(NonNullSchema): @@ -106,10 +100,10 @@ class HubSchema(NonNullSchema): class DeploymentSchema(NonNullSchema): id: str - product: ProductReferenceSchema + product: ReferenceSchema hub: HubReferenceSchema account_id: str - owner: VendorSchema + owner: ReferenceSchema last_sync_at: datetime status: DeploymentStatusChoices events: Events @@ -167,7 +161,7 @@ class PPRVersionReferenceSchema(NonNullSchema): class DeploymentReferenceSchema(NonNullSchema): id: str - product: ProductReferenceSchema + product: ReferenceSchema hub: HubReferenceSchema @@ -184,10 +178,17 @@ class Config: orm_mode = True +class StreamContextSchema(NonNullSchema): + account: ReferenceSchema + product: ReferenceSchema + marketplace: ReferenceSchema + + class StreamSchema(NonNullSchema): id: str name: str status: str + context: StreamContextSchema class BatchSchema(NonNullSchema): diff --git a/connect_ext_ppr/static/index.36fb1b65206989e793c7.js b/connect_ext_ppr/static/index.2e78270930bf4bf36c38.js similarity index 99% rename from connect_ext_ppr/static/index.36fb1b65206989e793c7.js rename to connect_ext_ppr/static/index.2e78270930bf4bf36c38.js index 2422f18..12282be 100644 --- a/connect_ext_ppr/static/index.36fb1b65206989e793c7.js +++ b/connect_ext_ppr/static/index.2e78270930bf4bf36c38.js @@ -543,7 +543,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _components_cDialog_vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ~components/cDialog.vue */ \"./ui/src/components/cDialog.vue\");\n/* harmony import */ var _HubsTab_vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./HubsTab.vue */ \"./ui/src/components/CreateDeploymentRequestDialog/HubsTab.vue\");\n/* harmony import */ var _MarketplacesTab_vue__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./MarketplacesTab.vue */ \"./ui/src/components/CreateDeploymentRequestDialog/MarketplacesTab.vue\");\n/* harmony import */ var _OptionsTab_vue__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./OptionsTab.vue */ \"./ui/src/components/CreateDeploymentRequestDialog/OptionsTab.vue\");\n/* harmony import */ var _ProductsTab_vue__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./ProductsTab.vue */ \"./ui/src/components/CreateDeploymentRequestDialog/ProductsTab.vue\");\n/* harmony import */ var _PprTab_vue__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./PprTab.vue */ \"./ui/src/components/CreateDeploymentRequestDialog/PprTab.vue\");\n/* harmony import */ var _SummaryTab_vue__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./SummaryTab.vue */ \"./ui/src/components/CreateDeploymentRequestDialog/SummaryTab.vue\");\n/* harmony import */ var _mixins_sync__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ~mixins/sync */ \"./ui/src/tools/mixins/sync.js\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @/utils */ \"./ui/src/utils.js\");\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst defaultForm = () => ({\n product: {},\n hub: {},\n ppr: {},\n marketplaces: {\n choices: [],\n all: false,\n },\n options: {\n manual: false,\n delegate: false,\n },\n});\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n mixins: [(0,_mixins_sync__WEBPACK_IMPORTED_MODULE_7__[\"default\"])([{ prop: 'value', local: 'localValue' }])],\n\n components: {\n cDialog: _components_cDialog_vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"],\n HubsTab: _HubsTab_vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"],\n MarketplacesTab: _MarketplacesTab_vue__WEBPACK_IMPORTED_MODULE_2__[\"default\"],\n OptionsTab: _OptionsTab_vue__WEBPACK_IMPORTED_MODULE_3__[\"default\"],\n ProductsTab: _ProductsTab_vue__WEBPACK_IMPORTED_MODULE_4__[\"default\"],\n PprTab: _PprTab_vue__WEBPACK_IMPORTED_MODULE_5__[\"default\"],\n SummaryTab: _SummaryTab_vue__WEBPACK_IMPORTED_MODULE_6__[\"default\"],\n },\n\n props: {\n value: Boolean,\n deployment: {\n type: Object,\n default: () => null,\n },\n },\n\n data: () => ({\n localValue: false,\n currentTab: null,\n form: defaultForm(),\n createdRequest: null,\n localDeployment: null,\n errorText: '',\n }),\n\n computed: {\n tabs: vm => [\n {\n key: 'product',\n label: 'Product',\n assistiveText: vm.form.product?.name,\n },\n {\n key: 'hub',\n label: 'Hub',\n assistiveText: vm.form.hub?.name,\n },\n {\n key: 'ppr',\n label: 'PPR',\n assistiveText: vm.form.ppr?.version ? `Version ${vm.form.ppr.version}` : undefined,\n },\n {\n key: 'marketplaces',\n label: 'Marketplaces',\n assistiveText: vm.form.marketplaces.all ? 'All' : vm.form.marketplaces?.choices.map(mp => mp.id).join(', '),\n },\n {\n key: 'options',\n label: 'Options',\n },\n {\n key: 'summary',\n label: 'Summary',\n },\n ],\n\n currentStep: vm => vm.tabs.findIndex(tab => tab.key === vm.currentTab?.key) + 1,\n\n currentStepText: ({ currentStep, isLastStep }) => (isLastStep ? 'Summary' : `Step ${currentStep}`),\n isLastStep: ({ tabs, currentStep }) => currentStep === tabs.length,\n isFirstStep: ({ currentStep }) => currentStep === 1,\n isPreviousToLastStep: ({ tabs, currentStep }) => currentStep === tabs.length - 1,\n\n isCurrentTabValid: vm => {\n const key = vm.currentTab?.key;\n const currentTabForm = vm.form[key];\n\n if (!key || !currentTabForm) return false;\n\n if (key === 'product' || key === 'hub') return !!currentTabForm.id;\n if (key === 'ppr') return !!currentTabForm.version;\n if (key === 'marketplaces') return !!currentTabForm.all || !!currentTabForm.choices.length;\n\n return true;\n },\n\n defaultTabActions: vm => [\n {\n label: 'Cancel',\n closeAfterHandle: true,\n color: '#212121',\n },\n { type: 'spacer' },\n {\n label: 'Back',\n handler: vm.goToPreviousStep,\n disabled: vm.isFirstStep,\n closeAfterHandle: false,\n color: '#212121',\n },\n {\n label: vm.isPreviousToLastStep ? 'Create' : 'Next',\n handler: vm.nextStepHandler,\n disabled: !vm.isCurrentTabValid,\n closeAfterHandle: false,\n color: '#2C98F0',\n },\n ],\n\n nextStepHandler: vm => {\n // Create deployment request before summary tab\n if (vm.isPreviousToLastStep) return vm.createDeploymentRequest;\n // Fetch deployment after we get product and hub\n if (vm.currentTab?.key === 'hub') return vm.fetchDeployment;\n\n return vm.goToNextStep;\n },\n\n summaryTabActions: vm => [\n {\n label: 'Go to details',\n handler: vm.goToDetails,\n closeAfterHandle: true,\n color: '#212121',\n },\n {\n label: 'Close',\n handler: () => vm.$emit('request-created'),\n closeAfterHandle: true,\n color: '#212121',\n },\n ],\n\n currentTabActions: vm => (vm.isLastStep ? vm.summaryTabActions : vm.defaultTabActions),\n },\n\n methods: {\n goToPreviousStep() {\n this.$refs.dialog.previousStep();\n },\n\n goToNextStep() {\n this.$refs.dialog.nextStep();\n },\n\n async createDeploymentRequest() {\n this.createdRequest = await (0,_utils__WEBPACK_IMPORTED_MODULE_8__.createDeploymentRequest)({\n marketplaces: this.form.marketplaces,\n deployment: { id: this.localDeployment.id },\n ppr: { id: this.form.ppr.id },\n manually: this.form.options.manual,\n delegate_l2: this.form.options.delegate,\n });\n\n this.goToNextStep();\n },\n\n async fetchDeployment() {\n if (this.deployment) return;\n\n [this.localDeployment] = await (0,_utils__WEBPACK_IMPORTED_MODULE_8__.getDeployments)({\n hubId: this.form.hub.id,\n productId: this.form.product.id,\n });\n\n this.goToNextStep();\n },\n\n goToDetails() {\n this.$router.push({ name: 'RequestDetails', params: { id: this.createdRequest.id } });\n },\n\n onTabChange(tab) {\n this.currentTab = tab;\n },\n\n setError(e) {\n this.errorText = e.message;\n },\n },\n\n watch: {\n async localValue(v) {\n if (!v) {\n this.form = defaultForm();\n } else if (this.deployment) {\n this.localDeployment = this.deployment;\n this.form.hub = this.deployment.hub;\n this.form.product = this.deployment.product;\n\n await this.$nextTick();\n this.$refs.dialog.activeTab = 'ppr';\n }\n },\n },\n});\n\n\n\n//# sourceURL=webpack://connect-extension-xvs/./ui/src/components/CreateDeploymentRequestDialog/index.vue?./node_modules/vue-loader/lib/index.js??vue-loader-options"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _components_cDialog_vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ~components/cDialog.vue */ \"./ui/src/components/cDialog.vue\");\n/* harmony import */ var _HubsTab_vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./HubsTab.vue */ \"./ui/src/components/CreateDeploymentRequestDialog/HubsTab.vue\");\n/* harmony import */ var _MarketplacesTab_vue__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./MarketplacesTab.vue */ \"./ui/src/components/CreateDeploymentRequestDialog/MarketplacesTab.vue\");\n/* harmony import */ var _OptionsTab_vue__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./OptionsTab.vue */ \"./ui/src/components/CreateDeploymentRequestDialog/OptionsTab.vue\");\n/* harmony import */ var _ProductsTab_vue__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./ProductsTab.vue */ \"./ui/src/components/CreateDeploymentRequestDialog/ProductsTab.vue\");\n/* harmony import */ var _PprTab_vue__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./PprTab.vue */ \"./ui/src/components/CreateDeploymentRequestDialog/PprTab.vue\");\n/* harmony import */ var _SummaryTab_vue__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./SummaryTab.vue */ \"./ui/src/components/CreateDeploymentRequestDialog/SummaryTab.vue\");\n/* harmony import */ var _mixins_sync__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ~mixins/sync */ \"./ui/src/tools/mixins/sync.js\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @/utils */ \"./ui/src/utils.js\");\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst defaultForm = () => ({\n product: {},\n hub: {},\n ppr: {},\n marketplaces: {\n choices: [],\n all: false,\n },\n options: {\n manual: false,\n delegate: false,\n },\n});\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n mixins: [(0,_mixins_sync__WEBPACK_IMPORTED_MODULE_7__[\"default\"])([{ prop: 'value', local: 'localValue' }])],\n\n components: {\n cDialog: _components_cDialog_vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"],\n HubsTab: _HubsTab_vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"],\n MarketplacesTab: _MarketplacesTab_vue__WEBPACK_IMPORTED_MODULE_2__[\"default\"],\n OptionsTab: _OptionsTab_vue__WEBPACK_IMPORTED_MODULE_3__[\"default\"],\n ProductsTab: _ProductsTab_vue__WEBPACK_IMPORTED_MODULE_4__[\"default\"],\n PprTab: _PprTab_vue__WEBPACK_IMPORTED_MODULE_5__[\"default\"],\n SummaryTab: _SummaryTab_vue__WEBPACK_IMPORTED_MODULE_6__[\"default\"],\n },\n\n props: {\n value: Boolean,\n deployment: {\n type: Object,\n default: () => null,\n },\n },\n\n data: () => ({\n localValue: false,\n currentTab: null,\n form: defaultForm(),\n createdRequest: null,\n localDeployment: null,\n errorText: '',\n }),\n\n computed: {\n tabs: vm => [\n {\n key: 'product',\n label: 'Product',\n assistiveText: vm.form.product?.name,\n },\n {\n key: 'hub',\n label: 'Hub',\n assistiveText: vm.form.hub?.name,\n },\n {\n key: 'ppr',\n label: 'PPR',\n assistiveText: vm.form.ppr?.version ? `Version ${vm.form.ppr.version}` : undefined,\n },\n {\n key: 'marketplaces',\n label: 'Marketplaces',\n assistiveText: vm.form.marketplaces.all ? 'All' : vm.form.marketplaces?.choices.map(mp => mp.id).join(', '),\n },\n {\n key: 'options',\n label: 'Options',\n },\n {\n key: 'summary',\n label: 'Summary',\n },\n ],\n\n currentStep: vm => vm.tabs.findIndex(tab => tab.key === vm.currentTab?.key) + 1,\n\n currentStepText: ({ currentStep, isLastStep }) => (isLastStep ? 'Summary' : `Step ${currentStep}`),\n isLastStep: ({ tabs, currentStep }) => currentStep === tabs.length,\n isFirstStep: ({ currentStep }) => currentStep === 1,\n isPreviousToLastStep: ({ tabs, currentStep }) => currentStep === tabs.length - 1,\n\n isCurrentTabValid: vm => {\n const key = vm.currentTab?.key;\n const currentTabForm = vm.form[key];\n\n if (!key || !currentTabForm) return false;\n\n if (key === 'product' || key === 'hub') return !!currentTabForm.id;\n if (key === 'ppr') return !!currentTabForm.version;\n if (key === 'marketplaces') return !!currentTabForm.all || !!currentTabForm.choices.length;\n\n return true;\n },\n\n defaultTabActions: vm => [\n {\n label: 'Cancel',\n closeAfterHandle: true,\n color: '#212121',\n },\n { type: 'spacer' },\n {\n label: 'Back',\n handler: vm.goToPreviousStep,\n disabled: vm.isFirstStep,\n closeAfterHandle: false,\n color: '#212121',\n },\n {\n label: vm.isPreviousToLastStep ? 'Create' : 'Next',\n handler: vm.nextStepHandler,\n disabled: !vm.isCurrentTabValid,\n closeAfterHandle: false,\n color: '#2C98F0',\n },\n ],\n\n nextStepHandler: vm => {\n // Create deployment request before summary tab\n if (vm.isPreviousToLastStep) return vm.createDeploymentRequest;\n // Fetch deployment after we get product and hub\n if (vm.currentTab?.key === 'hub') return vm.fetchDeployment;\n\n return vm.goToNextStep;\n },\n\n summaryTabActions: vm => [\n {\n label: 'Go to details',\n handler: vm.goToDetails,\n closeAfterHandle: true,\n color: '#212121',\n },\n {\n label: 'Close',\n handler: () => vm.$emit('request-created'),\n closeAfterHandle: true,\n color: '#212121',\n },\n ],\n\n currentTabActions: vm => (vm.isLastStep ? vm.summaryTabActions : vm.defaultTabActions),\n },\n\n methods: {\n goToPreviousStep() {\n this.$refs.dialog.previousStep();\n },\n\n goToNextStep() {\n this.$refs.dialog.nextStep();\n },\n\n async createDeploymentRequest() {\n this.createdRequest = await (0,_utils__WEBPACK_IMPORTED_MODULE_8__.createDeploymentRequest)({\n marketplaces: this.form.marketplaces.choices,\n deployment: { id: this.localDeployment.id },\n ppr: { id: this.form.ppr.id },\n manually: this.form.options.manual,\n delegate_l2: this.form.options.delegate,\n });\n\n this.goToNextStep();\n },\n\n async fetchDeployment() {\n if (this.deployment) return;\n\n [this.localDeployment] = await (0,_utils__WEBPACK_IMPORTED_MODULE_8__.getDeployments)({\n hubId: this.form.hub.id,\n productId: this.form.product.id,\n });\n\n this.goToNextStep();\n },\n\n goToDetails() {\n this.$router.push({ name: 'RequestDetails', params: { id: this.createdRequest.id } });\n },\n\n onTabChange(tab) {\n this.currentTab = tab;\n },\n\n setError(e) {\n this.errorText = e.message;\n },\n },\n\n watch: {\n async localValue(v) {\n if (!v) {\n this.form = defaultForm();\n } else if (this.deployment) {\n this.localDeployment = this.deployment;\n this.form.hub = this.deployment.hub;\n this.form.product = this.deployment.product;\n\n await this.$nextTick();\n this.$refs.dialog.activeTab = 'ppr';\n }\n },\n },\n});\n\n\n\n//# sourceURL=webpack://connect-extension-xvs/./ui/src/components/CreateDeploymentRequestDialog/index.vue?./node_modules/vue-loader/lib/index.js??vue-loader-options"); /***/ }), diff --git a/connect_ext_ppr/static/index.html b/connect_ext_ppr/static/index.html index 841103b..aa659c4 100644 --- a/connect_ext_ppr/static/index.html +++ b/connect_ext_ppr/static/index.html @@ -12,7 +12,7 @@