feat(network): use luna data grid
This commit is contained in:
@@ -13,7 +13,6 @@
|
|||||||
.title {
|
.title {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
font-size: $font-size-l;
|
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
.icon-copy {
|
.icon-copy {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -31,6 +30,7 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
user-select: text;
|
user-select: text;
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
|
font-size: $font-size-s;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
table {
|
table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import Tool from '../DevTools/Tool'
|
import Tool from '../DevTools/Tool'
|
||||||
import isEmpty from 'licia/isEmpty'
|
|
||||||
import $ from 'licia/$'
|
import $ from 'licia/$'
|
||||||
import ms from 'licia/ms'
|
import ms from 'licia/ms'
|
||||||
import each from 'licia/each'
|
import each from 'licia/each'
|
||||||
import last from 'licia/last'
|
import last from 'licia/last'
|
||||||
import Detail from './Detail'
|
import Detail from './Detail'
|
||||||
import map from 'licia/map'
|
import throttle from 'licia/throttle'
|
||||||
import escape from 'licia/escape'
|
|
||||||
import { getFileName, classPrefix as c } from '../lib/util'
|
import { getFileName, classPrefix as c } from '../lib/util'
|
||||||
import evalCss from '../lib/evalCss'
|
import evalCss from '../lib/evalCss'
|
||||||
import chobitsu from '../lib/chobitsu'
|
import chobitsu from '../lib/chobitsu'
|
||||||
|
import LunaDataGrid from 'luna-data-grid'
|
||||||
|
import ResizeSensor from 'licia/ResizeSensor'
|
||||||
|
|
||||||
export default class Network extends Tool {
|
export default class Network extends Tool {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -26,16 +26,53 @@ export default class Network extends Tool {
|
|||||||
this._container = container
|
this._container = container
|
||||||
this._initTpl()
|
this._initTpl()
|
||||||
this._detail = new Detail(this._$detail)
|
this._detail = new Detail(this._$detail)
|
||||||
|
this._requestDataGrid = new LunaDataGrid(this._$requests.get(0), {
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
id: 'name',
|
||||||
|
title: 'Name',
|
||||||
|
sortable: true,
|
||||||
|
weight: 30,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'method',
|
||||||
|
title: 'Method',
|
||||||
|
sortable: true,
|
||||||
|
weight: 14,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'status',
|
||||||
|
title: 'Status',
|
||||||
|
sortable: true,
|
||||||
|
weight: 14,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'type',
|
||||||
|
title: 'Type',
|
||||||
|
sortable: true,
|
||||||
|
weight: 14,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'size',
|
||||||
|
title: 'Size',
|
||||||
|
sortable: true,
|
||||||
|
weight: 14,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'time',
|
||||||
|
title: 'Time',
|
||||||
|
sortable: true,
|
||||||
|
weight: 14,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
this._updateDataGridHeight()
|
||||||
|
this._resizeSensor = new ResizeSensor($el.get(0))
|
||||||
this._bindEvent()
|
this._bindEvent()
|
||||||
}
|
}
|
||||||
show() {
|
|
||||||
super.show()
|
|
||||||
|
|
||||||
this._render()
|
|
||||||
}
|
|
||||||
clear() {
|
clear() {
|
||||||
this._requests = {}
|
this._requests = {}
|
||||||
this._render()
|
this._requestDataGrid.clear()
|
||||||
}
|
}
|
||||||
requests() {
|
requests() {
|
||||||
const ret = []
|
const ret = []
|
||||||
@@ -44,8 +81,13 @@ export default class Network extends Tool {
|
|||||||
})
|
})
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
_updateDataGridHeight() {
|
||||||
|
const height = this._$el.offset().height - 41
|
||||||
|
this._requestDataGrid.setOption('minHeight', height)
|
||||||
|
this._requestDataGrid.setOption('maxHeight', height)
|
||||||
|
}
|
||||||
_reqWillBeSent = (params) => {
|
_reqWillBeSent = (params) => {
|
||||||
this._requests[params.requestId] = {
|
const request = {
|
||||||
name: getFileName(params.request.url),
|
name: getFileName(params.request.url),
|
||||||
url: params.request.url,
|
url: params.request.url,
|
||||||
status: 'pending',
|
status: 'pending',
|
||||||
@@ -61,60 +103,83 @@ export default class Network extends Tool {
|
|||||||
reqHeaders: params.request.headers || {},
|
reqHeaders: params.request.headers || {},
|
||||||
resHeaders: {},
|
resHeaders: {},
|
||||||
}
|
}
|
||||||
|
let node
|
||||||
|
request.render = () => {
|
||||||
|
const data = {
|
||||||
|
name: request.name,
|
||||||
|
method: request.method,
|
||||||
|
status: request.status,
|
||||||
|
type: request.subType,
|
||||||
|
size: request.size,
|
||||||
|
time: request.displayTime,
|
||||||
|
}
|
||||||
|
if (node) {
|
||||||
|
node.data = data
|
||||||
|
node.render()
|
||||||
|
} else {
|
||||||
|
node = this._requestDataGrid.append(data, { selectable: true })
|
||||||
|
$(node.container).data('id', params.requestId)
|
||||||
|
}
|
||||||
|
if (request.hasErr) {
|
||||||
|
$(node.container).addClass(c('request-error'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request.render()
|
||||||
|
this._requests[params.requestId] = request
|
||||||
}
|
}
|
||||||
_resReceivedExtraInfo = (params) => {
|
_resReceivedExtraInfo = (params) => {
|
||||||
const target = this._requests[params.requestId]
|
const request = this._requests[params.requestId]
|
||||||
if (!target) {
|
if (!request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
target.resHeaders = params.headers
|
request.resHeaders = params.headers
|
||||||
|
|
||||||
this._updateType(target)
|
this._updateType(request)
|
||||||
this._render()
|
request.render()
|
||||||
}
|
}
|
||||||
_updateType(target) {
|
_updateType(request) {
|
||||||
const contentType = target.resHeaders['content-type'] || ''
|
const contentType = request.resHeaders['content-type'] || ''
|
||||||
const { type, subType } = getType(contentType)
|
const { type, subType } = getType(contentType)
|
||||||
target.type = type
|
request.type = type
|
||||||
target.subType = subType
|
request.subType = subType
|
||||||
}
|
}
|
||||||
_resReceived = (params) => {
|
_resReceived = (params) => {
|
||||||
const target = this._requests[params.requestId]
|
const request = this._requests[params.requestId]
|
||||||
if (!target) {
|
if (!request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const { response } = params
|
const { response } = params
|
||||||
const { status, headers } = response
|
const { status, headers } = response
|
||||||
target.status = status
|
request.status = status
|
||||||
if (status < 200 || status >= 300) {
|
if (status < 200 || status >= 300) {
|
||||||
target.hasErr = true
|
request.hasErr = true
|
||||||
}
|
}
|
||||||
if (headers) {
|
if (headers) {
|
||||||
target.resHeaders = headers
|
request.resHeaders = headers
|
||||||
this._updateType(target)
|
this._updateType(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
this._render()
|
request.render()
|
||||||
}
|
}
|
||||||
_loadingFinished = (params) => {
|
_loadingFinished = (params) => {
|
||||||
const target = this._requests[params.requestId]
|
const request = this._requests[params.requestId]
|
||||||
if (!target) {
|
if (!request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const time = params.timestamp * 1000
|
const time = params.timestamp * 1000
|
||||||
target.time = time - target.startTime
|
request.time = time - request.startTime
|
||||||
target.displayTime = ms(target.time)
|
request.displayTime = ms(request.time)
|
||||||
|
|
||||||
target.size = params.encodedDataLength
|
request.size = params.encodedDataLength
|
||||||
target.done = true
|
request.done = true
|
||||||
target.resTxt = chobitsu.domain('Network').getResponseBody({
|
request.resTxt = chobitsu.domain('Network').getResponseBody({
|
||||||
requestId: params.requestId,
|
requestId: params.requestId,
|
||||||
}).body
|
}).body
|
||||||
|
|
||||||
this._render()
|
request.render()
|
||||||
}
|
}
|
||||||
_bindEvent() {
|
_bindEvent() {
|
||||||
const $el = this._$el
|
const $el = this._$el
|
||||||
@@ -122,16 +187,16 @@ export default class Network extends Tool {
|
|||||||
|
|
||||||
const self = this
|
const self = this
|
||||||
|
|
||||||
$el
|
$el.on('click', c('.clear-request'), () => this.clear())
|
||||||
.on('click', c('.request'), function () {
|
|
||||||
const id = $(this).data('id')
|
|
||||||
const data = self._requests[id]
|
|
||||||
|
|
||||||
if (!data.done) return
|
this._requestDataGrid.on('select', (node) => {
|
||||||
|
const id = $(node.container).data('id')
|
||||||
self._detail.show(data)
|
const request = self._requests[id]
|
||||||
|
if (!request.done) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self._detail.show(request)
|
||||||
})
|
})
|
||||||
.on('click', c('.clear-request'), () => this.clear())
|
|
||||||
|
|
||||||
this._detail.on('showSources', function (type, data) {
|
this._detail.on('showSources', function (type, data) {
|
||||||
const sources = container.get('sources')
|
const sources = container.get('sources')
|
||||||
@@ -142,6 +207,10 @@ export default class Network extends Tool {
|
|||||||
container.showTool('sources')
|
container.showTool('sources')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this._resizeSensor.addListener(
|
||||||
|
throttle(() => this._updateDataGridHeight(), 15)
|
||||||
|
)
|
||||||
|
|
||||||
chobitsu.domain('Network').enable()
|
chobitsu.domain('Network').enable()
|
||||||
|
|
||||||
const network = chobitsu.domain('Network')
|
const network = chobitsu.domain('Network')
|
||||||
@@ -153,6 +222,7 @@ export default class Network extends Tool {
|
|||||||
destroy() {
|
destroy() {
|
||||||
super.destroy()
|
super.destroy()
|
||||||
|
|
||||||
|
this._resizeSensor.destroy()
|
||||||
evalCss.remove(this._style)
|
evalCss.remove(this._style)
|
||||||
|
|
||||||
const network = chobitsu.domain('Network')
|
const network = chobitsu.domain('Network')
|
||||||
@@ -170,45 +240,12 @@ export default class Network extends Tool {
|
|||||||
<span class="icon-clear"></span>
|
<span class="icon-clear"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ul class="requests"></ul>
|
<div class="requests"></div>
|
||||||
<div class="detail"></div>`)
|
<div class="detail"></div>`)
|
||||||
)
|
)
|
||||||
this._$detail = $el.find(c('.detail'))
|
this._$detail = $el.find(c('.detail'))
|
||||||
this._$requests = $el.find(c('.requests'))
|
this._$requests = $el.find(c('.requests'))
|
||||||
}
|
}
|
||||||
_render() {
|
|
||||||
if (!this.active) return
|
|
||||||
|
|
||||||
const renderData = {}
|
|
||||||
|
|
||||||
if (!isEmpty(this._requests)) renderData.requests = this._requests
|
|
||||||
|
|
||||||
let html = `<li><span class="${c('name')}">Empty</span></li>`
|
|
||||||
if (renderData.requests) {
|
|
||||||
html = map(
|
|
||||||
renderData.requests,
|
|
||||||
({ hasErr, name, status, method, subType, size, displayTime }, idx) => {
|
|
||||||
return `<li class="${c('request')} ${
|
|
||||||
hasErr ? c('error') : ''
|
|
||||||
}" data-id="${idx}">
|
|
||||||
<span class="${c('name')}">${escape(name)}</span>
|
|
||||||
<span class="${c('status')}">${status}</span>
|
|
||||||
<span class="${c('method')}">${method}</span>
|
|
||||||
<span class="${c('type')}">${subType}</span>
|
|
||||||
<span class="${c('size')}">${size}</span>
|
|
||||||
<span class="${c('time')}">${displayTime}</span>
|
|
||||||
</li>`
|
|
||||||
}
|
|
||||||
).join('')
|
|
||||||
}
|
|
||||||
|
|
||||||
this._renderHtml(html)
|
|
||||||
}
|
|
||||||
_renderHtml(html) {
|
|
||||||
if (html === this._lastHtml) return
|
|
||||||
this._lastHtml = html
|
|
||||||
this._$requests.html(html)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getType(contentType) {
|
function getType(contentType) {
|
||||||
|
|||||||
@@ -2,65 +2,21 @@
|
|||||||
@import '../style/mixin';
|
@import '../style/mixin';
|
||||||
|
|
||||||
#network {
|
#network {
|
||||||
padding-top: 36px;
|
padding-top: 40px;
|
||||||
.title {
|
.title {
|
||||||
@include absolute(100%, 36px);
|
@include absolute(100%, 40px);
|
||||||
@include right-btn();
|
@include right-btn();
|
||||||
background: var(--darker-background);
|
background: var(--darker-background);
|
||||||
padding: $padding;
|
padding: $padding;
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
height: 36px;
|
height: 40px;
|
||||||
border-bottom: 1px solid var(--border);
|
|
||||||
}
|
}
|
||||||
.requests {
|
.request-error {
|
||||||
@include overflow-auto(y);
|
|
||||||
height: 100%;
|
|
||||||
border-bottom: 1px solid var(--border);
|
|
||||||
margin-bottom: 10px;
|
|
||||||
li {
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
cursor: pointer;
|
|
||||||
border-bottom: 1px solid var(--border);
|
|
||||||
height: 41px;
|
|
||||||
color: var(--foreground);
|
|
||||||
white-space: nowrap;
|
|
||||||
&.error {
|
|
||||||
span {
|
|
||||||
color: var(--console-error-foreground);
|
color: var(--console-error-foreground);
|
||||||
}
|
}
|
||||||
}
|
.luna-data-grid-data-container:focus {
|
||||||
span {
|
.request-error.luna-data-grid-selected {
|
||||||
display: block;
|
background: var(--console-error-background);
|
||||||
line-height: 40px;
|
|
||||||
height: 40px;
|
|
||||||
padding: 0 5px;
|
|
||||||
font-size: $font-size-s;
|
|
||||||
vertical-align: top;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.name {
|
|
||||||
flex: 1;
|
|
||||||
padding-left: $padding;
|
|
||||||
}
|
|
||||||
.status {
|
|
||||||
width: 40px;
|
|
||||||
}
|
|
||||||
.method,
|
|
||||||
.type {
|
|
||||||
width: 50px;
|
|
||||||
}
|
|
||||||
.size {
|
|
||||||
width: 70px;
|
|
||||||
}
|
|
||||||
.time {
|
|
||||||
width: 60px;
|
|
||||||
padding-right: $padding;
|
|
||||||
}
|
|
||||||
&:nth-child(even) {
|
|
||||||
background: var(--contrast);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.detail {
|
.detail {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
padding: $padding;
|
padding: $padding;
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
background: var(--darker-background);
|
background: var(--darker-background);
|
||||||
transition: background $anim-duration;
|
transition: background-color $anim-duration;
|
||||||
.btn {
|
.btn {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
float: right;
|
float: right;
|
||||||
@@ -31,6 +31,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.description {
|
.description {
|
||||||
|
font-size: $font-size-s;
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
padding: $padding;
|
padding: $padding;
|
||||||
transition: background $anim-duration;
|
transition: background $anim-duration;
|
||||||
|
|||||||
@@ -190,8 +190,6 @@ export function safeStorage(type, memReplacement) {
|
|||||||
export function getFileName(url) {
|
export function getFileName(url) {
|
||||||
let ret = last(url.split('/'))
|
let ret = last(url.split('/'))
|
||||||
|
|
||||||
if (ret.indexOf('?') > -1) ret = trim(ret.split('?')[0])
|
|
||||||
|
|
||||||
if (ret === '') {
|
if (ret === '') {
|
||||||
url = new Url(url)
|
url = new Url(url)
|
||||||
ret = url.hostname
|
ret = url.hostname
|
||||||
|
|||||||
@@ -181,6 +181,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.luna-data-grid-data-container {
|
.luna-data-grid-data-container {
|
||||||
|
&:focus {
|
||||||
|
.luna-data-grid-node.luna-data-grid-selected {
|
||||||
|
background: var(--accent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.luna-data-grid-node.luna-data-grid-selected {
|
||||||
|
background: var(--highlight);
|
||||||
|
}
|
||||||
tr:nth-child(even) {
|
tr:nth-child(even) {
|
||||||
background: var(--contrast);
|
background: var(--contrast);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
|
font-size: $font-size;
|
||||||
[class^='icon-'],
|
[class^='icon-'],
|
||||||
[class*=' icon-'] {
|
[class*=' icon-'] {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ describe('network', function () {
|
|||||||
it('xhr', function (done) {
|
it('xhr', function (done) {
|
||||||
$('.eruda-clear-xhr').click()
|
$('.eruda-clear-xhr').click()
|
||||||
util.ajax.get(window.location.toString(), function () {
|
util.ajax.get(window.location.toString(), function () {
|
||||||
expect($('.eruda-requests li')).toHaveLength(1)
|
expect($('.eruda-requests .luna-data-grid-node')).toHaveLength(1)
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user