Skip to content

Commit

Permalink
Merge pull request #724 from Support-pl/dev
Browse files Browse the repository at this point in the history
VDC networking
  • Loading branch information
639852 committed Jul 25, 2024
2 parents 396db13 + 81f7dae commit c82c322
Show file tree
Hide file tree
Showing 14 changed files with 1,030 additions and 133 deletions.
95 changes: 95 additions & 0 deletions src/components/cloud/vdc/ipsPrice.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<template>
<a-flex gap="middle">
<h3 class="cloud__title">
<span style="white-space: nowrap">
IPv4 {{ $t('quantity') }}:
</span>

<span style="white-space: nowrap">
{{ ipsQuantity }}
</span>
</h3>

<a-flex align="center" gap="small">
<dollar-icon style="font-size: 25px" />
<h3 class="cloud__title">
<span style="white-space: nowrap">
{{ capitalize($t('usage')) }}:
</span>

<span style="white-space: nowrap">
{{ price }} {{ currency.code }}/{{ $tc('month', 0) }}
</span>
</h3>
</a-flex>
</a-flex>
</template>

<script setup>
import { computed, defineAsyncComponent } from 'vue'
import { useInstancesStore } from '@/stores/instances.js'
import { useCurrency } from '@/hooks/utils'
const dollarIcon = defineAsyncComponent(
() => import('@ant-design/icons-vue/DollarCircleOutlined')
)
const props = defineProps({
instances: { type: Array, required: true },
selected: { type: String, required: true }
})
const instancesStore = useInstancesStore()
const { currency } = useCurrency()
const price = computed(() => {
const result = []
props.instances.forEach((inst) => {
if (props.selected && props.selected !== inst.groupUuid) return
const resources = inst.billingPlan.resources.filter(
({ key }) => key.includes('ips')
)
resources.forEach(({ price, period }) => {
const k = period / 2592000
result.push(+(price / k).toFixed(2))
})
})
return result.reduce((sum, num) => +sum + +num, 0)
})
const ipsQuantity = computed(() => {
const result = []
instancesStore.services.forEach((service) => {
service.instancesGroups.forEach((group) => {
group.instances.forEach((inst) => {
if (group.type !== 'ione') return
if (props.selected && props.selected !== group.uuid) return
result.push(inst.resources.ips_public)
result.push(inst.resources.ips_private)
})
})
})
return result.reduce((sum, num) => sum + num, 0)
})
</script>

<script>
export default { name: 'VDCIpsPrice' }
</script>

<style scoped>
.cloud__title {
display: flex;
flex-wrap: wrap;
gap: 0 4px;
margin: 0;
}
</style>
168 changes: 168 additions & 0 deletions src/components/cloud/vdc/ipsTable.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
<template>
<a-table row-key="ip" :columns="headers" :data-source="data">
<template #bodyCell="{ column, record }">
<div v-if="column.key === 'status'" class="status">
<div class="status__color" :style="{ background: record.color }" />
<div class="status__title">
{{ record.title }}
</div>
</div>

<a-popconfirm
v-if="column.key === 'actions'"
:title="$t('disk_manage.Do you want to proceed?')"
:ok-text="$t('Yes')"
:cancel-text="$t('Cancel')"
@confirm="removeIP(record)"
>
<a-button danger>
{{ capitalize($t('free IP')) }}
</a-button>
</a-popconfirm>
</template>
</a-table>
</template>

<script setup>
import { computed } from 'vue'
import { getInstStatusColor } from '@/functions.js'
import { useI18n } from 'vue-i18n'
import { useInstancesStore } from '@/stores/instances.js'
import { useNotification } from '@/hooks/utils'
const props = defineProps({
instances: { type: Array, required: true },
options: { type: Array, required: true },
selected: { type: String, required: true }
})
const i18n = useI18n()
const instancesStore = useInstancesStore()
const { openNotification } = useNotification()
const headers = computed(() => [
{ title: 'IP', dataIndex: 'ip', key: 'ip' },
{
title: i18n.t('status'),
dataIndex: 'status',
key: 'status',
sorter: (a, b) => a.status.localeCompare(b.status)
},
{ title: i18n.t('Actions'), key: 'actions' }
])
const data = computed(() => {
let { networking, status } = props.options.find(
({ uuid }) => uuid === props.selected
) ?? {}
if (!props.selected) {
props.options.forEach((option) => {
networking = { ...(networking ?? {}), ...option.networking }
status = { ...(status ?? {}), ...option.status }
})
}
if (!networking) return []
return setTableData(networking, status)
})
function setTableData (networking, status) {
const result = []
Object.entries(networking).forEach(([key, value]) => {
value.private?.forEach((ip) => {
result.push({
ip,
type: 'private',
instanceUuid: key,
title: value.title,
status: status[key],
color: getInstStatusColor(status[key])
})
})
value.public?.forEach((ip) => {
result.push({
ip,
type: 'public',
instanceUuid: key,
title: value.title,
status: status[key],
color: getInstStatusColor(status[key])
})
})
})
return result
}
async function removeIP (item) {
const { serviceUuid, groupUuid } = props.instances.find(
({ uuid }) => uuid === item.instanceUuid
) ?? {}
const serviceItem = instancesStore.services.find(({ uuid }) => uuid === serviceUuid)
const service = JSON.parse(JSON.stringify(serviceItem))
const group = service?.instancesGroups.find(({ uuid }) => uuid === groupUuid)
const instance = group.instances.find(({ uuid }) => uuid === item.instanceUuid)
setIpsToInst(instance, item)
setIpsToGroup(group)
await updateService(service)
}
function setIpsToInst (inst, item) {
if (item.type === 'private') {
const i = inst.state.meta.networking.private.indexOf(item.ip)
inst.resources.ips_private -= 1
inst.state.meta.networking.private.splice(i, 1)
}
if (item.type === 'public') {
const i = inst.state.meta.networking.public.indexOf(item.ip)
inst.resources.ips_public -= 1
inst.state.meta.networking.public.splice(i, 1)
}
}
function setIpsToGroup (group) {
const ips = group.instances.reduce((prev, curr) => ({
private: prev.private + curr.resources.ips_private,
public: prev.public + curr.resources.ips_public
}), { private: 0, public: 0 })
group.resources.ips_private = ips.private
group.resources.ips_public = ips.public
}
async function updateService (service) {
try {
await instancesStore.updateService(service)
openNotification('success', { message: i18n.t('Done') })
} catch (error) {
openNotification('error', {
message: error.response?.data?.message ?? error.message ?? error
})
console.error(error)
}
}
</script>
<style scoped>
.status {
display: flex;
align-items: center;
gap: 8px;
}
.status__color {
width: 10px;
height: 10px;
border-radius: 50%;
}
</style>
69 changes: 69 additions & 0 deletions src/components/cloud/vdc/orderIpButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<template>
<a-dropdown :trigger="['click']">
<a-button
block
type="primary"
size="large"
class="button"
:disabled="disabled"
>
{{ capitalize($t('order IP address')) }}
</a-button>

<template #overlay>
<a-menu style="max-height: 300px; overflow-y: scroll">
<a-menu-item v-for="inst of instances" :key="inst.uuid" @click="selectInstance(inst)">
{{ inst.title }}
</a-menu-item>
</a-menu>
</template>
</a-dropdown>

<a-modal
v-model:open="isModalVisible"
width="600px"
:title="$t('Network control')"
:footer="null"
>
<network-control
:item-service="service"
:instance="instance"
@close-modal="isModalVisible = false"
/>
</a-modal>
</template>

<script setup>
import { ref } from 'vue'
import { useInstancesStore } from '@/stores/instances.js'
import networkControl from '@/components/cloud/options/networkControl.vue'
defineProps({
instances: { type: Array, required: true },
disabled: { type: Boolean, required: true }
})
const instancesStore = useInstancesStore()
const service = ref({})
const instance = ref({})
const isModalVisible = ref(false)
function selectInstance (value) {
const item = instancesStore.services.find(
({ uuid }) => uuid === value.serviceUuid
)
instance.value = JSON.parse(JSON.stringify(value))
service.value = JSON.parse(JSON.stringify(item))
isModalVisible.value = true
}
</script>

<style scoped>
.button {
height: auto;
padding: 12px 15px;
}
</style>
Loading

0 comments on commit c82c322

Please sign in to comment.