Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
web/satellite: common table component created
Change-Id: Ie45a2c37257f3311c767adcea1a22f284b66f24e
- Loading branch information
1 parent
43ed35e
commit f7a3be5
Showing
6 changed files
with
338 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright (C) 2022 Storj Labs, Inc. | ||
// See LICENSE for copying information. | ||
|
||
<template> | ||
<tr> | ||
<th v-if="selectable" class="icon"> | ||
<v-checkbox @setData="onChange" /> | ||
</th> | ||
<th v-for="(val, key, index) in item" :key="index" class="align-left data"> | ||
<p>{{ val }}</p> | ||
</th> | ||
<slot name="options" /> | ||
</tr> | ||
</template> | ||
|
||
<script lang="ts"> | ||
import { Component, Prop, Vue } from 'vue-property-decorator'; | ||
import VCheckbox from "@/components/common/VCheckbox.vue"; | ||
// @vue/component | ||
@Component({ | ||
components: { VCheckbox } | ||
}) | ||
export default class TableItem extends Vue { | ||
@Prop({ default: false }) | ||
public readonly selectable: boolean; | ||
@Prop({ default: () => {} }) | ||
public readonly item: object; | ||
public isSelected = false; | ||
public onChange(value: boolean): void { | ||
this.isSelected = value; | ||
this.$emit('setSelected', value); | ||
} | ||
} | ||
</script> |
137 changes: 137 additions & 0 deletions
137
web/satellite/src/components/common/TablePagination.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
// Copyright (C) 2022 Storj Labs, Inc. | ||
// See LICENSE for copying information. | ||
|
||
<template> | ||
<div class="pagination-container"> | ||
<div class="pagination-container__pages"> | ||
<span class="pagination-container__pages__label">{{ label }}</span> | ||
<div class="pagination-container__button" @click="prevPage"> | ||
<PaginationRightIcon class="pagination-container__button__image reversed" /> | ||
</div> | ||
<div class="pagination-container__button" @click="nextPage"> | ||
<PaginationRightIcon class="pagination-container__button__image" /> | ||
</div> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts"> | ||
import { Component, Prop, Vue } from 'vue-property-decorator'; | ||
import PaginationRightIcon from '@/../static/images/common/tablePaginationArrowRight.svg'; | ||
import { OnPageClickCallback } from '@/types/pagination'; | ||
// @vue/component | ||
@Component({ | ||
components: { | ||
PaginationRightIcon, | ||
}, | ||
}) | ||
export default class TablePagination extends Vue { | ||
private currentPageNumber = 1; | ||
public isLoading = false; | ||
@Prop({default: 0}) | ||
private readonly totalPageCount: number; | ||
@Prop({default: 0}) | ||
private readonly limit: number; | ||
@Prop({default: 0}) | ||
private readonly totalItemsCount: number; | ||
@Prop({default: () => () => new Promise(() => false)}) | ||
private readonly onPageClickCallback: OnPageClickCallback; | ||
public get label(): string { | ||
const currentMaxPage = this.currentPageNumber * this.limit > this.totalItemsCount ? | ||
this.totalItemsCount | ||
: this.currentPageNumber * this.limit; | ||
return `${this.currentPageNumber * this.limit - this.limit + 1} - ${currentMaxPage} of ${this.totalItemsCount}` | ||
} | ||
/** | ||
* Indicates if current page is first. | ||
*/ | ||
public get isFirstPage(): boolean { | ||
return this.currentPageNumber === 1; | ||
} | ||
/** | ||
* Indicates if current page is last. | ||
*/ | ||
public get isLastPage(): boolean { | ||
return this.currentPageNumber === this.totalPageCount; | ||
} | ||
/** | ||
* nextPage fires after 'next' arrow click. | ||
*/ | ||
public async nextPage(): Promise<void> { | ||
if (this.isLastPage || this.isLoading) { | ||
return; | ||
} | ||
this.isLoading = true; | ||
await this.onPageClickCallback(this.currentPageNumber + 1); | ||
this.incrementCurrentPage(); | ||
this.isLoading = false; | ||
} | ||
/** | ||
* prevPage fires after 'previous' arrow click. | ||
*/ | ||
public async prevPage(): Promise<void> { | ||
if (this.isFirstPage || this.isLoading) { | ||
return; | ||
} | ||
this.isLoading = true; | ||
await this.onPageClickCallback(this.currentPageNumber - 1); | ||
this.decrementCurrentPage(); | ||
this.isLoading = false; | ||
} | ||
private incrementCurrentPage(): void { | ||
this.currentPageNumber++; | ||
} | ||
private decrementCurrentPage(): void { | ||
this.currentPageNumber--; | ||
} | ||
} | ||
</script> | ||
|
||
<style scoped lang="scss"> | ||
.pagination-container { | ||
display: flex; | ||
align-items: center; | ||
justify-content: flex-end; | ||
&__pages { | ||
display: flex; | ||
align-items: center; | ||
&__label { | ||
margin-right: 25px; | ||
font-family: 'font_regular', sans-serif; | ||
font-size: 14px; | ||
line-height: 24px; | ||
color: rgb(44 53 58 / 60%); | ||
} | ||
} | ||
&__button { | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
cursor: pointer; | ||
width: 15px; | ||
height: 15px; | ||
max-width: 15px; | ||
max-height: 15px; | ||
} | ||
} | ||
.reversed { | ||
transform: rotate(180deg); | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
// Copyright (C) 2022 Storj Labs, Inc. | ||
// See LICENSE for copying information. | ||
|
||
<template> | ||
<div class="table-wrapper"> | ||
<table class="base-table" border="0" cellpadding="0" cellspacing="0"> | ||
<thead> | ||
<tr> | ||
<th v-if="selectable" class="icon" /> | ||
<slot name="head" /> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
<slot name="body" :selectable-items="selectableItems" @checkItem="checkItem" /> | ||
</tbody> | ||
</table> | ||
<div v-if="totalPageCount > 0" class="table-footer"> | ||
<span class="table-footer__label">{{ totalItemsCount }} {{ itemsLabel }}</span> | ||
<table-pagination | ||
:total-page-count="totalPageCount" | ||
:total-items-count="totalItemsCount" | ||
:limit="limit" | ||
:on-page-click-callback="onPageClickCallback" | ||
/> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts"> | ||
import { Component, Prop, Vue } from 'vue-property-decorator'; | ||
import TablePagination from "@/components/common/TablePagination.vue"; | ||
import { OnPageClickCallback } from "@/types/pagination"; | ||
export type SelectableItem<T> = T & { | ||
isSelected: boolean; | ||
} | ||
// @vue/component | ||
@Component({ | ||
components: { | ||
TablePagination, | ||
} | ||
}) | ||
export default class VTable extends Vue { | ||
@Prop({ default: false }) | ||
public readonly selectable: boolean; | ||
@Prop({default: 0}) | ||
private readonly totalPageCount: number; | ||
@Prop({default: "items"}) | ||
private readonly itemsLabel: string; | ||
@Prop({default: 0}) | ||
private readonly limit: number; | ||
@Prop({default: () => []}) | ||
private readonly items: object[]; | ||
@Prop({default: 0}) | ||
private readonly totalItemsCount: number; | ||
@Prop({default: () => () => new Promise(() => false)}) | ||
private readonly onPageClickCallback: OnPageClickCallback; | ||
public selectableItems: SelectableItem<object>[] = []; | ||
public mounted(): void { | ||
this.selectableItems = this.items.map(item => ({ isSelected: false, ...item })); | ||
} | ||
public checkItem({ value, index }: { value: boolean, index: number }): void { | ||
this.selectableItems[index].isSelected = value; | ||
} | ||
} | ||
</script> | ||
|
||
<style lang="scss"> | ||
.table-wrapper { | ||
background: #fff; | ||
box-shadow: 0 4px 32px rgb(0 0 0 / 4%); | ||
border-radius: 12px; | ||
} | ||
.base-table { | ||
display: table; | ||
width: 100%; | ||
z-index: 997; | ||
th { | ||
box-sizing: border-box; | ||
padding: 16px; | ||
overflow: hidden; | ||
white-space: nowrap; | ||
text-overflow: ellipsis; | ||
font-family: 'font_regular', sans-serif; | ||
} | ||
thead { | ||
background: var(--c-block-gray); | ||
text-transform: uppercase; | ||
tr { | ||
height: 52px; | ||
font-size: 12px; | ||
color: #6b7280; | ||
} | ||
} | ||
tbody { | ||
tr:hover { | ||
background: #e6edf7; | ||
} | ||
th { | ||
font-family: 'font_regular', sans-serif; | ||
color: #111827; | ||
font-size: 14px; | ||
border-top: solid 1px #e5e7eb; | ||
} | ||
.data { | ||
font-family: 'font_bold', sans-serif; | ||
} | ||
.data ~ .data { | ||
font-family: 'font_regular', sans-serif; | ||
} | ||
} | ||
} | ||
.align-left { | ||
text-align: left; | ||
} | ||
.overflow-visible { | ||
overflow: visible !important; | ||
} | ||
.icon { | ||
width: 5%; | ||
overflow: visible !important; | ||
} | ||
.table-footer { | ||
display: flex; | ||
align-items: center; | ||
justify-content: space-between; | ||
padding: 15px 20px; | ||
font-size: 14px; | ||
line-height: 24px; | ||
color: rgb(44 53 58 / 60%); | ||
border-top: solid 1px #e5e7eb; | ||
} | ||
</style> |
3 changes: 3 additions & 0 deletions
3
web/satellite/static/images/common/tablePaginationArrowRight.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 10 additions & 2 deletions
12
web/satellite/tests/unit/common/__snapshots__/VCheckbox.spec.ts.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,13 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`Checkbox.vue renders correctly 1`] = `<div class="wrap"><label class="container"><input id="checkbox" type="checkbox" class="checkmark-input"> <span class="checkmark"></span></label> <label for="checkbox" class="label"></label></div>`; | ||
exports[`Checkbox.vue renders correctly 1`] = ` | ||
<div class="wrap"><label class="container"><input id="checkbox" type="checkbox" class="checkmark-input"> <span class="checkmark"></span></label> | ||
<!----> | ||
</div> | ||
`; | ||
exports[`Checkbox.vue renders correctly with error 1`] = `<div class="wrap"><label class="container"><input id="checkbox" type="checkbox" class="checkmark-input"> <span class="checkmark error"></span></label> <label for="checkbox" class="label"></label></div>`; | ||
exports[`Checkbox.vue renders correctly with error 1`] = ` | ||
<div class="wrap"><label class="container"><input id="checkbox" type="checkbox" class="checkmark-input"> <span class="checkmark error"></span></label> | ||
<!----> | ||
</div> | ||
`; |
f7a3be5
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This commit has been mentioned on Storj Community Forum (official). There might be relevant details there:
https://forum.storj.io/t/release-preparation-v-1-58/18976/1