Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout feat: implement adding ssh key Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout fix: showing default values Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout feat: implement selector placeholders and default values Merge branch 'feat/ui-layout' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout fix: getting user information after setting payment method Merge branch 'master' into feat/ui-layout feat: implement setting payment plan in payment page feat: populate options for advanced settings modal fix: remove showing advanced settings modal when loading the page feat: implement Advanced Settings Modal layout feat: implement modal and selector components feat: implement launch bubble screen Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout feat: implement add stripe card feat: implement login process Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout feat: implement payment page feat: implement mail verification screen Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout feat: prevent registration when the configs.allowRegistration is set to false fix: weird routing Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout feat: implement actual pages Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout feat: api integration for register page fix: messages feat: api integration for forget-password page fix: login title and password placeholder feat: disable button until get response Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout feat: integrate api for new login page feat: implement responsive header feat: implement checkbox Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout fix: checkbox event issue feat: implement register page feat: implement registration page Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout feat: implement UI for forgot-password Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout feat: implement new login page feat: implement input shared component Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout feat: implement auth header Co-authored-by: Tyler <everdev0923@gmail.com> Co-authored-by: jonathan <jonathan@noreply.git.bubblev.org> Reviewed-on: https://git.bubblev.org/bubblev/bubble-web/pulls/35pull/38/head
@@ -7810,6 +7810,11 @@ | |||||
"integrity": "sha1-HuO8mhbsv1EYvjNLsV+cRvgvWCU=", | "integrity": "sha1-HuO8mhbsv1EYvjNLsV+cRvgvWCU=", | ||||
"dev": true | "dev": true | ||||
}, | }, | ||||
"vuejs-datepicker": { | |||||
"version": "1.6.2", | |||||
"resolved": "https://registry.npmjs.org/vuejs-datepicker/-/vuejs-datepicker-1.6.2.tgz", | |||||
"integrity": "sha512-PkC4vxzFBo7i6FSCUAJfnaWOx6VkKbOqxijSGHHlWxh8FIUKEZVtFychkonVWtK3iwWfhmYtqHcwsmgxefLpLQ==" | |||||
}, | |||||
"vuelidate": { | "vuelidate": { | ||||
"version": "0.7.5", | "version": "0.7.5", | ||||
"resolved": "https://registry.npmjs.org/vuelidate/-/vuelidate-0.7.5.tgz", | "resolved": "https://registry.npmjs.org/vuelidate/-/vuelidate-0.7.5.tgz", | ||||
@@ -26,6 +26,7 @@ | |||||
"vue-select": "^3.10.7", | "vue-select": "^3.10.7", | ||||
"vue-snotify": "^3.2.1", | "vue-snotify": "^3.2.1", | ||||
"vue-spinner": "^1.0.4", | "vue-spinner": "^1.0.4", | ||||
"vuejs-datepicker": "^1.6.2", | |||||
"vuelidate": "^0.7.5", | "vuelidate": "^0.7.5", | ||||
"vuex": "^3.1.1" | "vuex": "^3.1.1" | ||||
}, | }, | ||||
@@ -0,0 +1,200 @@ | |||||
<!-- Copyright (c) 2020 Bubble, Inc. All rights reserved. For personal (non-commercial) use, see license: https://getbubblenow.com/bubble-license/ --> | |||||
<template> | |||||
<modal | |||||
name="add-ssh-key" | |||||
:adaptive="true" | |||||
width="90%" | |||||
:maxWidth="600" | |||||
height="auto" | |||||
> | |||||
<form action="" class="form" @submit.prevent="addSshKey"> | |||||
<div class="form-group"> | |||||
<textarea | |||||
:placeholder="messages.field_label_ssh_key_public_key" | |||||
name="publicSsh" | |||||
class="form-control public-ssh" | |||||
rows="8" | |||||
v-model="sshPublicKey" | |||||
></textarea> | |||||
<div | |||||
class="description text-left" | |||||
v-html="messages.field_description_ssh_key_public_key" | |||||
></div> | |||||
<div | |||||
v-if="submitted && errors.has('sshPublicKey')" | |||||
class="invalid-feedback d-block" | |||||
> | |||||
{{ errors.first('sshPublicKey') }} | |||||
</div> | |||||
</div> | |||||
<div class="form-group"> | |||||
<Input | |||||
class="form-control" | |||||
:placeholder="messages.field_label_ssh_key_name" | |||||
v-model="name" | |||||
/> | |||||
<div | |||||
v-if="submitted && errors.has('name')" | |||||
class="invalid-feedback d-block" | |||||
> | |||||
{{ errors.first('name') }} | |||||
</div> | |||||
</div> | |||||
<div class="form-group"> | |||||
<datetime | |||||
v-model="expiration" | |||||
input-id="expiration" | |||||
input-class="form-control" | |||||
class="position-relative" | |||||
:min-datetime="minExpiration" | |||||
:phrases="dateControlPhrases" | |||||
:zone="timezone" | |||||
:week-start="parseInt(messages.datecontrol_weekstart)" | |||||
:placeholder="messages.field_label_ssh_key_expiration" | |||||
> | |||||
<template slot="after"> | |||||
<a v-if="expiration" href="#" class="clear-date" @click="clearDate"> | |||||
× | |||||
</a> | |||||
</template> | |||||
</datetime> | |||||
<div | |||||
class="description text-left" | |||||
v-html="messages.field_description_ssh_key_expiration" | |||||
></div> | |||||
<div | |||||
v-if="submitted && errors.has('expiration')" | |||||
class="invalid-feedback d-block" | |||||
> | |||||
{{ errors.first('expiration') }} | |||||
</div> | |||||
</div> | |||||
<div | |||||
class="form-group mt-4 d-flex justify-content-center align-items-center" | |||||
> | |||||
<div class="flex-grow-1 pr-2"> | |||||
<Button block color="outline" @click="hide"> | |||||
{{ messages.button_label_cancel }} | |||||
</Button> | |||||
</div> | |||||
<div class="flex-grow-1 pl-2"> | |||||
<Button block color="default" type="submit"> | |||||
{{ messages.button_label_add_ssh_key }} | |||||
</Button> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
</modal> | |||||
</template> | |||||
<style lang="scss" scoped> | |||||
.public-ssh { | |||||
font-size: 14px; | |||||
} | |||||
.clear-date { | |||||
position: absolute; | |||||
right: 10px; | |||||
top: 50%; | |||||
transform: translateY(-50%); | |||||
} | |||||
</style> | |||||
<script> | |||||
import { mapActions, mapState } from 'vuex'; | |||||
import { util } from '~/_helpers'; | |||||
import { Button, Input } from '../shared'; | |||||
export default { | |||||
components: { | |||||
Button, | |||||
Input, | |||||
}, | |||||
data: () => ({ | |||||
name: '', | |||||
sshPublicKey: '', | |||||
minExpiration: new Date().toISOString(), | |||||
expiration: null, | |||||
timezone: null, | |||||
submitted: false, | |||||
}), | |||||
methods: { | |||||
...mapActions('system', ['detectTimezone']), | |||||
...mapActions('users', ['addSshKeyByUserId']), | |||||
show() { | |||||
this.$modal.show('add-ssh-key'); | |||||
}, | |||||
hide() { | |||||
this.$modal.hide('add-ssh-key'); | |||||
}, | |||||
addSshKey(e) { | |||||
const currentUser = util.currentUser(); | |||||
this.errors.clear(); | |||||
this.submitted = true; | |||||
this.addSshKeyByUserId({ | |||||
userId: currentUser.uuid, | |||||
sshKey: { | |||||
name: this.name, | |||||
sshPublicKey: this.sshPublicKey, | |||||
expirationISO8601: this.expiration, | |||||
}, | |||||
messages: this.messages, | |||||
errors: this.errors, | |||||
}).then(() => { | |||||
this.hide(); | |||||
this.$emit('updateSsh'); | |||||
}); | |||||
}, | |||||
clearDate(e) { | |||||
e.preventDefault(); | |||||
this.expiration = null; | |||||
}, | |||||
}, | |||||
computed: { | |||||
...mapState('system', ['messages', 'detectedTimezone']), | |||||
dateControlPhrases() { | |||||
return { | |||||
ok: this.messages.message_datecontrol_ok, | |||||
cancel: this.messages.message_datecontrol_cancel, | |||||
}; | |||||
}, | |||||
}, | |||||
watch: { | |||||
detectedTimezone(tz) { | |||||
if (tz) this.timezone = tz.timeZoneId; | |||||
}, | |||||
sshPublicKey(ssh) { | |||||
const sshSections = ssh.split(' '); | |||||
if (sshSections[2]) { | |||||
this.name = sshSections[2]; | |||||
} | |||||
}, | |||||
}, | |||||
created() { | |||||
if ( | |||||
this.detectedTimezone === null || | |||||
!this.detectedTimezone.hasOwnProperty('timeZoneId') | |||||
) { | |||||
this.detectTimezone(); | |||||
} else { | |||||
this.timezone = this.detectedTimezone.timeZoneId; | |||||
} | |||||
}, | |||||
}; | |||||
</script> |
@@ -95,14 +95,29 @@ | |||||
</v-select> | </v-select> | ||||
</div> | </div> | ||||
<div class="form-group"> | <div class="form-group"> | ||||
<v-select :placeholder="messages.field_label_network_ssh_key"> | |||||
<v-select | |||||
:placeholder="messages.field_label_network_ssh_key" | |||||
:options="sshKeys" | |||||
> | |||||
<template v-slot:selected-option="option"> | <template v-slot:selected-option="option"> | ||||
<span>SSH Key: {{ option.name }}</span> | <span>SSH Key: {{ option.name }}</span> | ||||
</template> | </template> | ||||
<template v-slot:option="option"> | |||||
{{ option.name }} | |||||
( | |||||
<span v-if="option.expiration">{{ | |||||
messages.date_format_ssh_key_expiration.parseDateMessage( | |||||
option.expiration, | |||||
messages | |||||
) | |||||
}}</span> | |||||
<span v-else>{{ messages.message_ssh_key_no_expiration }}</span> | |||||
) | |||||
</template> | |||||
</v-select> | </v-select> | ||||
</div> | </div> | ||||
<div class="form-group"> | <div class="form-group"> | ||||
<Button color="outline" height="34"> | |||||
<Button color="outline" height="34" @click="addSSHKey"> | |||||
{{ messages.form_title_add_ssh_key }} | {{ messages.form_title_add_ssh_key }} | ||||
</Button> | </Button> | ||||
<p class="description text-left ml-0 mt-2"> | <p class="description text-left ml-0 mt-2"> | ||||
@@ -118,7 +133,7 @@ | |||||
class="form-group mt-4 d-flex justify-content-center align-items-center" | class="form-group mt-4 d-flex justify-content-center align-items-center" | ||||
> | > | ||||
<div class="flex-grow-1 pr-2"> | <div class="flex-grow-1 pr-2"> | ||||
<Button block color="outline"> | |||||
<Button block color="outline" @click="hide"> | |||||
{{ messages.button_label_cancel }} | {{ messages.button_label_cancel }} | ||||
</Button> | </Button> | ||||
</div> | </div> | ||||
@@ -129,6 +144,7 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</form> | </form> | ||||
<AddSSHKeyModal ref="sshKeyModal" @updateSsh="onUpdateSSH" /> | |||||
</modal> | </modal> | ||||
</template> | </template> | ||||
@@ -165,11 +181,14 @@ import { util } from '~/_helpers'; | |||||
import { Button, Input, Checkbox } from '../shared'; | import { Button, Input, Checkbox } from '../shared'; | ||||
import AddSSHKeyModal from './AddSshKey'; | |||||
export default { | export default { | ||||
components: { | components: { | ||||
Button, | Button, | ||||
Input, | Input, | ||||
Checkbox, | Checkbox, | ||||
AddSSHKeyModal, | |||||
}, | }, | ||||
data: () => ({ | data: () => ({ | ||||
@@ -199,6 +218,7 @@ export default { | |||||
...mapState('domains', ['domains']), | ...mapState('domains', ['domains']), | ||||
...mapState('networks', ['nearestRegions']), | ...mapState('networks', ['nearestRegions']), | ||||
...mapState('footprints', ['footprints']), | ...mapState('footprints', ['footprints']), | ||||
...mapState('users', ['sshKeys']), | |||||
timezoneObjects: function() { | timezoneObjects: function() { | ||||
const tz_objects = []; | const tz_objects = []; | ||||
@@ -237,6 +257,7 @@ export default { | |||||
...mapActions('domains', ['getAllDomains']), | ...mapActions('domains', ['getAllDomains']), | ||||
...mapActions('networks', ['getNearestRegions']), | ...mapActions('networks', ['getNearestRegions']), | ||||
...mapActions('footprints', ['getAllFootprints']), | ...mapActions('footprints', ['getAllFootprints']), | ||||
...mapActions('users', ['listSshKeysByUserId']), | |||||
show() { | show() { | ||||
this.$modal.show('advanced-settings'); | this.$modal.show('advanced-settings'); | ||||
@@ -245,6 +266,10 @@ export default { | |||||
this.$modal.hide('advanced-settings'); | this.$modal.hide('advanced-settings'); | ||||
}, | }, | ||||
addSSHKey() { | |||||
this.$refs.sshKeyModal.show(); | |||||
}, | |||||
initDefaults() { | initDefaults() { | ||||
const currentUser = util.currentUser(); | const currentUser = util.currentUser(); | ||||
@@ -263,6 +288,7 @@ export default { | |||||
messages: this.messages, | messages: this.messages, | ||||
errors: this.errors, | errors: this.errors, | ||||
}); | }); | ||||
this.onUpdateSSH(); | |||||
}, | }, | ||||
findRegion(uuid) { | findRegion(uuid) { | ||||
@@ -300,11 +326,19 @@ export default { | |||||
this.messages['tz_description_' + tz] | this.messages['tz_description_' + tz] | ||||
); | ); | ||||
}, | }, | ||||
onUpdateSSH() { | |||||
const currentUser = util.currentUser(); | |||||
this.listSshKeysByUserId({ | |||||
userId: currentUser.uuid, | |||||
messages: this.messages, | |||||
errors: this.errors, | |||||
}); | |||||
}, | |||||
}, | }, | ||||
mounted() { | mounted() { | ||||
this.initDefaults(); | this.initDefaults(); | ||||
this.show(); | |||||
}, | }, | ||||
watch: { | watch: { | ||||
@@ -352,9 +386,7 @@ export default { | |||||
} | } | ||||
} | } | ||||
}, | }, | ||||
}, | |||||
watch: { | |||||
domains(doms) { | domains(doms) { | ||||
if (doms && doms[0]) { | if (doms && doms[0]) { | ||||
if (this.accountPlan.domain == null || this.accountPlan.domain === '') | if (this.accountPlan.domain == null || this.accountPlan.domain === '') | ||||
@@ -12,7 +12,9 @@ | |||||
}" | }" | ||||
:disabled="disabled" | :disabled="disabled" | ||||
:style="cssVars" | :style="cssVars" | ||||
@click="onClick" | |||||
class="app-btn" | class="app-btn" | ||||
type="button" | |||||
> | > | ||||
<span class="btn--text"> | <span class="btn--text"> | ||||
<slot></slot> | <slot></slot> | ||||
@@ -148,5 +150,11 @@ export default { | |||||
}; | }; | ||||
}, | }, | ||||
}, | }, | ||||
methods: { | |||||
onClick(e) { | |||||
this.$emit('click', e); | |||||
}, | |||||
}, | |||||
}; | }; | ||||
</script> | </script> |
@@ -18,6 +18,11 @@ export default { | |||||
content: this.value, | content: this.value, | ||||
}; | }; | ||||
}, | }, | ||||
watch: { | |||||
value(v) { | |||||
this.content = v; | |||||
} | |||||
}, | |||||
methods: { | methods: { | ||||
handleInput(e) { | handleInput(e) { | ||||
this.$emit('input', this.content); | this.$emit('input', this.content); | ||||
@@ -31,6 +31,7 @@ | |||||
<Button | <Button | ||||
color="default" | color="default" | ||||
class="bubble-form-submit" | class="bubble-form-submit" | ||||
block | |||||
@click="handleSubmit" | @click="handleSubmit" | ||||
:disabled="status.sendingResetPasswordMessage" | :disabled="status.sendingResetPasswordMessage" | ||||
> | > | ||||
@@ -168,6 +168,10 @@ | |||||
font-size: 36px; | font-size: 36px; | ||||
margin-top: 25px; | margin-top: 25px; | ||||
} | } | ||||
.description { | |||||
max-width: 290px; | |||||
} | |||||
</style> | </style> | ||||
<script> | <script> | ||||
@@ -40,7 +40,6 @@ $form-border-radius: 2px; | |||||
.description { | .description { | ||||
font-size: 14px; | font-size: 14px; | ||||
max-width: 290px; | |||||
margin: 0 auto; | margin: 0 auto; | ||||
color: #666666; | color: #666666; | ||||
text-align: center; | text-align: center; | ||||
@@ -141,7 +141,7 @@ const actions = { | |||||
addSshKeyByUserId({ commit }, {userId, sshKey, messages, errors}) { | addSshKeyByUserId({ commit }, {userId, sshKey, messages, errors}) { | ||||
commit('addSshKeyByUserIdRequest'); | commit('addSshKeyByUserIdRequest'); | ||||
userService.addSshKeyByUserId(userId, sshKey, messages, errors) | |||||
return userService.addSshKeyByUserId(userId, sshKey, messages, errors) | |||||
.then( | .then( | ||||
key => commit('addSshKeyByUserIdSuccess', key), | key => commit('addSshKeyByUserIdSuccess', key), | ||||
error => commit('addSshKeyByUserIdFailure', error) | error => commit('addSshKeyByUserIdFailure', error) | ||||