diff --git a/app/docker/react/components/templates.ts b/app/docker/react/components/templates.ts index cbccc3dcb..f92e1a5df 100644 --- a/app/docker/react/components/templates.ts +++ b/app/docker/react/components/templates.ts @@ -1,17 +1,6 @@ import angular from 'angular'; -import { r2a } from '@/react-tools/react2angular'; -import { withCurrentUser } from '@/react-tools/withCurrentUser'; -import { withUIRouter } from '@/react-tools/withUIRouter'; -import { StackFromCustomTemplateFormWidget } from '@/react/docker/templates/StackFromCustomTemplateFormWidget'; - -export const templatesModule = angular - .module('portainer.docker.react.components.templates', []) - - .component( - 'stackFromCustomTemplateFormWidget', - r2a(withUIRouter(withCurrentUser(StackFromCustomTemplateFormWidget)), [ - 'template', - 'unselect', - ]) - ).name; +export const templatesModule = angular.module( + 'portainer.docker.react.components.templates', + [] +).name; diff --git a/app/edge/__module.js b/app/edge/__module.js index 32f606220..433dd6214 100644 --- a/app/edge/__module.js +++ b/app/edge/__module.js @@ -166,7 +166,7 @@ angular url: '/custom', views: { 'content@': { - component: 'edgeCustomTemplatesView', + component: 'customTemplatesView', }, }, data: { diff --git a/app/edge/react/views/templates.ts b/app/edge/react/views/templates.ts index effa45af5..b86345b6e 100644 --- a/app/edge/react/views/templates.ts +++ b/app/edge/react/views/templates.ts @@ -1,13 +1,6 @@ import angular from 'angular'; -import { r2a } from '@/react-tools/react2angular'; -import { withCurrentUser } from '@/react-tools/withCurrentUser'; -import { withUIRouter } from '@/react-tools/withUIRouter'; -import { ListView } from '@/react/edge/templates/custom-templates/ListView'; - -export const templatesModule = angular - .module('portainer.edge.react.views.templates', []) - .component( - 'edgeCustomTemplatesView', - r2a(withCurrentUser(withUIRouter(ListView)), []) - ).name; +export const templatesModule = angular.module( + 'portainer.edge.react.views.templates', + [] +).name; diff --git a/app/kubernetes/custom-templates/index.js b/app/kubernetes/custom-templates/index.js index 5b83845f3..01d8a3260 100644 --- a/app/kubernetes/custom-templates/index.js +++ b/app/kubernetes/custom-templates/index.js @@ -1,8 +1,6 @@ import angular from 'angular'; -import { kubeCustomTemplatesView } from './kube-custom-templates-view'; - -export default angular.module('portainer.kubernetes.custom-templates', []).config(config).component('kubeCustomTemplatesView', kubeCustomTemplatesView).name; +export default angular.module('portainer.kubernetes.custom-templates', []).config(config).name; function config($stateRegistryProvider) { const templates = { @@ -17,7 +15,7 @@ function config($stateRegistryProvider) { views: { 'content@': { - component: 'kubeCustomTemplatesView', + component: 'customTemplatesView', }, }, data: { diff --git a/app/kubernetes/custom-templates/kube-custom-templates-view/index.js b/app/kubernetes/custom-templates/kube-custom-templates-view/index.js deleted file mode 100644 index 4c2d1115f..000000000 --- a/app/kubernetes/custom-templates/kube-custom-templates-view/index.js +++ /dev/null @@ -1,6 +0,0 @@ -import controller from './kube-custom-templates-view.controller.js'; - -export const kubeCustomTemplatesView = { - templateUrl: './kube-custom-templates-view.html', - controller, -}; diff --git a/app/kubernetes/custom-templates/kube-custom-templates-view/kube-custom-templates-view.controller.js b/app/kubernetes/custom-templates/kube-custom-templates-view/kube-custom-templates-view.controller.js deleted file mode 100644 index 9580855f8..000000000 --- a/app/kubernetes/custom-templates/kube-custom-templates-view/kube-custom-templates-view.controller.js +++ /dev/null @@ -1,83 +0,0 @@ -import _ from 'lodash-es'; -import { confirmDelete } from '@@/modals/confirm'; - -export default class KubeCustomTemplatesViewController { - /* @ngInject */ - constructor($async, $state, Authentication, CustomTemplateService, FormValidator, Notifications) { - Object.assign(this, { $async, $state, Authentication, CustomTemplateService, FormValidator, Notifications }); - - this.state = { - selectedTemplate: null, - formValidationError: '', - actionInProgress: false, - }; - - this.currentUser = { - isAdmin: false, - id: null, - }; - - this.isEditAllowed = this.isEditAllowed.bind(this); - this.getTemplates = this.getTemplates.bind(this); - this.validateForm = this.validateForm.bind(this); - this.confirmDelete = this.confirmDelete.bind(this); - this.selectTemplate = this.selectTemplate.bind(this); - } - - selectTemplate(templateId) { - this.$state.go('kubernetes.deploy', { templateId }); - } - - isEditAllowed(template) { - // todo - check if current user is admin/endpointadmin/owner - return this.currentUser.isAdmin || this.currentUser.id === template.CreatedByUserId; - } - - getTemplates() { - return this.$async(async () => { - try { - const templates = await this.CustomTemplateService.customTemplates(3); - this.templates = templates.filter((t) => !t.EdgeTemplate); - } catch (err) { - this.Notifications.error('Failed loading templates', err, 'Unable to load custom templates'); - } - }); - } - - validateForm(accessControlData, isAdmin) { - this.state.formValidationError = ''; - const error = this.FormValidator.validateAccessControl(accessControlData, isAdmin); - - if (error) { - this.state.formValidationError = error; - return false; - } - return true; - } - - confirmDelete(templateId) { - return this.$async(async () => { - const confirmed = await confirmDelete('Are you sure that you want to delete this template?'); - if (!confirmed) { - return; - } - - try { - var template = _.find(this.templates, { Id: templateId }); - await this.CustomTemplateService.remove(templateId); - this.Notifications.success('Template successfully deleted', template && template.Title); - this.templates = this.templates.filter((template) => template.Id !== templateId); - } catch (err) { - this.Notifications.error('Failure', err, 'Failed to delete template'); - } - }); - } - - $onInit() { - this.getTemplates(); - - this.currentUser.isAdmin = this.Authentication.isAdmin(); - const user = this.Authentication.getUserDetails(); - this.currentUser.id = user.ID; - } -} diff --git a/app/kubernetes/custom-templates/kube-custom-templates-view/kube-custom-templates-view.html b/app/kubernetes/custom-templates/kube-custom-templates-view/kube-custom-templates-view.html deleted file mode 100644 index 2ac399d05..000000000 --- a/app/kubernetes/custom-templates/kube-custom-templates-view/kube-custom-templates-view.html +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/portainer/react/components/custom-templates/index.ts b/app/portainer/react/components/custom-templates/index.ts index 7474dc08e..46f817249 100644 --- a/app/portainer/react/components/custom-templates/index.ts +++ b/app/portainer/react/components/custom-templates/index.ts @@ -4,16 +4,6 @@ import { r2a } from '@/react-tools/react2angular'; import { CustomTemplatesVariablesDefinitionField } from '@/react/portainer/custom-templates/components/CustomTemplatesVariablesDefinitionField'; import { CustomTemplatesVariablesField } from '@/react/portainer/custom-templates/components/CustomTemplatesVariablesField'; import { withControlledInput } from '@/react-tools/withControlledInput'; -import { withCurrentUser } from '@/react-tools/withCurrentUser'; -import { withUIRouter } from '@/react-tools/withUIRouter'; -import { - CommonFields, - validation as commonFieldsValidation, -} from '@/react/portainer/custom-templates/components/CommonFields'; -import { PlatformField } from '@/react/portainer/custom-templates/components/PlatformSelector'; -import { TemplateTypeSelector } from '@/react/portainer/custom-templates/components/TemplateTypeSelector'; -import { withFormValidation } from '@/react-tools/withFormValidation'; -import { CustomTemplatesList } from '@/react/portainer/templates/custom-templates/ListView/CustomTemplatesList'; import { VariablesFieldAngular } from './variables-field'; @@ -37,33 +27,6 @@ export const ngModule = angular 'errors', 'isVariablesNamesFromParent', ]) - ) - .component( - 'customTemplatesList', - r2a(withUIRouter(withCurrentUser(CustomTemplatesList)), [ - 'onDelete', - 'onSelect', - 'templates', - 'selectedId', - 'templateLinkParams', - 'storageKey', - ]) - ) - .component( - 'customTemplatesPlatformSelector', - r2a(PlatformField, ['onChange', 'value']) - ) - .component( - 'customTemplatesTypeSelector', - r2a(TemplateTypeSelector, ['onChange', 'value']) ); -withFormValidation( - ngModule, - withControlledInput(CommonFields, { values: 'onChange' }), - 'customTemplatesCommonFields', - [], - commonFieldsValidation -); - export const customTemplatesModule = ngModule.name; diff --git a/app/portainer/react/views/templates.ts b/app/portainer/react/views/templates.ts index 99c7146e1..5b79de9de 100644 --- a/app/portainer/react/views/templates.ts +++ b/app/portainer/react/views/templates.ts @@ -6,6 +6,7 @@ import { withUIRouter } from '@/react-tools/withUIRouter'; import { CreateView } from '@/react/portainer/templates/custom-templates/CreateView'; import { EditView } from '@/react/portainer/templates/custom-templates/EditView'; import { AppTemplatesView } from '@/react/portainer/templates/app-templates/AppTemplatesView'; +import { ListView } from '@/react/portainer/templates/custom-templates/ListView/ListView'; export const templatesModule = angular .module('portainer.app.react.views.templates', []) @@ -13,6 +14,10 @@ export const templatesModule = angular 'appTemplatesView', r2a(withCurrentUser(withUIRouter(AppTemplatesView)), []) ) + .component( + 'customTemplatesView', + r2a(withCurrentUser(withUIRouter(ListView)), []) + ) .component( 'createCustomTemplatesView', r2a(withCurrentUser(withUIRouter(CreateView)), []) diff --git a/app/portainer/views/custom-templates/custom-templates-view/customTemplatesView.html b/app/portainer/views/custom-templates/custom-templates-view/customTemplatesView.html deleted file mode 100644 index 172cb4b9e..000000000 --- a/app/portainer/views/custom-templates/custom-templates-view/customTemplatesView.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - diff --git a/app/portainer/views/custom-templates/custom-templates-view/customTemplatesViewController.js b/app/portainer/views/custom-templates/custom-templates-view/customTemplatesViewController.js deleted file mode 100644 index aca241a81..000000000 --- a/app/portainer/views/custom-templates/custom-templates-view/customTemplatesViewController.js +++ /dev/null @@ -1,305 +0,0 @@ -import _ from 'lodash-es'; -import { AccessControlFormData } from 'Portainer/components/accessControlForm/porAccessControlFormModel'; -import { isTemplateVariablesEnabled, renderTemplate } from '@/react/portainer/custom-templates/components/utils'; -import { confirmDelete } from '@@/modals/confirm'; -import { getVariablesFieldDefaultValues } from '@/react/portainer/custom-templates/components/CustomTemplatesVariablesField'; -import { TEMPLATE_NAME_VALIDATION_REGEX } from '@/react/portainer/custom-templates/components/CommonFields'; - -class CustomTemplatesViewController { - /* @ngInject */ - constructor( - $anchorScroll, - $async, - $rootScope, - $state, - Authentication, - CustomTemplateService, - FormValidator, - NetworkService, - Notifications, - ResourceControlService, - StackService, - StateManager - ) { - this.$anchorScroll = $anchorScroll; - this.$async = $async; - this.$rootScope = $rootScope; - this.$state = $state; - this.Authentication = Authentication; - this.CustomTemplateService = CustomTemplateService; - this.FormValidator = FormValidator; - this.NetworkService = NetworkService; - this.Notifications = Notifications; - this.ResourceControlService = ResourceControlService; - this.StateManager = StateManager; - this.StackService = StackService; - - this.isTemplateVariablesEnabled = isTemplateVariablesEnabled; - - this.DOCKER_STANDALONE = 'DOCKER_STANDALONE'; - this.DOCKER_SWARM_MODE = 'DOCKER_SWARM_MODE'; - - this.state = { - selectedTemplate: null, - showAdvancedOptions: false, - formValidationError: '', - actionInProgress: false, - deployable: false, - templateNameRegex: TEMPLATE_NAME_VALIDATION_REGEX, - templateContent: '', - templateLoadFailed: false, - }; - - this.currentUser = { - isAdmin: false, - id: null, - }; - - this.formValues = { - network: '', - name: '', - fileContent: '', - AccessControlData: new AccessControlFormData(), - variables: [], - }; - - this.getTemplates = this.getTemplates.bind(this); - this.getTemplatesAsync = this.getTemplatesAsync.bind(this); - this.removeTemplates = this.removeTemplates.bind(this); - this.removeTemplatesAsync = this.removeTemplatesAsync.bind(this); - this.validateForm = this.validateForm.bind(this); - this.createStack = this.createStack.bind(this); - this.createStackAsync = this.createStackAsync.bind(this); - this.selectTemplate = this.selectTemplate.bind(this); - this.selectTemplateAsync = this.selectTemplateAsync.bind(this); - this.unselectTemplate = this.unselectTemplate.bind(this); - this.unselectTemplateAsync = this.unselectTemplateAsync.bind(this); - this.getNetworks = this.getNetworks.bind(this); - this.getNetworksAsync = this.getNetworksAsync.bind(this); - this.confirmDelete = this.confirmDelete.bind(this); - this.confirmDeleteAsync = this.confirmDeleteAsync.bind(this); - this.editorUpdate = this.editorUpdate.bind(this); - this.isEditAllowed = this.isEditAllowed.bind(this); - this.onChangeFormValues = this.onChangeFormValues.bind(this); - this.onChangeTemplateVariables = this.onChangeTemplateVariables.bind(this); - } - - isEditAllowed(template) { - return this.currentUser.isAdmin || this.currentUser.id === template.CreatedByUserId; - } - - getTemplates() { - return this.$async(this.getTemplatesAsync); - } - async getTemplatesAsync() { - try { - const templates = await this.CustomTemplateService.customTemplates([1, 2]); - this.templates = templates.filter((t) => !t.EdgeTemplate); - } catch (err) { - this.Notifications.error('Failed loading templates', err, 'Unable to load custom templates'); - } - } - - removeTemplates(templates) { - return this.$async(this.removeTemplatesAsync, templates); - } - async removeTemplatesAsync(templates) { - for (let template of templates) { - try { - await this.CustomTemplateService.remove(template.id); - this.Notifications.success('Success', 'Removed template successfully'); - _.remove(this.templates, template); - } catch (err) { - this.Notifications.error('Failed removing template', err, 'Unable to remove custom template'); - } - } - } - - onChangeTemplateVariables(variables) { - this.onChangeFormValues({ variables }); - - this.renderTemplate(); - } - - renderTemplate() { - if (!this.isTemplateVariablesEnabled) { - return; - } - - const fileContent = renderTemplate(this.state.templateContent, this.formValues.variables, this.state.selectedTemplate.Variables); - this.onChangeFormValues({ fileContent }); - } - - onChangeFormValues(values) { - this.formValues = { - ...this.formValues, - ...values, - }; - } - - validateForm(accessControlData, isAdmin) { - this.state.formValidationError = ''; - const error = this.FormValidator.validateAccessControl(accessControlData, isAdmin); - - if (error) { - this.state.formValidationError = error; - return false; - } - return true; - } - - createStack() { - return this.$async(this.createStackAsync); - } - async createStackAsync() { - const userId = this.currentUser.id; - const accessControlData = this.formValues.AccessControlData; - - if (!this.validateForm(accessControlData, this.currentUser.isAdmin)) { - return; - } - const stackName = this.formValues.name; - - const endpointId = this.endpoint.Id; - - this.state.actionInProgress = true; - - try { - const file = this.formValues.fileContent; - const createAction = this.state.selectedTemplate.Type === 1 ? this.StackService.createSwarmStackFromFileContent : this.StackService.createComposeStackFromFileContent; - const { ResourceControl: resourceControl } = await createAction(stackName, file, [], endpointId); - await this.ResourceControlService.applyResourceControl(userId, accessControlData, resourceControl); - this.Notifications.success('Success', 'Stack successfully deployed'); - this.$state.go('docker.stacks'); - } catch (err) { - this.Notifications.error('Deployment error', err, 'Failed to deploy stack'); - } finally { - this.state.actionInProgress = false; - } - } - - unselectTemplate() { - // wrapping unselect with async to make a digest cycle run between unselect to select - return this.$async(this.unselectTemplateAsync); - } - async unselectTemplateAsync() { - this.state.selectedTemplate = null; - - this.formValues = { - network: '', - name: '', - fileContent: '', - AccessControlData: new AccessControlFormData(), - variables: [], - }; - } - - selectTemplate(templateId) { - return this.$async(this.selectTemplateAsync, templateId); - } - async selectTemplateAsync(templateId) { - if (this.state.selectedTemplate) { - await this.unselectTemplate(this.state.selectedTemplate); - } - - const template = _.find(this.templates, { Id: templateId }); - - const isGit = template.GitConfig !== null; - this.state.isEditorReadOnly = isGit; - - try { - this.state.templateContent = this.formValues.fileContent = await this.CustomTemplateService.customTemplateFile(template.Id, template.GitConfig !== null); - } catch (err) { - this.state.templateLoadFailed = true; - this.Notifications.error('Failure', err, 'Unable to retrieve custom template data'); - } - - this.formValues.network = _.find(this.availableNetworks, function (o) { - return o.Name === 'bridge'; - }); - - this.formValues.name = template.Title ? template.Title : ''; - this.state.selectedTemplate = template; - this.$anchorScroll('view-top'); - const applicationState = this.StateManager.getState(); - this.state.deployable = this.isDeployable(applicationState.endpoint, template.Type); - - if (template.Variables && template.Variables.length > 0) { - const variables = getVariablesFieldDefaultValues(template.Variables); - this.onChangeTemplateVariables(variables); - } - - window.scrollTo({ top: 0, behavior: 'smooth' }); - } - - getNetworks(provider, apiVersion) { - return this.$async(this.getNetworksAsync, provider, apiVersion); - } - async getNetworksAsync(provider, apiVersion) { - try { - const networks = await this.NetworkService.networks( - provider === 'DOCKER_STANDALONE' || provider === 'DOCKER_SWARM_MODE', - false, - provider === 'DOCKER_SWARM_MODE' && apiVersion >= 1.25 - ); - this.availableNetworks = networks; - } catch (err) { - this.Notifications.error('Failure', err, 'Failed to load networks.'); - } - } - - confirmDelete(templateId) { - return this.$async(this.confirmDeleteAsync, templateId); - } - async confirmDeleteAsync(templateId) { - const confirmed = await confirmDelete('Are you sure that you want to delete this template?'); - if (!confirmed) { - return; - } - - try { - var template = _.find(this.templates, { Id: templateId }); - await this.CustomTemplateService.remove(templateId); - this.Notifications.success('Template successfully deleted', template && template.Title); - this.templates = this.templates.filter((template) => template.Id !== templateId); - } catch (err) { - this.Notifications.error('Failure', err, 'Failed to delete template'); - } - } - - editorUpdate(value) { - this.formValues.fileContent = value; - } - - isDeployable(endpoint, templateType) { - let deployable = false; - switch (templateType) { - case 1: - deployable = endpoint.mode.provider === this.DOCKER_SWARM_MODE; - break; - case 2: - deployable = endpoint.mode.provider === this.DOCKER_STANDALONE; - break; - } - - return deployable; - } - - $onInit() { - const applicationState = this.StateManager.getState(); - - const { - endpoint: { mode: endpointMode }, - apiVersion, - } = applicationState; - - this.getTemplates(); - this.getNetworks(endpointMode.provider, apiVersion); - - this.currentUser.isAdmin = this.Authentication.isAdmin(); - const user = this.Authentication.getUserDetails(); - this.currentUser.id = user.ID; - } -} - -export default CustomTemplatesViewController; diff --git a/app/portainer/views/custom-templates/custom-templates-view/index.js b/app/portainer/views/custom-templates/custom-templates-view/index.js deleted file mode 100644 index a3f3d18c4..000000000 --- a/app/portainer/views/custom-templates/custom-templates-view/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import CustomTemplatesViewController from './customTemplatesViewController.js'; - -angular.module('portainer.app').component('customTemplatesView', { - templateUrl: './customTemplatesView.html', - controller: CustomTemplatesViewController, - bindings: { - endpoint: '<', - }, -}); diff --git a/app/react/components/form-components/FormActions.tsx b/app/react/components/form-components/FormActions.tsx index 6b804d777..00df929ee 100644 --- a/app/react/components/form-components/FormActions.tsx +++ b/app/react/components/form-components/FormActions.tsx @@ -25,17 +25,18 @@ export function FormActions({
- - {submitLabel} - - - {children} +
+ + {submitLabel} + + {children} +
diff --git a/app/react/edge/templates/custom-templates/ListView/ListView.tsx b/app/react/edge/templates/custom-templates/ListView/ListView.tsx deleted file mode 100644 index ef93cf78c..000000000 --- a/app/react/edge/templates/custom-templates/ListView/ListView.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { notifySuccess } from '@/portainer/services/notifications'; -import { useCustomTemplates } from '@/react/portainer/templates/custom-templates/queries/useCustomTemplates'; -import { useDeleteTemplateMutation } from '@/react/portainer/templates/custom-templates/queries/useDeleteTemplateMutation'; -import { CustomTemplate } from '@/react/portainer/templates/custom-templates/types'; -import { CustomTemplatesList } from '@/react/portainer/templates/custom-templates/ListView/CustomTemplatesList'; - -import { PageHeader } from '@@/PageHeader'; -import { confirmDelete } from '@@/modals/confirm'; - -export function ListView() { - const templatesQuery = useCustomTemplates({ - params: { - edge: true, - }, - }); - const deleteMutation = useDeleteTemplateMutation(); - - return ( - <> - - - ({ - to: 'edge.stacks.new', - params: { templateId: template.Id, templateType: 'custom' }, - })} - storageKey="edge-custom-templates" - /> - - ); - - async function handleDelete(templateId: CustomTemplate['Id']) { - if ( - !(await confirmDelete('Are you sure you want to delete this template?')) - ) { - return; - } - - deleteMutation.mutate(templateId, { - onSuccess: () => { - notifySuccess('Success', 'Template deleted'); - }, - }); - } -} diff --git a/app/react/edge/templates/custom-templates/ListView/index.ts b/app/react/edge/templates/custom-templates/ListView/index.ts deleted file mode 100644 index dd06dfd19..000000000 --- a/app/react/edge/templates/custom-templates/ListView/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { ListView } from './ListView'; diff --git a/app/react/edge/templates/custom-templates/common/git.ts b/app/react/edge/templates/custom-templates/common/git.ts deleted file mode 100644 index 0e8c52232..000000000 --- a/app/react/edge/templates/custom-templates/common/git.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { transformGitAuthenticationViewModel } from '@/react/portainer/gitops/AuthFieldset/utils'; -import { GitFormModel } from '@/react/portainer/gitops/types'; - -export function toGitRequest( - gitConfig: GitFormModel, - credentialId: number | undefined -): GitFormModel { - return { - ...gitConfig, - ...getGitAuthValues(gitConfig, credentialId), - }; -} - -function getGitAuthValues( - gitConfig: GitFormModel | undefined, - credentialId: number | undefined -) { - if (!credentialId) { - return gitConfig; - } - - const authModel = transformGitAuthenticationViewModel({ - ...gitConfig, - RepositoryGitCredentialID: credentialId, - }); - - return authModel - ? { - RepositoryAuthentication: true, - RepositoryGitCredentialID: authModel.GitCredentialID, - RepositoryPassword: authModel.Password, - RepositoryUsername: authModel.Username, - } - : {}; -} diff --git a/app/react/portainer/templates/custom-templates/ListView/CustomTemplatesList.tsx b/app/react/portainer/templates/custom-templates/ListView/CustomTemplatesList.tsx index dc6a475c9..a0bb23720 100644 --- a/app/react/portainer/templates/custom-templates/ListView/CustomTemplatesList.tsx +++ b/app/react/portainer/templates/custom-templates/ListView/CustomTemplatesList.tsx @@ -15,20 +15,20 @@ import { CustomTemplatesListItem } from './CustomTemplatesListItem'; export function CustomTemplatesList({ templates, - onSelect, onDelete, selectedId, templateLinkParams, storageKey, }: { templates?: CustomTemplate[]; - onSelect?: (template: CustomTemplate['Id']) => void; - onDelete: (template: CustomTemplate['Id']) => void; + onDelete: (templateId: CustomTemplate['Id']) => void; selectedId?: CustomTemplate['Id']; - templateLinkParams?: (template: CustomTemplate) => { - to: string; - params: object; - }; + templateLinkParams?: (template: CustomTemplate) => + | { + to: string; + params: object; + } + | undefined; storageKey: string; }) { const [page, setPage] = useState(0); @@ -68,7 +68,6 @@ export function CustomTemplatesList({ ('template', (param) => + param ? parseInt(param, 10) : 0 + ); + + return ( + <> + + + {viewType === 'docker' && !!selectedTemplateId && ( + + )} + + + + ); + + async function handleDelete(templateId: CustomTemplate['Id']) { + if ( + !(await confirmDelete('Are you sure you want to delete this template?')) + ) { + return; + } + + deleteMutation.mutate(templateId, { + onSuccess: () => { + notifySuccess('Success', 'Template deleted'); + }, + }); + } +} diff --git a/app/react/docker/templates/StackFromCustomTemplateFormWidget/DeployForm.tsx b/app/react/portainer/templates/custom-templates/ListView/StackFromCustomTemplateFormWidget/DeployForm.tsx similarity index 96% rename from app/react/docker/templates/StackFromCustomTemplateFormWidget/DeployForm.tsx rename to app/react/portainer/templates/custom-templates/ListView/StackFromCustomTemplateFormWidget/DeployForm.tsx index 4218e65b0..51ec1748e 100644 --- a/app/react/docker/templates/StackFromCustomTemplateFormWidget/DeployForm.tsx +++ b/app/react/portainer/templates/custom-templates/ListView/StackFromCustomTemplateFormWidget/DeployForm.tsx @@ -23,26 +23,24 @@ import { import { StackType } from '@/react/common/stacks/types'; import { toGitFormModel } from '@/react/portainer/gitops/types'; import { AdvancedSettings } from '@/react/portainer/templates/app-templates/DeployFormWidget/AdvancedSettings'; +import { useSwarmId } from '@/react/docker/proxy/queries/useSwarm'; import { Button } from '@@/buttons'; import { FormActions } from '@@/form-components/FormActions'; import { FormSection } from '@@/form-components/FormSection'; import { WebEditorForm } from '@@/WebEditorForm'; - -import { useSwarmId } from '../../proxy/queries/useSwarm'; +import { Link } from '@@/Link'; import { FormValues } from './types'; import { useValidation } from './useValidation'; export function DeployForm({ template, - unselect, templateFile, isDeployable, }: { template: CustomTemplate; templateFile: string; - unselect: () => void; isDeployable: boolean; }) { const router = useRouter(); @@ -157,7 +155,12 @@ export function DeployForm({ >