From 2ed2188bb01fa321177125917102e5f664497d2a Mon Sep 17 00:00:00 2001 From: king <18310653075@163.com> Date: 星期三, 12 八月 2020 16:41:25 +0800 Subject: [PATCH] 2020-08-12 --- src/templates/zshare/modalform/index.jsx | 1 src/tabviews/formtab/index.jsx | 2 src/tabviews/zshare/calendar/index.jsx | 274 +++++++++++++++++++++++++++ src/tabviews/zshare/topSearch/index.jsx | 2 src/templates/zshare/formconfig.jsx | 3 src/tabviews/zshare/settingcomponent/index.jsx | 15 src/tabviews/zshare/actionList/excelInbutton/index.jsx | 10 src/tabviews/zshare/actionList/excelInbutton/excelin/index.jsx | 13 src/tabviews/zshare/mutilform/index.jsx | 5 src/api/index.js | 23 ++ src/templates/modalconfig/source.jsx | 6 src/templates/zshare/codemirror/index.jsx | 18 + src/tabviews/zshare/calendar/index.scss | 187 ++++++++++++++++++ 13 files changed, 542 insertions(+), 17 deletions(-) diff --git a/src/api/index.js b/src/api/index.js index 130f012..e87c871 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -302,6 +302,10 @@ url: `/webapi/dostars${param.func ? '/' + param.func : ''}`, data: param }).then(res => { + if (!res.status) { + reject() + return + } let version = res.app_version || '1.00' appVersion.newVersion = version appVersion.oldVersion = appVersion.oldVersion || version @@ -364,6 +368,25 @@ } /** + * @description 鍒犻櫎鏌愪釜鑿滃崟閰嶇疆淇℃伅 + */ + deleteMenuStorage (menuId) { + return new Promise(resolve => { + if (!mkDataBase) { + resolve() + return + } + mkDataBase.transaction(tx => { + tx.executeSql(`DELETE FROM CONFIGS where menuid='${menuId}'`, [], () => { + resolve() + }, () => { + mkDataBase = null + }) + }) + }) + } + + /** * @description 鑾峰彇鎴栦慨鏀逛簯绔厤缃� */ getCloudConfig (param) { diff --git a/src/tabviews/formtab/index.jsx b/src/tabviews/formtab/index.jsx index f93d948..02bba3c 100644 --- a/src/tabviews/formtab/index.jsx +++ b/src/tabviews/formtab/index.jsx @@ -218,6 +218,8 @@ if (this.props.menuType === 'HS') { // 浜戠鏁版嵁楠岃瘉 param.open_key = Utils.encrypt(param.secretkey, param.timestamp, true) + } else if (window.GLOB.systemType !== 'production') { + isSSO = false } let defer = new Promise(resolve => { diff --git a/src/tabviews/zshare/actionList/excelInbutton/excelin/index.jsx b/src/tabviews/zshare/actionList/excelInbutton/excelin/index.jsx index d3d057d..b4481c0 100644 --- a/src/tabviews/zshare/actionList/excelInbutton/excelin/index.jsx +++ b/src/tabviews/zshare/actionList/excelInbutton/excelin/index.jsx @@ -42,11 +42,16 @@ const workbook = XLSX.read(result, { type: 'binary' }) let errors = null + let sheetName = btn.verify.sheet - if (!workbook.Sheets.hasOwnProperty(btn.verify.sheet)) { + if (Object.keys(workbook.Sheets).length === 1) { + sheetName = Object.keys(workbook.Sheets)[0] + } + + if (!workbook.Sheets.hasOwnProperty(sheetName)) { errors = 'notexit' } else if (range === 1) { - let header = XLSX.utils.sheet_to_json(workbook.Sheets[btn.verify.sheet], {header: columns})[0] + let header = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName], {header: columns})[0] if (!header) { errors = 'empty' @@ -67,11 +72,11 @@ let data = [] if (!errors) { - data = XLSX.utils.sheet_to_json(workbook.Sheets[btn.verify.sheet], {header: columns, range: (range)}) + data = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName], {header: columns, range: (range)}) } // 鏈�缁堣幏鍙栧埌骞朵笖鏍煎紡鍖栧悗鐨� json 鏁版嵁 - this.props.returndata(data, errors) + this.props.returndata(data, errors, sheetName) this.setState({ excelId: '', }, () => { diff --git a/src/tabviews/zshare/actionList/excelInbutton/index.jsx b/src/tabviews/zshare/actionList/excelInbutton/index.jsx index c5d087d..f22403e 100644 --- a/src/tabviews/zshare/actionList/excelInbutton/index.jsx +++ b/src/tabviews/zshare/actionList/excelInbutton/index.jsx @@ -186,26 +186,26 @@ /** * @description Excel 瀵煎叆 */ - getexceldata = (data, errors) => { + getexceldata = (data, errors, sheetName) => { const { btn } = this.props if (errors) { if (errors === 'notexit') { notification.warning({ top: 92, - message: '宸ヤ綔琛ㄣ��' + btn.verify.sheet + '銆嬩笉瀛樺湪锛�', + message: '宸ヤ綔琛ㄣ��' + sheetName + '銆嬩笉瀛樺湪锛�', duration: 5 }) } else if (errors === 'empty') { notification.warning({ top: 92, - message: '宸ヤ綔琛ㄣ��' + btn.verify.sheet + '銆嬩负绌猴紒', + message: '宸ヤ綔琛ㄣ��' + sheetName + '銆嬩负绌猴紒', duration: 5 }) } else if (errors === 'headerError') { notification.warning({ top: 92, - message: '宸ヤ綔琛ㄣ��' + btn.verify.sheet + '銆嬭〃澶磋缃敊璇紝璇锋鏌ヨ〃澶翠腑鐨勫悕绉板強椤哄簭锛屼笌鎸夐挳Excel鍒椾俊鎭槸鍚︿竴鑷达紒', + message: '宸ヤ綔琛ㄣ��' + sheetName + '銆嬭〃澶磋缃敊璇紝璇锋鏌ヨ〃澶翠腑鐨勫悕绉板強椤哄簭锛屼笌鎸夐挳Excel鍒椾俊鎭槸鍚︿竴鑷达紒', duration: 5 }) } @@ -217,7 +217,7 @@ if (!data || data.length === 0) { notification.warning({ top: 92, - message: '鏈幏鍙栧埌宸ヤ綔琛ㄣ��' + btn.verify.sheet + '銆嬫暟鎹紒', + message: '鏈幏鍙栧埌宸ヤ綔琛ㄣ��' + sheetName + '銆嬫暟鎹紒', duration: 5 }) this.updateStatus('over') diff --git a/src/tabviews/zshare/calendar/index.jsx b/src/tabviews/zshare/calendar/index.jsx new file mode 100644 index 0000000..abb13ee --- /dev/null +++ b/src/tabviews/zshare/calendar/index.jsx @@ -0,0 +1,274 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { is, fromJS } from 'immutable' +import { Select, Radio, Row, Col, Popover, Badge } from 'antd' +import moment from 'moment' + +// import Utils from '@/utils/utils.js' +import './index.scss' + +const { Option } = Select + +class Calendar extends Component { + static propTpyes = { + data: PropTypes.any, // 浜嬩欢鏁版嵁 + levels: PropTypes.any + } + + state = { + level: 'day', + levels: null, + yearlist: null, + selectYear: moment().format('YYYY'), + selectMonth: moment().format('MM'), + datelist: null, + monthlist: null, + } + + UNSAFE_componentWillMount() { + const { levels } = this.props + + let yearlist = [] + let _selectYear = +this.state.selectYear + yearlist.push(`${_selectYear}`) + + for (let i = 1; i <= 50; i++) { + yearlist.unshift(`${_selectYear - i}`) + yearlist.push(`${_selectYear + i}`) + } + + let datelist = this.getDateList(this.state.selectYear) + let _levels = null + + if (!levels) { + _levels = ['day', 'month', 'year'] + } else { + _levels = levels + } + + let level = _levels[0] + let monthlist = null + level = 'month' + + if (_levels.includes('month')) { + monthlist = datelist.filter(item => item.month === moment().format('MM'))[0] + } + + this.setState({ + yearlist, + datelist, + monthlist, + level, + levels: _levels + }) + } + + UNSAFE_componentWillReceiveProps(nextProps) { + if (!is(fromJS(this.props.data), fromJS(nextProps.data))) { + + } + } + + shouldComponentUpdate (nextProps, nextState) { + return !is(fromJS(this.state), fromJS(nextState)) + } + + getDateList = (selectYear) => { + let datelist = [] + let months = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'] + let monthName = { + '01': '涓�鏈�', '02': '浜屾湀', '03': '涓夋湀', '04': '鍥涙湀', '05': '浜旀湀', '06': '鍏湀', + '07': '涓冩湀', '08': '鍏湀', '09': '涔濇湀', '10': '鍗佹湀', '11': '鍗佷竴鏈�', '12': '鍗佷簩鏈�' + } + + months.forEach(month => { + let _weeklist = [{week: 1, sublist: []}] + let _week = moment(`${selectYear}${month}01`, 'YYYYMMDD').weekday() + let end = +moment(`${selectYear}${month}`, 'YYYYMM').endOf('month').format('DD') + + for (let i = 0; i < _week; i++) { + _weeklist[0].sublist.push(null) + } + + for (let i = 1; i <= end; i++) { + if (_weeklist[_weeklist.length - 1].sublist.length < 7) { + _weeklist[_weeklist.length - 1].sublist.push({day: i < 10 ? `0${i}` : `${i}`, label: i}) + } else { + let _week = {week: _weeklist.length + 1, sublist: [{day: i < 10 ? `0${i}` : `${i}`, label: i}]} + _weeklist.push(_week) + } + } + + let re = 7 - _weeklist[_weeklist.length - 1].sublist.length + for (let i = 0; i < re; i++) { + _weeklist[_weeklist.length - 1].sublist.push(null) + } + + datelist.push({ + month: month, + label: monthName[month], + sublist: _weeklist + }) + }) + + return datelist + } + + levelChange = (e) => { + this.setState({ level: e.target.value }) + } + + yearChange = (value) => { + const { levels, selectMonth } = this.state + let datelist = this.getDateList(value) + let monthlist = null + + if (levels.includes('month')) { + monthlist = datelist.filter(item => item.month === selectMonth)[0] + } + + this.setState({ selectYear: value, datelist, monthlist }) + } + + monthChange = (value) => { + const { datelist } = this.state + + this.setState({ + selectMonth: value, + monthlist: datelist.filter(item => item.month === value)[0] + }) + } + + triggerDay = (item) => { + + } + + render() { + const { level, selectMonth, selectYear, yearlist, levels, datelist, monthlist } = this.state + const _levelName = {day: '鏃�', month: '鏈�', year: '骞�'} + const listData = [ + { type: 'orange', content: 'This is error event 2.' }, + { type: 'cyan', content: 'This is error event 3.' }, + { type: 'green', content: 'This is error event 4.' }, + ] + + return ( + <div className="mk-calendar"> + <div className="mk-calendar-control"> + <Select value={selectYear} onChange={this.yearChange}> + {yearlist.map(item => (<Option key={item} value={item}>{item}骞�</Option>))} + </Select> + {level === 'month' ? <Select value={selectMonth} onChange={this.monthChange}> + <Option value="01">1鏈�</Option> + <Option value="02">2鏈�</Option> + <Option value="03">3鏈�</Option> + <Option value="04">4鏈�</Option> + <Option value="05">5鏈�</Option> + <Option value="06">6鏈�</Option> + <Option value="07">7鏈�</Option> + <Option value="08">8鏈�</Option> + <Option value="09">9鏈�</Option> + <Option value="10">10鏈�</Option> + <Option value="11">11鏈�</Option> + <Option value="12">12鏈�</Option> + </Select> : null} + {levels.length > 1 ? <Radio.Group value={level} onChange={this.levelChange}> + {levels.map(item => (<Radio.Button key={item} value={item}>{_levelName[item]}</Radio.Button>))} + </Radio.Group> : null} + </div> + <div className="mk-calendar-content"> + {level === 'day' ? <Row className="day-calendar" gutter={16}> + {datelist.map(item => ( + <Col span={4} key={item.month}> + <table> + <thead> + <tr> + <th colSpan="7">{item.label}</th> + </tr> + <tr> + <th>涓�</th><th>浜�</th><th>涓�</th><th>鍥�</th><th>浜�</th><th>鍏�</th><th>鏃�</th> + </tr> + </thead> + <tbody> + {item.sublist.map(cell => ( + <tr key={cell.week}> + {cell.sublist.map((d, i) => ( + <td key={i}> + {d ? <div className={'day-wrap ' + d.class} onClick={() => this.triggerDay(d)}> + {d.label ? <Popover mouseEnterDelay={0.3} overlayClassName="calendar-day-pop" content={ + <div> + {listData.map((data, index) => ( + <div key={index} className="message"> + <Badge color={data.type} text={data.content} /> + </div> + ))} + </div> + } trigger="hover"> + {d.label} + </Popover> : d.label} + </div> : null } + </td> + ))} + </tr> + ))} + </tbody> + </table> + </Col> + ))} + </Row> : null} + {level === 'month' && monthlist ? <div className="month-calendar"> + <table> + <thead> + <tr> + <th>涓�</th><th>浜�</th><th>涓�</th><th>鍥�</th><th>浜�</th><th>鍏�</th><th>鏃�</th> + </tr> + </thead> + <tbody> + {monthlist.sublist.map(cell => ( + <tr key={cell.week}> + {cell.sublist.map((d, i) => ( + <td key={i}> + {d ? <div className="month-wrap" onClick={() => this.triggerDay(d)}> + <div className="header"> + {d.label} + </div> + <ul className="content"> + {[1,3,7,18,22].includes(d.label) && listData.map((data, index) => ( + <li key={index} className="message" title={data.content}> + <Badge color={data.type} text={data.content} /> + </li> + ))} + </ul> + </div> : null } + </td> + ))} + </tr> + ))} + </tbody> + </table> + </div>: null} + {level === 'year' && monthlist ? <Row className="year-calendar"> + {datelist.map(item => ( + <Col span={8} key={item.month}> + <div className="year-wrap"> + <div className="header"> + {item.label} + </div> + <ul className="content"> + {['01', '05', '10'].includes(item.month) && listData.map((data, index) => ( + <li key={index} className="message" title={data.content}> + <Badge color={data.type} text={data.content} /> + </li> + ))} + </ul> + </div> + </Col> + ))} + </Row>: null} + </div> + </div> + ) + } +} + +export default Calendar \ No newline at end of file diff --git a/src/tabviews/zshare/calendar/index.scss b/src/tabviews/zshare/calendar/index.scss new file mode 100644 index 0000000..b51378a --- /dev/null +++ b/src/tabviews/zshare/calendar/index.scss @@ -0,0 +1,187 @@ +.mk-calendar { + width: 100%; + padding: 10px; + + .mk-calendar-control { + text-align: right; + .ant-select { + width: 90px; + margin-right: 15px; + } + } + .mk-calendar-content { + margin-top: 10px; + .day-calendar .ant-col { + min-height: 235px; + table { + width: 100%; + thead { + text-align: center; + color: #1890ff; + tr { + height: 30px; + } + tr:first-child { + th { + font-weight: 600; + font-size: 16px; + } + } + } + tbody { + text-align: center; + tr { + height: 28px; + td { + .day-wrap { + cursor: pointer; + transition: background 0.1s; + span { + display: inline-block; + width: 100%; + height: 100%; + } + } + .day-wrap:hover { + background: #bae7ff; + } + } + } + } + } + } + .month-calendar { + table { + width: 100%; + thead { + text-align: center; + color: #1890ff; + font-size: 16px; + tr { + height: 35px; + } + } + tbody { + tr { + td { + position: relative; + width: 14.2%; + .month-wrap { + cursor: pointer; + height: 120px; + width: 100%; + transition: background 0.1s; + .header { + text-align: center; + font-size: 16px; + } + .content { + padding: 0 10px 10px; + height: 90px; + overflow-y: auto; + position: absolute; + left: 0; + right: 0; + .message { + width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + } + .content::-webkit-scrollbar { + width: 5px; + } + .content::-webkit-scrollbar-thumb { + border-radius: 5px; + box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.09); + background: rgba(0, 0, 0, 0.09); + } + .content::-webkit-scrollbar-track { + box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05); + border-radius: 3px; + border: 1px solid rgba(0, 0, 0, 0.07); + background: rgba(0, 0, 0, 0); + } + } + .month-wrap:hover { + background: #e6f7ff; + } + } + } + } + } + } + .year-calendar { + .year-wrap { + cursor: pointer; + transition: background 0.1s; + .header { + text-align: center; + font-size: 16px; + color: #1890ff; + } + .content { + padding: 5px 15px 10px; + height: 110px; + overflow-y: auto; + .message { + width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + } + .content::-webkit-scrollbar { + width: 5px; + } + .content::-webkit-scrollbar-thumb { + border-radius: 5px; + box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.09); + background: rgba(0, 0, 0, 0.09); + } + .content::-webkit-scrollbar-track { + box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05); + border-radius: 3px; + border: 1px solid rgba(0, 0, 0, 0.07); + background: rgba(0, 0, 0, 0); + } + } + .year-wrap:hover { + background: #e6f7ff; + } + } + } +} +.calendar-day-pop { + .message { + .ant-badge-status-text { + display: inline-block; + min-width: 100px; + max-width: 200px; + white-space: nowrap; + vertical-align: middle; + overflow: hidden; + text-overflow: ellipsis; + } + } + .ant-popover-inner-content { + min-height: 100px; + max-height: 200px; + overflow-y: auto; + } + .ant-popover-inner-content::-webkit-scrollbar { + width: 5px; + } + .ant-popover-inner-content::-webkit-scrollbar-thumb { + border-radius: 5px; + box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.09); + background: rgba(0, 0, 0, 0.09); + } + .ant-popover-inner-content::-webkit-scrollbar-track { + box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05); + border-radius: 3px; + border: 1px solid rgba(0, 0, 0, 0.07); + background: rgba(0, 0, 0, 0); + } +} diff --git a/src/tabviews/zshare/mutilform/index.jsx b/src/tabviews/zshare/mutilform/index.jsx index 00a1445..3926e06 100644 --- a/src/tabviews/zshare/mutilform/index.jsx +++ b/src/tabviews/zshare/mutilform/index.jsx @@ -284,6 +284,7 @@ obj_name: 'data', arr_field: item.arr_field } + let isSSO = item.database === 'sso' if (this.props.BID) { param.BID = this.props.BID @@ -294,11 +295,13 @@ if (this.props.menuType === 'HS') { // 浜戠鏁版嵁楠岃瘉 param.open_key = Utils.encrypt(param.secretkey, param.timestamp, true) + } else if (window.GLOB.systemType !== 'production') { + isSSO = false } deffers.push( new Promise(resolve => { - Api.getSystemCacheConfig(param, item.database === 'sso').then(res => { + Api.getSystemCacheConfig(param, isSSO).then(res => { res.$search = item resolve(res) }) diff --git a/src/tabviews/zshare/settingcomponent/index.jsx b/src/tabviews/zshare/settingcomponent/index.jsx index 8acead5..14f627a 100644 --- a/src/tabviews/zshare/settingcomponent/index.jsx +++ b/src/tabviews/zshare/settingcomponent/index.jsx @@ -120,12 +120,15 @@ }) return } - this.setState({ - visible: false, - confirmLoading: false - }, () => { - window.GLOB.CacheMap = new Map() - this.props.reloadview() + + Api.deleteMenuStorage(this.props.MenuID).then(() => { + this.setState({ + visible: false, + confirmLoading: false + }, () => { + window.GLOB.CacheMap = new Map() + this.props.reloadview() + }) }) }) } diff --git a/src/tabviews/zshare/topSearch/index.jsx b/src/tabviews/zshare/topSearch/index.jsx index 08caa46..3889b5e 100644 --- a/src/tabviews/zshare/topSearch/index.jsx +++ b/src/tabviews/zshare/topSearch/index.jsx @@ -139,6 +139,8 @@ if (this.props.menuType === 'HS') { // 浜戠鏁版嵁楠岃瘉 param.open_key = Utils.encrypt(param.secretkey, param.timestamp, true) + } else if (window.GLOB.systemType !== 'production') { + isSSO = false } let defer = new Promise(resolve => { diff --git a/src/templates/modalconfig/source.jsx b/src/templates/modalconfig/source.jsx index 4a52cbf..7cf801f 100644 --- a/src/templates/modalconfig/source.jsx +++ b/src/templates/modalconfig/source.jsx @@ -134,6 +134,12 @@ }, { type: 'form', + label: CommonDict['model.form.color'], + subType: 'color', + url: '' + }, + { + type: 'form', label: CommonDict['header.form.funcvar'], subType: 'funcvar', url: '' diff --git a/src/templates/zshare/codemirror/index.jsx b/src/templates/zshare/codemirror/index.jsx index 28cd658..4351acb 100644 --- a/src/templates/zshare/codemirror/index.jsx +++ b/src/templates/zshare/codemirror/index.jsx @@ -28,7 +28,7 @@ value: '', // 瀹炴椂鍐呭 options: null, // mode : text/javascript銆乼ext/x-mysql ; theme : cobalt - 榛戝簳 fullScreen: false, - style: null, + style: {fontSize: '18px', lineHeight: '32px'}, display: true } @@ -89,6 +89,10 @@ _style = {fontSize: '18px', lineHeight: '32px'} } else if (size === 20) { _style = {fontSize: '20px', lineHeight: '34px'} + } else if (size === 22) { + _style = {fontSize: '22px', lineHeight: '36px'} + } else if (size === 24) { + _style = {fontSize: '24px', lineHeight: '40px'} } // 鍒囨崲瀛椾綋澶у皬锛屽埛鏂扮紪杈戝櫒绐楀彛锛岃В鍐宠皟鏁村悗鐨勯�夋嫨鍖哄煙閿欎贡闂 @@ -125,6 +129,18 @@ > <span style={{padding: '0 10px 0px 5px'}}>20px</span> </Menu.Item> + <Menu.Item + style={style && style.fontSize === '22px' ? {backgroundColor: '#bae7ff'} : ''} + onClick={() => {this.changeSize(22)}} + > + <span style={{padding: '0 10px 0px 5px'}}>22px</span> + </Menu.Item> + <Menu.Item + style={style && style.fontSize === '24px' ? {backgroundColor: '#bae7ff'} : ''} + onClick={() => {this.changeSize(24)}} + > + <span style={{padding: '0 10px 0px 5px'}}>24px</span> + </Menu.Item> </Menu> ) diff --git a/src/templates/zshare/formconfig.jsx b/src/templates/zshare/formconfig.jsx index fc2a31e..e620eb9 100644 --- a/src/templates/zshare/formconfig.jsx +++ b/src/templates/zshare/formconfig.jsx @@ -2125,6 +2125,9 @@ value: 'textarea', text: Formdict['model.form.textarea'] }, { + value: 'color', + text: Formdict['model.form.color'] + }, { value: 'funcvar', text: Formdict['header.form.funcvar'] }, diff --git a/src/templates/zshare/modalform/index.jsx b/src/templates/zshare/modalform/index.jsx index d33515f..e39e374 100644 --- a/src/templates/zshare/modalform/index.jsx +++ b/src/templates/zshare/modalform/index.jsx @@ -19,6 +19,7 @@ datemonth: ['label', 'field', 'initval', 'type', 'readonly', 'required', 'hidden', 'readin', 'blacklist'], datetime: ['label', 'field', 'initval', 'type', 'readonly', 'required', 'hidden', 'readin', 'blacklist'], textarea: ['label', 'field', 'initval', 'type', 'readonly', 'required', 'hidden', 'readin', 'blacklist', 'fieldlength', 'maxRows', 'encryption', 'interception'], + color: ['label', 'field', 'type', 'blacklist', 'required', 'hidden', 'readin'], funcvar: ['label', 'field', 'type', 'blacklist', 'hidden'], linkMain: ['label', 'field', 'type', 'readonly', 'required', 'hidden', 'fieldlength', 'blacklist'] } -- Gitblit v1.8.0