diff --git a/packages/oc-pages/dashboard/components/cells/deployment-controls.vue b/packages/oc-pages/dashboard/components/cells/deployment-controls.vue index 8605e233..00c97c8a 100644 --- a/packages/oc-pages/dashboard/components/cells/deployment-controls.vue +++ b/packages/oc-pages/dashboard/components/cells/deployment-controls.vue @@ -105,7 +105,7 @@ export default { result.push('view-artifacts') } - if(window.gon.projectId && this.userCanEdit) { + if((window.gon.unfurl_gui || window.gon.projectId) && this.userCanEdit) { //temporary limitation (restrict to dashboard app) // allowing local deploy regardless of teardown status @@ -113,7 +113,7 @@ export default { } if(this.userCanEdit) { - result.push('rename-deployment') + if(this.deploymentItem?.isRenamable) result.push('rename-deployment') } if(!window.gon.unfurl_gui || window.gon.gitlab_url) { diff --git a/packages/oc-pages/dashboard/store/modules/deployment-info/deployment-item.js b/packages/oc-pages/dashboard/store/modules/deployment-info/deployment-item.js index 4616b068..e8366cbe 100644 --- a/packages/oc-pages/dashboard/store/modules/deployment-info/deployment-item.js +++ b/packages/oc-pages/dashboard/store/modules/deployment-info/deployment-item.js @@ -182,4 +182,11 @@ export default class DeploymentItem { if(!this.isAutostopCancelable) throw new Error(`Job ${this.autostopJob?.id || -1} is not cancelable`) await axios.post(this.autostopCancelLink) } + + get isRenamable() { + return ( + this.deployPath != this.application.blueprintPath && + this.deployment.source != '__generated' + ) + } } diff --git a/packages/oc-pages/project_overview/pages/templates/index.vue b/packages/oc-pages/project_overview/pages/templates/index.vue index 7f49f728..17656d9f 100644 --- a/packages/oc-pages/project_overview/pages/templates/index.vue +++ b/packages/oc-pages/project_overview/pages/templates/index.vue @@ -14,6 +14,7 @@ import { bus } from 'oc_vue_shared/bus'; import { slugify } from 'oc_vue_shared/util' import { deleteDeploymentTemplate } from '../../store/modules/deployment_template_updates' import {fetchUserHasWritePermissions, setMergeRequestReadyStatus, createMergeRequest, listMergeRequests} from 'oc_vue_shared/client_utils/projects' +import {normpath} from 'oc_vue_shared/lib/normalize' import * as routes from '../../router/constants' @@ -84,6 +85,7 @@ export default { 'getPrimaryCard', 'getCardsStacked', 'getDeploymentTemplate', + 'getDeployment', 'getDependencies', 'hasPreparedMutations', 'safeToNavigateAway', @@ -100,6 +102,7 @@ export default { 'getValidConnections', 'lookupConfigurableTypes', 'lookupEnvironment', + 'lookupDeployPath', 'getParentDependency', 'getPrimary', 'environmentsAreReady', @@ -118,12 +121,21 @@ export default { ]), deploymentDir() { - const environment = this.$route.params.environment - // this.getDeploymentTemplate.name not loaded yet + if(!this.getDeploymentTemplate) return null + const environment = this.$route.params.environment - // params.slug is the blueprint unfortunately - const deploymentSlug = this.$route.params.slug //slugify(this.$route.query.fn) - return `environments/${environment}/${this.project.globalVars.projectPath}/${deploymentSlug}` + if(this.getDeployment) { + const deployPath = this.lookupDeployPath(this.getDeployment.name, environment) + if(deployPath) return deployPath.name + } + + const deploymentSlug = this.$route.params.slug + let projectPath = this.project.globalVars.projectPath + + if(window.gon.unfurl_gui && normpath(projectPath) == normpath(window.gon.working_dir_project)) { + projectPath = 'local' + } + return normpath(`environments/${environment}/${projectPath}/${deploymentSlug}`) }, saveStatus() { switch(this.$route.name) { @@ -247,16 +259,28 @@ export default { }, deploymentParams() { - let projectUrl = `${window.gon.gitlab_url}/${this.project.globalVars.projectPath}.git` + const projectPath = this.project.globalVars.projectPath + + let projectUrl + if(projectPath.startsWith('local:')) { + // projectUrl = projectPath.replace('local:', 'file://') + projectUrl = null + } else { + projectUrl = `${window.gon.gitlab_url || 'https://unfurl.cloud'}/${this.project.globalVars.projectPath}.git` + } + + const deploymentBlueprint = this.$route.query.ts || this.getDeploymentTemplate?.source + if(this.$route.query.bprev) { projectUrl += `#${this.$route.query.bprev}` } + return { environmentName: this.$route.params.environment, projectUrl, deployPath: this.deploymentDir, deploymentName: this.$route.params.slug, - deploymentBlueprint: this.$route.query.ts || this.getDeploymentTemplate?.source, + deploymentBlueprint } } }, @@ -317,7 +341,22 @@ export default { const ref = this.$refs['oc-template-resource'] ref.hide() } - }, 100) + }, 100), + + deploymentDir: { + immediate: true, // force calculation + handler(val) { + if(val && this.$route.name != routes.OC_PROJECT_VIEW_CREATE_TEMPLATE) { + this.setUpdateObjectPath(val); + } + } + }, + deploymentParams: { + immediate: true, + handler(val) { + this.setDeploymentParams(val) + } + } }, serverPrefetch() { @@ -400,6 +439,7 @@ export default { 'pushPreparedMutation', 'setCommitMessage', 'setUpdateType', + 'setDeploymentParams', 'createError', 'setCommitBranch', 'setBlueprintBranch' @@ -509,7 +549,6 @@ export default { const renameDeploymentTemplate = this.$route.query.fn; const environmentName = this.$route.params.environment if(this.$route.name != routes.OC_PROJECT_VIEW_CREATE_TEMPLATE) { - this.setUpdateObjectPath(this.deploymentDir); this.setUpdateObjectProjectPath(this.getHomeProjectPath); this.setEnvironmentScope(environmentName) } diff --git a/packages/oc-pages/project_overview/router/index.js b/packages/oc-pages/project_overview/router/index.js index 947a6bbe..ef328eef 100644 --- a/packages/oc-pages/project_overview/router/index.js +++ b/packages/oc-pages/project_overview/router/index.js @@ -61,7 +61,6 @@ export default function createRouter(base) { for(const fn of ['push', 'replace']) { router[fn] = _.debounce(function(...args) { - console.log(fn, ...args) return router.og[fn](...args).catch(e => { if (!isNavigationFailure(e, NavigationFailureType.redirected)) { Promise.reject(e) @@ -72,19 +71,22 @@ export default function createRouter(base) { router.resolve = function(to, ...args) { const from = router.currentRoute + let modified = false + const modifiedTo = {query: {}, ...to} for(const param of PERSISTED_QUERY_PARAMS) { - if(from.query.hasOwnProperty(param) && !to.query.hasOwnProperty(param)) { - to.query[param] = from.query[param] + if(from.query?.hasOwnProperty(param) && !to.query?.hasOwnProperty(param)) { + modifiedTo.query[param] = from.query[param] } + modified = true } - return router.og.resolve(to, ...args) + return router.og.resolve(modified? modifiedTo: to, ...args) } router.beforeEach((to, from, next) => { let modified = false const modifiedTo = {...to} for(const param of PERSISTED_QUERY_PARAMS) { - if(from.query.hasOwnProperty(param) && !to.query.hasOwnProperty(param)) { + if(from.query?.hasOwnProperty(param) && !to.query?.hasOwnProperty(param)) { modifiedTo.query[param] = from.query[param] modified = true } diff --git a/packages/oc-pages/project_overview/store/modules/deployment_template_updates.js b/packages/oc-pages/project_overview/store/modules/deployment_template_updates.js index d9a98664..d0a6d2ea 100644 --- a/packages/oc-pages/project_overview/store/modules/deployment_template_updates.js +++ b/packages/oc-pages/project_overview/store/modules/deployment_template_updates.js @@ -180,6 +180,9 @@ Serializers = { dt.resourceTemplates = _.union(Object.keys(localResourceTemplates || {}), Object.keys(state.ResourceTemplate || {})) } + if(dt.source == '__generated') { + dt.directives = ['predefined'] // mark as not needing to be committed + } }, // TODO unit test ResourceTemplate(rt, state) { @@ -405,7 +408,7 @@ export function updatePropertyInResourceTemplate({templateName, propertyName, pr let _propertyValue = propertyValue // cloned at caller if(deploymentTemplate.ResourceTemplate && deploymentTemplate.ResourceTemplate[templateName]) { - if(deploymentTemplate.source) { + if(deploymentTemplate._sourceTemplate) { result.push( deleteResourceTemplate({templateName, deploymentTemplateName: deploymentTemplate.name}) ) @@ -549,7 +552,7 @@ export function appendResourceTemplateInDependent({templateName, dependentName, const deploymentTemplate = accumulator['DeploymentTemplate'][deploymentTemplateName] patch = deploymentTemplate['ResourceTemplate'][dependentName] - if(patch && deploymentTemplate.source) { + if(patch && deploymentTemplate._sourceTemplate) { result.push( deleteResourceTemplate({templateName: dependentName, deploymentTemplateName: deploymentTemplate.name}) ) @@ -789,6 +792,8 @@ const state = () => ({ effectiveFirstMutation: 0, accumulator: {}, patches: {}, + deploymentParams: {}, + path: null, committedNames: [], commitMessage: null, commitBranch: null, @@ -830,6 +835,9 @@ const mutations = { } state.projectPath = projectPath }, + setDeploymentParams(state, deploymentParams) { + state.deploymentParams = deploymentParams + }, setCommitMessage(state, commitMessage) { state.commitMessage = commitMessage }, @@ -1012,33 +1020,29 @@ const actions = { let sync, method, path = state.path if(state.updateType == UPDATE_TYPE.deployment) { - variables.deployment_path = path + variables.deployment_path = path || state.deploymentParams?.deployPath if(!rootGetters.hasDeployPathKey(path)) { // infer information from the deployment object path instead of our getters // I'm not sure there's much to be gained here in terms of decoupling, but this should work better with clone - const pathSplits = path.split('/') - pathSplits.shift() - const environmentName = pathSplits.shift() - const deploymentName = pathSplits.pop() - const blueprintProjectPath = pathSplits.join('/') + variables.environment = state.deploymentParams?.environmentName + variables.deployment_blueprint = state.deploymentParams?.deploymentName + variables.blueprint_url = state.deploymentParams?.projectUrl? + new URL(state.deploymentParams.projectUrl) : null - variables.environment = environmentName - variables.deployment_blueprint = deploymentName - - variables.blueprint_url = new URL((window.gon.gitlab_url || 'https://unfurl.cloud') + '/' + blueprintProjectPath + '.git') - variables.blueprint_url.username = rootGetters.getUsername - const password = await fetchUserAccessToken() - if(password) { - variables.blueprint_url.password + if(variables.blueprint_url) { + const password = await fetchUserAccessToken() + if(password) { + variables.blueprint_url.password = password + } } - if(state.blueprintBranch) { - variables.blueprint_url.hash = state.blueprintBranch + if(variables.blueprint_url) { + variables.blueprint_url = variables.blueprint_url.toString() + } else { + delete variables.blueprint_url } - variables.blueprint_url = variables.blueprint_url.toString() - method = 'create_ensemble' } else { method = 'update_ensemble' diff --git a/packages/oc-pages/project_overview/store/modules/project_application_blueprint.js b/packages/oc-pages/project_overview/store/modules/project_application_blueprint.js index 72286c3c..9802fbc0 100644 --- a/packages/oc-pages/project_overview/store/modules/project_application_blueprint.js +++ b/packages/oc-pages/project_overview/store/modules/project_application_blueprint.js @@ -219,12 +219,12 @@ const actions = { if(projectPath && !deploymentTemplate.projectPath) { deploymentTemplate.projectPath = projectPath } - if(deploymentTemplate.source) { + if(deploymentTemplate._sourceTemplate) { if(!deploymentTemplate.ResourceTemplate) { deploymentTemplate.ResourceTemplate = {} } - Object.entries(getters.resolveDeploymentTemplate(deploymentTemplate.source)?.ResourceTemplate || {}).forEach(([name, rt]) => { + Object.entries(getters.resolveDeploymentTemplate(deploymentTemplate._sourceTemplate)?.ResourceTemplate || {}).forEach(([name, rt]) => { if( (root.ResourceTemplate[name] && root.ResourceTemplate[name].directives.includes('default')) && (!deploymentTemplate.ResourceTemplate[name]) diff --git a/packages/oc-pages/project_overview/store/modules/template_resources.js b/packages/oc-pages/project_overview/store/modules/template_resources.js index 94629e3e..ab2d9eb9 100644 --- a/packages/oc-pages/project_overview/store/modules/template_resources.js +++ b/packages/oc-pages/project_overview/store/modules/template_resources.js @@ -278,10 +278,10 @@ const actions = { deploymentTemplate = {...deploymentTemplate, projectPath, branch: blueprintBranch} blueprint = {...blueprint, projectPath, branch: blueprintBranch} - const sourceDeploymentTemplate = deploymentTemplate.source || deploymentTemplate.name + const sourceDeploymentTemplate = deploymentTemplate._sourceTemplate || deploymentTemplate.name - if(!deploymentTemplate.source && renameDeploymentTemplate) { - deploymentTemplate.source = sourceDeploymentTemplate + if(!deploymentTemplate._sourceTemplate && renameDeploymentTemplate) { + deploymentTemplate._sourceTemplate = deploymentTemplate.source = sourceDeploymentTemplate deploymentTemplate.title = renameDeploymentTemplate; deploymentTemplate.name = slugify(renameDeploymentTemplate); deploymentTemplate.slug = deploymentTemplate.name diff --git a/packages/oc-pages/vue_shared/lib/normalize.js b/packages/oc-pages/vue_shared/lib/normalize.js index d04c87e7..5bd7a0b0 100644 --- a/packages/oc-pages/vue_shared/lib/normalize.js +++ b/packages/oc-pages/vue_shared/lib/normalize.js @@ -65,6 +65,7 @@ const transforms = { }) } const appBlueprint = Object.values(root.ApplicationBlueprint)[0] + dt._sourceTemplate = dt.source == '__generated'? undefined : dt.source if(appBlueprint) { for(const pathProp of PATH_PROPS) { diff --git a/ufsv-patch/fixture.js b/ufsv-patch/fixture.js index 77389e6e..9d71c94b 100644 --- a/ufsv-patch/fixture.js +++ b/ufsv-patch/fixture.js @@ -91,6 +91,13 @@ class Fixture { store.commit('setUpdateObjectPath', this.deploymentDir) store.commit('setUpdateObjectProjectPath', this.dashboardProjectPath) store.commit('setEnvironmentScope', this.environment) + store.commit('setDeploymentParams', { + environmentName: this.environment, + projectUrl: `${OC_URL}/${this.projectPath}`, + deployPath: this.deploymentDir, + deploymentName: this.templateSlug, + deploymentBlueprint: this.templateSlug + }) store.commit('setCurrentNamespace', this.user.username)