Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
amundsen_dev
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Surendar Reddy Mangannagari
amundsen_dev
Commits
b2230452
Unverified
Commit
b2230452
authored
Sep 02, 2020
by
Marcos Iglesias
Committed by
GitHub
Sep 02, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: Empty and Loading states for the table (#639)
Signed-off-by:
Marcos Iglesias Valle
<
golodhros@gmail.com
>
parent
97a5e14f
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
357 additions
and
31 deletions
+357
-31
_animations.scss
amundsen_application/static/css/_animations.scss
+5
-1
index.spec.tsx
...lication/static/js/components/common/Table/index.spec.tsx
+208
-0
index.tsx
...n_application/static/js/components/common/Table/index.tsx
+96
-30
styles.scss
...application/static/js/components/common/Table/styles.scss
+33
-0
table.story.tsx
...ication/static/js/components/common/Table/table.story.tsx
+6
-0
testDataBuilder.ts
...tion/static/js/components/common/Table/testDataBuilder.ts
+9
-0
No files found.
amundsen_application/static/css/_animations.scss
View file @
b2230452
...
@@ -16,7 +16,7 @@ $loading-curve: cubic-bezier(0.45, 0, 0.15, 1);
...
@@ -16,7 +16,7 @@ $loading-curve: cubic-bezier(0.45, 0, 0.15, 1);
}
}
}
}
.
is-shimmer-animated
{
%
is-shimmer-animated
{
animation
:
$loading-duration
shimmer
$loading-curve
infinite
;
animation
:
$loading-duration
shimmer
$loading-curve
infinite
;
background-image
:
linear-gradient
(
background-image
:
linear-gradient
(
to
right
,
to
right
,
...
@@ -29,3 +29,7 @@ $loading-curve: cubic-bezier(0.45, 0, 0.15, 1);
...
@@ -29,3 +29,7 @@ $loading-curve: cubic-bezier(0.45, 0, 0.15, 1);
background-repeat
:
no-repeat
;
background-repeat
:
no-repeat
;
background-size
:
300%
100%
;
background-size
:
300%
100%
;
}
}
.is-shimmer-animated
{
@extend
%is-shimmer-animated
;
}
amundsen_application/static/js/components/common/Table/index.spec.tsx
View file @
b2230452
...
@@ -30,6 +30,83 @@ describe('Table', () => {
...
@@ -30,6 +30,83 @@ describe('Table', () => {
}).
not
.
toThrow
();
}).
not
.
toThrow
();
});
});
describe
(
'when empty data is passed'
,
()
=>
{
const
{
columns
,
data
}
=
dataBuilder
.
withEmptyData
().
build
();
it
(
'renders a table'
,
()
=>
{
const
{
wrapper
}
=
setup
({
data
,
columns
,
});
const
expected
=
1
;
const
actual
=
wrapper
.
find
(
'.ams-table'
).
length
;
expect
(
actual
).
toEqual
(
expected
);
});
describe
(
'table header'
,
()
=>
{
it
(
'renders a table header'
,
()
=>
{
const
{
wrapper
}
=
setup
({
data
,
columns
,
});
const
expected
=
1
;
const
actual
=
wrapper
.
find
(
'.ams-table-header'
).
length
;
expect
(
actual
).
toEqual
(
expected
);
});
it
(
'renders one cell inside the header'
,
()
=>
{
const
{
wrapper
}
=
setup
({
data
,
columns
,
});
const
expected
=
1
;
const
actual
=
wrapper
.
find
(
'.ams-table-header .ams-table-heading-cell'
).
length
;
expect
(
actual
).
toEqual
(
expected
);
});
});
describe
(
'table body'
,
()
=>
{
it
(
'renders a table body'
,
()
=>
{
const
{
wrapper
}
=
setup
({
data
,
columns
,
});
const
expected
=
1
;
const
actual
=
wrapper
.
find
(
'.ams-table-body'
).
length
;
expect
(
actual
).
toEqual
(
expected
);
});
it
(
'renders one row'
,
()
=>
{
const
{
wrapper
}
=
setup
({
data
,
columns
,
});
const
expected
=
1
;
const
actual
=
wrapper
.
find
(
'.ams-table-row'
).
length
;
expect
(
actual
).
toEqual
(
expected
);
});
it
(
'renders an empty message'
,
()
=>
{
const
{
wrapper
}
=
setup
({
data
,
columns
,
});
const
expected
=
1
;
const
actual
=
wrapper
.
find
(
'.ams-table-row .ams-empty-message-cell'
)
.
length
;
expect
(
actual
).
toEqual
(
expected
);
});
});
});
describe
(
'when simple data is passed'
,
()
=>
{
describe
(
'when simple data is passed'
,
()
=>
{
it
(
'renders a table'
,
()
=>
{
it
(
'renders a table'
,
()
=>
{
const
{
wrapper
}
=
setup
();
const
{
wrapper
}
=
setup
();
...
@@ -119,6 +196,137 @@ describe('Table', () => {
...
@@ -119,6 +196,137 @@ describe('Table', () => {
});
});
});
});
});
});
describe
(
'options'
,
()
=>
{
describe
(
'when a tableClassName is passed'
,
()
=>
{
it
(
'adds the class to the table'
,
()
=>
{
const
{
wrapper
}
=
setup
({
options
:
{
tableClassName
:
'test-class'
},
});
const
expected
=
1
;
const
actual
=
wrapper
.
find
(
'.test-class'
).
length
;
expect
(
actual
).
toEqual
(
expected
);
});
});
describe
(
'when isLoading is active'
,
()
=>
{
it
(
'renders a table'
,
()
=>
{
const
{
wrapper
}
=
setup
({
data
:
[],
columns
:
[],
options
:
{
isLoading
:
true
,
numLoadingBlocks
:
10
,
},
});
const
expected
=
1
;
const
actual
=
wrapper
.
find
(
'.ams-table'
).
length
;
expect
(
actual
).
toEqual
(
expected
);
});
describe
(
'table header'
,
()
=>
{
it
(
'renders a table header'
,
()
=>
{
const
{
wrapper
}
=
setup
({
data
:
[],
columns
:
[],
options
:
{
isLoading
:
true
,
},
});
const
expected
=
1
;
const
actual
=
wrapper
.
find
(
'.ams-table-header'
).
length
;
expect
(
actual
).
toEqual
(
expected
);
});
it
(
'renders one cell inside the header'
,
()
=>
{
const
{
wrapper
}
=
setup
({
data
:
[],
columns
:
[],
options
:
{
isLoading
:
true
,
numLoadingBlocks
:
10
,
},
});
const
expected
=
1
;
const
actual
=
wrapper
.
find
(
'.ams-table-header .ams-table-heading-loading-cell'
).
length
;
expect
(
actual
).
toEqual
(
expected
);
});
it
(
'renders one loading block inside the header'
,
()
=>
{
const
{
wrapper
}
=
setup
({
data
:
[],
columns
:
[],
options
:
{
isLoading
:
true
,
numLoadingBlocks
:
10
,
},
});
const
expected
=
1
;
const
actual
=
wrapper
.
find
(
'.ams-table-header .ams-table-shimmer-block'
).
length
;
expect
(
actual
).
toEqual
(
expected
);
});
});
describe
(
'table body'
,
()
=>
{
it
(
'renders a table body'
,
()
=>
{
const
{
wrapper
}
=
setup
({
data
:
[],
columns
:
[],
options
:
{
isLoading
:
true
,
numLoadingBlocks
:
10
,
},
});
const
expected
=
1
;
const
actual
=
wrapper
.
find
(
'.ams-table-body'
).
length
;
expect
(
actual
).
toEqual
(
expected
);
});
it
(
'renders one row'
,
()
=>
{
const
{
wrapper
}
=
setup
({
data
:
[],
columns
:
[],
options
:
{
isLoading
:
true
,
numLoadingBlocks
:
10
,
},
});
const
expected
=
1
;
const
actual
=
wrapper
.
find
(
'.ams-table-row'
).
length
;
expect
(
actual
).
toEqual
(
expected
);
});
it
(
'renders the proper number of shimmering blocks'
,
()
=>
{
const
numOfLoadingBlocks
=
10
;
const
{
wrapper
}
=
setup
({
data
:
[],
columns
:
[],
options
:
{
isLoading
:
true
,
numLoadingBlocks
:
numOfLoadingBlocks
,
},
});
const
expected
=
numOfLoadingBlocks
;
const
actual
=
wrapper
.
find
(
'.ams-table-row .shimmer-resource-loader-item'
).
length
;
expect
(
actual
).
toEqual
(
expected
);
});
});
});
});
});
});
describe
(
'lifetime'
,
()
=>
{});
describe
(
'lifetime'
,
()
=>
{});
...
...
amundsen_application/static/js/components/common/Table/index.tsx
View file @
b2230452
...
@@ -3,42 +3,86 @@
...
@@ -3,42 +3,86 @@
import
*
as
React
from
'react'
;
import
*
as
React
from
'react'
;
import
ShimmeringResourceLoader
from
'../ShimmeringResourceLoader'
;
import
'./styles.scss'
;
import
'./styles.scss'
;
export
interface
TableColumn
{
export
interface
TableColumn
{
title
:
string
;
title
:
string
;
field
:
string
;
field
:
string
;
horAlign
?:
'left'
|
'right'
|
'center'
;
// width?: number;
// className?: string;
// className?: string;
// horAlign?: 'left' | 'right' | 'center';
// width?: number;
// sortable?: bool (false)
// sortable?: bool (false)
// data?: () => React.ReactNode ((row,index) => <div>{index}</div>)
// data?: () => React.ReactNode ((row,index) => <div>{index}</div>)
// actions?: Action[]
// actions?: Action[]
}
}
export
interface
TableOptions
{
tableClassName
?:
string
;
isLoading
?:
boolean
;
numLoadingBlocks
?:
number
;
}
export
interface
TableProps
{
export
interface
TableProps
{
columns
:
TableColumn
[];
columns
:
TableColumn
[];
data
:
[];
data
:
[];
options
?:
TableOptions
;
}
}
const
Table
:
React
.
FC
<
TableProps
>
=
({
data
,
columns
}:
TableProps
)
=>
{
const
DEFAULT_EMPTY_MESSAGE
=
'No Results'
;
const
fields
=
columns
.
map
(({
field
})
=>
field
)
;
const
DEFAULT_LOADING_ITEMS
=
3
;
return
(
type
EmptyRowProps
=
{
<
table
className=
"ams-table"
>
colspan
:
number
;
<
thead
className=
"ams-table-header"
>
};
const
EmptyRow
:
React
.
FC
<
EmptyRowProps
>
=
({
colspan
}:
EmptyRowProps
)
=>
(
<
tr
className=
"ams-table-row"
>
<
td
className=
"ams-empty-message-cell"
colSpan=
{
colspan
}
>
{
DEFAULT_EMPTY_MESSAGE
}
</
td
>
</
tr
>
);
const
ShimmeringHeader
:
React
.
FC
=
()
=>
(
<
tr
>
<
tr
>
{
columns
.
map
(({
title
},
index
)
=>
{
<
th
className=
"ams-table-heading-loading-cell"
>
return
(
<
div
className=
"ams-table-shimmer-block"
/>
<
th
className=
"ams-table-heading-cell"
key=
{
`index:${index}`
}
>
{
title
}
</
th
>
</
th
>
);
})
}
</
tr
>
</
tr
>
</
thead
>
);
<
tbody
className=
"ams-table-body"
>
{
data
.
map
((
item
,
index
)
=>
{
type
ShimmeringBodyProps
=
{
numLoadingBlocks
:
number
;
};
const
ShimmeringBody
:
React
.
FC
<
ShimmeringBodyProps
>
=
({
numLoadingBlocks
,
}:
ShimmeringBodyProps
)
=>
(
<
tr
className=
"ams-table-row"
>
<
td
className=
"ams-table-body-loading-cell"
>
<
ShimmeringResourceLoader
numItems=
{
numLoadingBlocks
}
/>
</
td
>
</
tr
>
);
const
Table
:
React
.
FC
<
TableProps
>
=
({
data
,
columns
,
options
=
{},
}:
TableProps
)
=>
{
const
{
tableClassName
=
''
,
isLoading
=
false
,
numLoadingBlocks
=
DEFAULT_LOADING_ITEMS
,
}
=
options
;
const
fields
=
columns
.
map
(({
field
})
=>
field
);
let
body
:
React
.
ReactNode
=
<
EmptyRow
colspan=
{
fields
.
length
}
/>;
if
(
data
.
length
)
{
body
=
data
.
map
((
item
,
index
)
=>
{
return
(
return
(
<
tr
className=
"ams-table-row"
key=
{
`index:${index}`
}
>
<
tr
className=
"ams-table-row"
key=
{
`index:${index}`
}
>
{
Object
.
entries
(
item
)
{
Object
.
entries
(
item
)
...
@@ -50,8 +94,30 @@ const Table: React.FC<TableProps> = ({ data, columns }: TableProps) => {
...
@@ -50,8 +94,30 @@ const Table: React.FC<TableProps> = ({ data, columns }: TableProps) => {
))
}
))
}
</
tr
>
</
tr
>
);
);
});
}
let
header
:
React
.
ReactNode
=
(
<
tr
>
{
columns
.
map
(({
title
},
index
)
=>
{
return
(
<
th
className=
"ams-table-heading-cell"
key=
{
`index:${index}`
}
>
{
title
}
</
th
>
);
})
}
})
}
</
tbody
>
</
tr
>
);
if
(
isLoading
)
{
header
=
<
ShimmeringHeader
/>;
body
=
<
ShimmeringBody
numLoadingBlocks=
{
numLoadingBlocks
}
/>;
}
return
(
<
table
className=
{
`ams-table ${tableClassName || ''}`
}
>
<
thead
className=
"ams-table-header"
>
{
header
}
</
thead
>
<
tbody
className=
"ams-table-body"
>
{
body
}
</
tbody
>
</
table
>
</
table
>
);
);
};
};
...
...
amundsen_application/static/js/components/common/Table/styles.scss
View file @
b2230452
// Copyright Contributors to the Amundsen project.
// SPDX-License-Identifier: Apache-2.0
@import
'variables'
;
@import
'variables'
;
@import
'typography'
;
@import
'typography'
;
@import
'animations'
;
$table-header-font-size
:
12px
;
$table-header-font-size
:
12px
;
$table-header-line-height
:
16px
;
$table-header-line-height
:
16px
;
$table-header-height
:
33px
;
$table-header-height
:
33px
;
$table-header-border-width
:
2px
;
$table-header-border-width
:
2px
;
$shimmer-block-height
:
16px
;
$shimmer-block-width
:
40%
;
.ams-table
{
.ams-table
{
width
:
100%
;
width
:
100%
;
max-width
:
100%
;
max-width
:
100%
;
...
@@ -24,3 +31,29 @@ $table-header-border-width: 2px;
...
@@ -24,3 +31,29 @@ $table-header-border-width: 2px;
height
:
$table-header-height
;
height
:
$table-header-height
;
text-transform
:
uppercase
;
text-transform
:
uppercase
;
}
}
.ams-empty-message-cell
{
@extend
%text-body-w3
;
color
:
$text-primary
;
text-align
:
center
;
}
.ams-table-heading-loading-cell
{
padding
:
$spacer-1
;
}
.ams-table-body-loading-cell
{
padding
:
0
$spacer-1
;
.shimmer-resource-loader
{
margin-top
:
-1px
;
}
}
.ams-table-shimmer-block
{
@extend
%is-shimmer-animated
;
height
:
$shimmer-block-height
;
width
:
$shimmer-block-width
;
}
amundsen_application/static/js/components/common/Table/table.story.tsx
View file @
b2230452
...
@@ -17,5 +17,11 @@ stories.add('Table', () => (
...
@@ -17,5 +17,11 @@ stories.add('Table', () => (
<
StorySection
title=
"Basic Table"
>
<
StorySection
title=
"Basic Table"
>
<
Table
columns=
{
columns
}
data=
{
data
}
/>
<
Table
columns=
{
columns
}
data=
{
data
}
/>
</
StorySection
>
</
StorySection
>
<
StorySection
title=
"Empty Table"
>
<
Table
columns=
{
columns
}
data=
{
[]
}
/>
</
StorySection
>
<
StorySection
title=
"Loading Table"
>
<
Table
columns=
{
[]
}
data=
{
[]
}
options=
{
{
isLoading
:
true
}
}
/>
</
StorySection
>
</>
</>
));
));
amundsen_application/static/js/components/common/Table/testDataBuilder.ts
View file @
b2230452
...
@@ -50,6 +50,15 @@ function TestDataBuilder(config = {}) {
...
@@ -50,6 +50,15 @@ function TestDataBuilder(config = {}) {
return
new
this
.
Klass
(
attr
);
return
new
this
.
Klass
(
attr
);
};
};
this
.
withEmptyData
=
()
=>
{
const
attr
=
{
data
:
[],
columns
:
[{
title
:
'Name'
,
field
:
'name'
}],
};
return
new
this
.
Klass
(
attr
);
};
this
.
withMoreDataThanColumns
=
()
=>
{
this
.
withMoreDataThanColumns
=
()
=>
{
const
attr
=
{
const
attr
=
{
data
:
[
data
:
[
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment