This is an automated email from the ASF dual-hosted git repository.

rohit pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack-primate.git


The following commit(s) were added to refs/heads/master by this push:
     new 0b4122b  network: Add support for tiers in PF, LB rules for a VPC 
(#379)
0b4122b is described below

commit 0b4122bd3122b8197c7a910d8c8d9c2a896f7d45
Author: Hoang Nguyen <[email protected]>
AuthorDate: Wed Jun 24 14:54:25 2020 +0700

    network: Add support for tiers in PF, LB rules for a VPC (#379)
    
    Fixes #333
    Fixes #438
    
    Signed-off-by: Rohit Yadav <[email protected]>
    Co-authored-by: Rohit Yadav <[email protected]>
---
 src/components/view/ResourceView.vue  |  19 ++-
 src/views/network/EnableStaticNat.vue |   6 +-
 src/views/network/LoadBalancing.vue   | 242 +++++++++++++++++++++++++---------
 src/views/network/PortForwarding.vue  | 235 +++++++++++++++++++++++++--------
 4 files changed, 375 insertions(+), 127 deletions(-)

diff --git a/src/components/view/ResourceView.vue 
b/src/components/view/ResourceView.vue
index f3f79e2..c7035a9 100644
--- a/src/components/view/ResourceView.vue
+++ b/src/components/view/ResourceView.vue
@@ -43,7 +43,7 @@
             v-for="tab in tabs"
             :tab="$t('label.' + tab.name)"
             :key="tab.name"
-            v-if="showHideTab(tab)">
+            v-if="showTab(tab)">
             <component :is="tab.component" :resource="resource" 
:loading="loading" :tab="activeTab" />
           </a-tab-pane>
         </a-tabs>
@@ -97,8 +97,12 @@ export default {
       if (newItem.id === oldItem.id) return
 
       if (this.resource.associatednetworkid) {
-        api('listNetworks', { id: this.resource.associatednetworkid 
}).then(response => {
-          this.networkService = response.listnetworksresponse.network[0]
+        api('listNetworks', { id: this.resource.associatednetworkid, listall: 
true }).then(response => {
+          if (response && response.listnetworksresponse && 
response.listnetworksresponse.network) {
+            this.networkService = response.listnetworksresponse.network[0]
+          } else {
+            this.networkService = {}
+          }
         })
       }
     }
@@ -107,12 +111,15 @@ export default {
     onTabChange (key) {
       this.activeTab = key
     },
-    showHideTab (tab) {
+    showTab (tab) {
       if ('networkServiceFilter' in tab) {
-        if (this.resource.virtualmachineid && tab.name !== 'Firewall') {
+        if (this.resource && this.resource.virtualmachineid && 
!this.resource.vpcid && tab.name !== 'firewall') {
           return false
         }
-        if (this.resource && this.resource.vpcid && tab.name !== 'Firewall') {
+        if (this.resource && this.resource.virtualmachineid && 
this.resource.vpcid) {
+          return false
+        }
+        if (this.resource && this.resource.vpcid && tab.name !== 'firewall') {
           return true
         }
         return this.networkService && this.networkService.service &&
diff --git a/src/views/network/EnableStaticNat.vue 
b/src/views/network/EnableStaticNat.vue
index 3a7c35f..c9e22b0 100644
--- a/src/views/network/EnableStaticNat.vue
+++ b/src/views/network/EnableStaticNat.vue
@@ -172,7 +172,7 @@ export default {
         domainid: this.resource.domainid,
         keyword: this.searchQuery
       }).then(response => {
-        this.vmsList = response.listvirtualmachinesresponse.virtualmachine
+        this.vmsList = response.listvirtualmachinesresponse.virtualmachine || 
[]
       }).catch(error => {
         this.$notifyError(error)
       }).finally(() => {
@@ -204,9 +204,9 @@ export default {
       this.loading = true
       api('listNics', {
         virtualmachineid: this.selectedVm,
-        networkid: this.resource.associatednetworkid
+        networkid: this.resource.associatednetworkid || this.selectedVpcTier
       }).then(response => {
-        this.nicsList = response.listnicsresponse.nic
+        this.nicsList = response.listnicsresponse.nic || []
 
         let secondaryIps = this.nicsList.map(item => item.secondaryip)
 
diff --git a/src/views/network/LoadBalancing.vue 
b/src/views/network/LoadBalancing.vue
index b258676..638da12 100644
--- a/src/views/network/LoadBalancing.vue
+++ b/src/views/network/LoadBalancing.vue
@@ -18,6 +18,21 @@
 <template>
   <div>
     <div>
+      <div class="filter" v-if="'vpcid' in resource && !('associatednetworkid' 
in resource)">
+        <div class="form">
+          <div class="form__item" ref="newRuleTier">
+            <div class="form__label">{{ $t('label.tiername') }}</div>
+            <a-select v-model="newRule.tier">
+              <a-select-option
+                v-for="tier in tiers.data"
+                :loading="tiers.loading"
+                :key="tier.id">
+                {{ tier.displaytext }}
+              </a-select-option>
+            </a-select>
+          </div>
+        </div>
+      </div>
       <div class="form">
         <div class="form__item" ref="newRuleName">
           <div class="form__label"><span class="form__required">*</span>{{ 
$t('label.name') }}</div>
@@ -63,7 +78,7 @@
 
     <a-table
       size="small"
-      style="overflow-y: auto"
+      class="list-view"
       :loading="loading"
       :columns="columns"
       :dataSource="lbRules"
@@ -278,47 +293,58 @@
         {disabled: newRule.virtualmachineid === [] } }"
       @cancel="closeModal"
     >
+      <div>
+        <a-input-search
+          class="input-search"
+          placeholder="Search"
+          v-model="searchQuery"
+          allowClear
+          @search="onSearch" />
+        <a-table
+          size="small"
+          class="list-view"
+          :loading="addVmModalLoading"
+          :columns="vmColumns"
+          :dataSource="vms"
+          :pagination="false"
+          :rowKey="record => record.id"
+          :scroll="{ y: 300 }">
+          <div slot="name" slot-scope="text, record, index">
+            <span>
+              {{ text }}
+            </span>
+            <a-icon v-if="addVmModalNicLoading" type="loading"></a-icon>
+            <a-select
+              style="display: block"
+              v-else-if="!addVmModalNicLoading && 
newRule.virtualmachineid[index] === record.id"
+              mode="multiple"
+              v-model="newRule.vmguestip[index]"
+            >
+              <a-select-option v-for="(nic, nicIndex) in nics[index]" 
:key="nic" :value="nic">
+                {{ nic }}{{ nicIndex === 0 ? ' (Primary)' : null }}
+              </a-select-option>
+            </a-select>
+          </div>
 
-      <a-icon v-if="addVmModalLoading" type="loading"></a-icon>
-
-      <div v-else>
-        <div class="vm-modal__header">
-          <span style="min-width: 200px;">{{ $t('label.name') }}</span>
-          <span>{{ $t('label.instancename') }}</span>
-          <span>{{ $t('label.displayname') }}</span>
-          <span>{{ $t('label.ip') }}</span>
-          <span>{{ $t('label.account') }}</span>
-          <span>{{ $t('label.zonenamelabel') }}</span>
-          <span>{{ $t('label.state') }}</span>
-          <span>{{ $t('label.select') }}</span>
-        </div>
+          <div slot="state" slot-scope="text">
+            <status :text="text ? text : ''" displayText></status>
+          </div>
 
-        <a-checkbox-group style="width: 100%;">
-          <div v-for="(vm, index) in vms" :key="index" class="vm-modal__item">
-            <span style="min-width: 200px;">
-              <span>
-                {{ vm.name }}
-              </span>
-              <a-icon v-if="addVmModalNicLoading" type="loading"></a-icon>
-              <a-select
-                v-else-if="!addVmModalNicLoading && 
newRule.virtualmachineid[index] === vm.id"
-                mode="multiple"
-                v-model="newRule.vmguestip[index]"
-              >
-                <a-select-option v-for="(nic, nicIndex) in nics[index]" 
:key="nic" :value="nic">
-                  {{ nic }}{{ nicIndex === 0 ? ' (Primary)' : null }}
-                </a-select-option>
-              </a-select>
-            </span>
-            <span>{{ vm.instancename }}</span>
-            <span>{{ vm.displayname }}</span>
-            <span></span>
-            <span>{{ vm.account }}</span>
-            <span>{{ vm.zonename }}</span>
-            <span>{{ vm.state }}</span>
-            <a-checkbox :value="vm.id" @change="e => fetchNics(e, index)" />
+          <div slot="action" slot-scope="text, record, index" 
style="text-align: center">
+            <a-checkbox :value="record.id" @change="e => fetchNics(e, index)" 
/>
           </div>
-        </a-checkbox-group>
+        </a-table>
+        <a-pagination
+          class="pagination"
+          size="small"
+          :current="vmPage"
+          :pageSize="vmPageSize"
+          :total="vmCount"
+          :showTotal="total => `Total ${total} items`"
+          :pageSizeOptions="['10', '20', '40', '80', '100']"
+          @change="handleChangePage"
+          @showSizeChange="handleChangePageSize"
+          showSizeChanger/>
       </div>
 
     </a-modal>
@@ -423,7 +449,46 @@ export default {
           title: this.$t('label.action'),
           scopedSlots: { customRender: 'actions' }
         }
-      ]
+      ],
+      tiers: {
+        loading: false,
+        data: []
+      },
+      vmColumns: [
+        {
+          title: this.$t('label.name'),
+          dataIndex: 'name',
+          scopedSlots: { customRender: 'name' },
+          width: 220
+        },
+        {
+          title: this.$t('label.state'),
+          dataIndex: 'state',
+          scopedSlots: { customRender: 'state' }
+        },
+        {
+          title: this.$t('label.displayname'),
+          dataIndex: 'displayname'
+        },
+        {
+          title: this.$t('label.account'),
+          dataIndex: 'account'
+        },
+        {
+          title: this.$t('label.zonename'),
+          dataIndex: 'zonename'
+        },
+        {
+          title: this.$t('label.select'),
+          dataIndex: 'action',
+          scopedSlots: { customRender: 'action' },
+          width: 80
+        }
+      ],
+      vmPage: 1,
+      vmPageSize: 10,
+      vmCount: 0,
+      searchQuery: null
     }
   },
   mounted () {
@@ -446,9 +511,30 @@ export default {
   },
   methods: {
     fetchData () {
+      this.fetchListTiers()
+      this.fetchLBRules()
+    },
+    fetchListTiers () {
+      this.tiers.loading = true
+
+      api('listNetworks', {
+        account: this.resource.account,
+        domainid: this.resource.domainid,
+        supportedservices: 'Lb',
+        vpcid: this.resource.vpcid
+      }).then(json => {
+        this.tiers.data = json.listnetworksresponse.network || []
+        this.newRule.tier = this.tiers.data && this.tiers.data[0].id ? 
this.tiers.data[0].id : null
+        this.$forceUpdate()
+      }).catch(error => {
+        this.$notifyError(error)
+      }).finally(() => { this.tiers.loading = false })
+    },
+    fetchLBRules () {
       this.loading = true
       this.lbRules = []
       this.stickinessPolicies = []
+
       api('listLoadBalancerRules', {
         listAll: true,
         publicipid: this.resource.id,
@@ -882,26 +968,7 @@ export default {
         if (!this.newRule.name || !this.newRule.publicport || 
!this.newRule.privateport) return
       }
       this.addVmModalVisible = true
-      this.addVmModalLoading = true
-      api('listVirtualMachines', {
-        listAll: true,
-        page: 1,
-        pagesize: 500,
-        networkid: this.resource.associatednetworkid,
-        account: this.resource.account,
-        domainid: this.resource.domainid
-      }).then(response => {
-        this.vms = response.listvirtualmachinesresponse.virtualmachine
-        this.vms.forEach((vm, index) => {
-          this.newRule.virtualmachineid[index] = null
-          this.nics[index] = null
-          this.newRule.vmguestip[index] = null
-        })
-        this.addVmModalLoading = false
-      }).catch(error => {
-        this.$notifyError(error)
-        this.closeModal()
-      })
+      this.fetchVirtualMachines()
     },
     fetchNics (e, index) {
       if (!e.target.checked) {
@@ -917,7 +984,7 @@ export default {
         virtualmachineid: e.target.value,
         networkid: this.resource.associatednetworkid
       }).then(response => {
-        if (!response.listnicsresponse.nic[0]) return
+        if (!response || !response.listnicsresponse || 
!response.listnicsresponse.nic[0]) return
         const newItem = []
         newItem.push(response.listnicsresponse.nic[0].ipaddress)
         if (response.listnicsresponse.nic[0].secondaryip) {
@@ -931,6 +998,33 @@ export default {
         this.closeModal()
       })
     },
+    fetchVirtualMachines () {
+      this.vmCount = 0
+      this.vms = []
+      this.addVmModalLoading = true
+      const networkId = ('vpcid' in this.resource && !('associatednetworkid' 
in this.resource)) ? this.newRule.tier : this.resource.associatednetworkid
+      api('listVirtualMachines', {
+        listAll: true,
+        keyword: this.searchQuery,
+        page: this.vmPage,
+        pagesize: this.vmPageSize,
+        networkid: networkId,
+        account: this.resource.account,
+        domainid: this.resource.domainid
+      }).then(response => {
+        this.vmCount = response.listvirtualmachinesresponse.count || 0
+        this.vms = response.listvirtualmachinesresponse.virtualmachine || []
+        this.vms.forEach((vm, index) => {
+          this.newRule.virtualmachineid[index] = null
+          this.nics[index] = null
+          this.newRule.vmguestip[index] = null
+        })
+      }).catch(error => {
+        this.$notifyError(error)
+      }).finally(() => {
+        this.addVmModalLoading = false
+      })
+    },
     handleAssignToLBRule (data) {
       const vmIDIpMap = {}
 
@@ -991,9 +1085,10 @@ export default {
         return
       }
 
+      const networkId = ('vpcid' in this.resource && !('associatednetworkid' 
in this.resource)) ? this.newRule.tier : this.resource.associatednetworkid
       api('createLoadBalancerRule', {
         openfirewall: false,
-        networkid: this.resource.associatednetworkid,
+        networkid: networkId,
         publicipid: this.resource.id,
         algorithm: this.newRule.algorithm,
         name: this.newRule.name,
@@ -1040,6 +1135,10 @@ export default {
       this.page = currentPage
       this.pageSize = pageSize
       this.fetchData()
+    },
+    onSearch (value) {
+      this.searchQuery = value
+      this.fetchVirtualMachines()
     }
   }
 }
@@ -1372,6 +1471,7 @@ export default {
 
   .pagination {
     margin-top: 20px;
+    text-align: right;
   }
 
   .actions {
@@ -1381,4 +1481,22 @@ export default {
       }
     }
   }
+
+  .list-view {
+    overflow-y: auto;
+    display: block;
+    width: 100%;
+  }
+
+  .filter {
+    display: block;
+    width: 240px;
+    margin-bottom: 10px;
+  }
+
+  .input-search {
+    margin-bottom: 10px;
+    width: 220px;
+    float: right;
+  }
 </style>
diff --git a/src/views/network/PortForwarding.vue 
b/src/views/network/PortForwarding.vue
index f5bc4ac..dabf6e3 100644
--- a/src/views/network/PortForwarding.vue
+++ b/src/views/network/PortForwarding.vue
@@ -18,6 +18,21 @@
 <template>
   <div>
     <div>
+      <div class="filter" v-if="'vpcid' in resource && !('associatednetworkid' 
in resource)">
+        <div class="form">
+          <div class="form__item" ref="newRuleTier">
+            <div class="form__label">{{ $t('label.tiername') }}</div>
+            <a-select v-model="newRule.tier">
+              <a-select-option
+                v-for="tier in tiers.data"
+                :loading="tiers.loading"
+                :key="tier.id">
+                {{ tier.displaytext }}
+              </a-select-option>
+            </a-select>
+          </div>
+        </div>
+      </div>
       <div class="form">
         <div class="form__item">
           <div class="form__label">{{ $t('label.privateport') }}</div>
@@ -159,57 +174,70 @@
         {disabled: newRule.virtualmachineid === null } }"
       @cancel="closeModal"
     >
+      <div>
+        <a-input-search
+          class="input-search"
+          placeholder="Search"
+          v-model="searchQuery"
+          allowClear
+          @search="onSearch" />
+        <a-table
+          size="small"
+          class="list-view"
+          :loading="addVmModalLoading"
+          :columns="vmColumns"
+          :dataSource="vms"
+          :pagination="false"
+          :rowKey="record => record.id"
+          :scroll="{ y: 300 }">
+          <div slot="name" slot-scope="text, record">
+            <span>
+              {{ text }}
+            </span>
+            <a-icon v-if="addVmModalNicLoading" type="loading"></a-icon>
+            <a-select
+              style="display: block"
+              v-else-if="!addVmModalNicLoading && newRule.virtualmachineid === 
record.id"
+              v-model="newRule.vmguestip"
+            >
+              <a-select-option v-for="(nic, nicIndex) in nics" :key="nic" 
:value="nic">
+                {{ nic }}{{ nicIndex === 0 ? ' (Primary)' : null }}
+              </a-select-option>
+            </a-select>
+          </div>
 
-      <a-icon v-if="addVmModalLoading" type="loading"></a-icon>
-
-      <div v-else>
-        <div class="vm-modal__header">
-          <span style="min-width: 200px;">{{ $t('label.name') }}</span>
-          <span>{{ $t('label.instancename') }}</span>
-          <span>{{ $t('label.displayname') }}</span>
-          <span>{{ $t('label.ip') }}</span>
-          <span>{{ $t('label.account') }}</span>
-          <span>{{ $t('label.zone') }}</span>
-          <span>{{ $t('label.state') }}</span>
-          <span>{{ $t('label.select') }}</span>
-        </div>
+          <div slot="state" slot-scope="text">
+            <status :text="text ? text : ''" displayText></status>
+          </div>
 
-        <a-radio-group v-model="newRule.virtualmachineid" style="width: 100%;" 
@change="fetchNics">
-          <div v-for="(vm, index) in vms" :key="index" class="vm-modal__item">
-
-            <span style="min-width: 200px;">
-              <span>
-                {{ vm.name }}
-              </span>
-              <a-icon v-if="addVmModalNicLoading" type="loading"></a-icon>
-              <a-select
-                v-else-if="!addVmModalNicLoading && newRule.virtualmachineid 
=== vm.id"
-                v-model="newRule.vmguestip">
-                <a-select-option v-for="(nic, nicIndex) in nics" :key="nic" 
:value="nic">
-                  {{ nic }}{{ nicIndex === 0 ? ' (Primary)' : null }}
-                </a-select-option>
-              </a-select>
-            </span>
-            <span>{{ vm.instancename }}</span>
-            <span>{{ vm.displayname }}</span>
-            <span></span>
-            <span>{{ vm.account }}</span>
-            <span>{{ vm.zonename }}</span>
-            <span>{{ vm.state }}</span>
-            <a-radio :value="vm.id" />
+          <div slot="action" slot-scope="text, record" style="text-align: 
center">
+            <a-radio :value="record.id" @change="e => fetchNics(e)" />
           </div>
-        </a-radio-group>
+        </a-table>
+        <a-pagination
+          class="pagination"
+          size="small"
+          :current="vmPage"
+          :pageSize="vmPageSize"
+          :total="vmCount"
+          :showTotal="total => `Total ${total} items`"
+          :pageSizeOptions="['10', '20', '40', '80', '100']"
+          @change="handleChangePage"
+          @showSizeChange="handleChangePageSize"
+          showSizeChanger/>
       </div>
-
     </a-modal>
-
   </div>
 </template>
 
 <script>
 import { api } from '@/api'
+import Status from '@/components/widgets/Status'
 
 export default {
+  components: {
+    Status
+  },
   props: {
     resource: {
       type: Object,
@@ -272,7 +300,51 @@ export default {
           title: this.$t('label.action'),
           scopedSlots: { customRender: 'actions' }
         }
-      ]
+      ],
+      tiers: {
+        loading: false,
+        data: []
+      },
+      vmColumns: [
+        {
+          title: this.$t('label.name'),
+          dataIndex: 'name',
+          scopedSlots: { customRender: 'name' },
+          width: 210
+        },
+        {
+          title: this.$t('label.state'),
+          dataIndex: 'state',
+          scopedSlots: { customRender: 'state' }
+        },
+        {
+          title: this.$t('label.displayname'),
+          dataIndex: 'displayname'
+        },
+        {
+          title: this.$t('label.ip'),
+          dataIndex: 'ip',
+          width: 100
+        },
+        {
+          title: this.$t('label.account'),
+          dataIndex: 'account'
+        },
+        {
+          title: this.$t('label.zone'),
+          dataIndex: 'zonename'
+        },
+        {
+          title: this.$t('label.select'),
+          dataIndex: 'action',
+          scopedSlots: { customRender: 'action' },
+          width: 80
+        }
+      ],
+      vmPage: 1,
+      vmPageSize: 10,
+      vmCount: 0,
+      searchQuery: null
     }
   },
   mounted () {
@@ -295,6 +367,28 @@ export default {
   },
   methods: {
     fetchData () {
+      this.fetchListTiers()
+      this.fetchPFRules()
+    },
+    fetchListTiers () {
+      if ('vpcid' in this.resource && 'associatednetworkid' in this.resource) {
+        return
+      }
+      this.tiers.loading = true
+      api('listNetworks', {
+        account: this.resource.account,
+        domainid: this.resource.domainid,
+        supportedservices: 'PortForwarding',
+        vpcid: this.resource.vpcid
+      }).then(json => {
+        this.tiers.data = json.listnetworksresponse.network || []
+        this.newRule.tier = this.tiers.data && this.tiers.data[0].id ? 
this.tiers.data[0].id : null
+        this.$forceUpdate()
+      }).catch(error => {
+        this.$notifyError(error)
+      }).finally(() => { this.tiers.loading = false })
+    },
+    fetchPFRules () {
       this.loading = true
       api('listPortForwardingRules', {
         listAll: true,
@@ -331,10 +425,11 @@ export default {
     addRule () {
       this.loading = true
       this.addVmModalVisible = false
+      const networkId = ('vpcid' in this.resource && !('associatednetworkid' 
in this.resource)) ? this.newRule.tier : this.resource.associatednetworkid
       api('createPortForwardingRule', {
         ...this.newRule,
         ipaddressid: this.resource.id,
-        networkid: this.resource.associatednetworkid
+        networkid: networkId
       }).then(response => {
         this.$pollJob({
           jobId: response.createportforwardingruleresponse.jobid,
@@ -476,24 +571,11 @@ export default {
     },
     openAddVMModal () {
       this.addVmModalVisible = true
-      this.addVmModalLoading = true
-      api('listVirtualMachines', {
-        listAll: true,
-        page: 1,
-        pagesize: 500,
-        networkid: this.resource.associatednetworkid,
-        account: this.resource.account,
-        domainid: this.resource.domainid
-      }).then(response => {
-        this.vms = response.listvirtualmachinesresponse.virtualmachine
-        this.addVmModalLoading = false
-      }).catch(error => {
-        this.$notifyError(error)
-        this.closeModal()
-      })
+      this.fetchVirtualMachines()
     },
     fetchNics (e) {
       this.addVmModalNicLoading = true
+      this.newRule.virtualmachineid = e.target.value
       api('listNics', {
         virtualmachineid: e.target.value,
         networkid: this.resource.associatednetworkid
@@ -512,6 +594,27 @@ export default {
         this.closeModal()
       })
     },
+    fetchVirtualMachines () {
+      this.vmCount = 0
+      this.vms = []
+      this.addVmModalLoading = true
+      const networkId = ('vpcid' in this.resource && !('associatednetworkid' 
in this.resource)) ? this.newRule.tier : this.resource.associatednetworkid
+      api('listVirtualMachines', {
+        listAll: true,
+        keyword: this.searchQuery,
+        page: this.vmPage,
+        pagesize: this.vmPageSize,
+        networkid: networkId,
+        account: this.resource.account,
+        domainid: this.resource.domainid
+      }).then(response => {
+        this.vmCount = response.listvirtualmachinesresponse.count || 0
+        this.vms = response.listvirtualmachinesresponse.virtualmachine
+        this.addVmModalLoading = false
+      }).catch(error => {
+        this.$notifyError(error)
+      })
+    },
     handleChangePage (page, pageSize) {
       this.page = page
       this.pageSize = pageSize
@@ -521,6 +624,10 @@ export default {
       this.page = currentPage
       this.pageSize = pageSize
       this.fetchData()
+    },
+    onSearch (value) {
+      this.searchQuery = value
+      this.fetchVirtualMachines()
     }
   }
 }
@@ -707,6 +814,22 @@ export default {
 
   .pagination {
     margin-top: 20px;
+    text-align: right;
   }
 
+  .list-view {
+    overflow-y: auto;
+    display: block;
+    width: 100%;
+  }
+
+  .filter {
+    display: block;
+    width: 240px;
+    margin-bottom: 10px;
+
+    .form__item {
+      width: 100%;
+    }
+  }
 </style>

Reply via email to