<commit_before>/**
 * @file GroupList component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';

import List from '../List';
import Theme from '../Theme';
import Tip from '../Tip';

import Util from '../_vendors/Util';
import Event from '../_vendors/Event';

export default class GroupList extends Component {

    static Mode = List.Mode;
    static SEPARATOR = List.SEPARATOR;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.state = {
            value: this.initValue(props)
        };

        this.initValue = ::this.initValue;
        this.wheelHandler = ::this.wheelHandler;

    }

    initValue(props) {

        if (!props) {
            return;
        }

        const {value, selectMode} = props;

        if (!selectMode) {
            return;
        }

        if (value) {
            return value;
        }

        switch (selectMode) {
            case GroupList.Mode.MULTI_SELECT:
                return [];
            case GroupList.Mode.SINGLE_SELECT:
                return null;
            default:
                return value;
        }

    }

    wheelHandler(e) {
        const {shouldPreventContainerScroll, onWheel} = this.props;
        shouldPreventContainerScroll && Event.preventContainerScroll(e);
        onWheel && onWheel(e);
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.value !== this.state.value) {
            this.setState({
                value: this.initValue(nextProps)
            });
        }
    }

    render() {

        const {

                children, className, style, data, disabled,

                ...restProps

            } = this.props,
            {value} = this.state,

            listClassName = (className ? ' ' + className : '');

        return (

                {
                    data && data.length > 0 ?
                        data.map((item, index) => {

                            if (item === GroupList.SEPARATOR) {
                                return

;
                            }

                            return (

{item.name}

                                    <List {...restProps}
                                          data={item.children}/>

                            );

                        })
                        :
                        null
                }

                {children}

        );

    }
};

GroupList.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * The theme.
     */
    theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * Children passed into the ListItem.
     */
    data: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.shape({

        // group name
        name: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        children: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.shape({

            /**
             * The CSS class name of the list button.
             */
            className: PropTypes.string,

            /**
             * Override the styles of the list button.
             */
            style: PropTypes.object,

            /**
             * The theme of the list button.
             */
            theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

            /**
             * The text value of the list button.Type can be string or number.
             */
            value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

            /**
             * The list item's display text. Type can be string, number or bool.
             */
            text: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

            /**
             * The desc value of the list button. Type can be string or number.
             */
            desc: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

            /**
             * If true,the list item will be disabled.
             */
            disabled: PropTypes.bool,

            /**
             * If true,the button will be have loading effect.
             */
            isLoading: PropTypes.bool,

            /**
             * If true,the element's ripple effect will be disabled.
             */
            disableTouchRipple: PropTypes.bool,

            /**
             * Use this property to display an icon. It will display on the left.
             */
            iconCls: PropTypes.string,

            /**
             * Use this property to display an icon. It will display on the right.
             */
            rightIconCls: PropTypes.string,

            /**
             * The message of tip.
             */
            tip: PropTypes.string,

            /**
             * The position of tip.
             */
            tipPosition: PropTypes.oneOf(Util.enumerateValue(Tip.Position)),

            /**
             * If true,the item will have center displayed ripple effect.
             */
            rippleDisplayCenter: PropTypes.bool,

            /**
             * You can create a complicated renderer callback instead of value and desc prop.
             */
            itemRenderer: PropTypes.func,

            /**
             * Callback function fired when a list item touch-tapped.
             */
            onTouchTap: PropTypes.func

        }), PropTypes.string, PropTypes.number]))

    }), PropTypes.symbol])).isRequired,

    /**
     * The id field name in data. (default: "id")
     */
    idField: PropTypes.string,

    /**
     * The value field name in data. (default: "value")
     */
    valueField: PropTypes.string,

    /**
     * The display field name in data. (default: "text")
     */
    displayField: PropTypes.string,

    /**
     * The description field name in data. (default: "desc")
     */
    descriptionField: PropTypes.string,

    /**
     * If true, the list will be disabled.
     */
    disabled: PropTypes.bool,

    /**
     * If true, the list will be at loading status.
     */
    isLoading: PropTypes.bool,

    /**
     * The mode of listItem.Can be normal,checkbox.
     */
    selectMode: PropTypes.oneOf(Util.enumerateValue(GroupList.Mode)),

    shouldPreventContainerScroll: PropTypes.bool,

    /**
     * You can create a complicated renderer callback instead of value and desc prop.
     */
    renderer: PropTypes.func,

    /**
     * Callback function fired when the list-item select.
     */
    onItemTouchTap: PropTypes.func,

    /**
     * Callback function fired when the list changed.
     */
    onChange: PropTypes.func,

    /**
     * Callback function fired when wrapper wheeled.
     */
    onWheel: PropTypes.func

};

GroupList.defaultProps = {

    className: null,
    style: null,
    theme: Theme.DEFAULT,

    data: [],

    idField: 'id',
    valueField: 'value',
    displayField: 'text',
    descriptionField: 'desc',
    disabled: false,
    selectMode: GroupList.Mode.NORMAL,
    shouldPreventContainerScroll: true

};<commit_msg>update select mode<commit_after>/**
 * @file GroupList component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';

import List from '../List';
import Theme from '../Theme';
import Tip from '../Tip';

import Util from '../_vendors/Util';
import Event from '../_vendors/Event';
import SelectMode from '../_statics/SelectMode';

export default class GroupList extends Component {

    static SelectMode = SelectMode;
    static SEPARATOR = List.SEPARATOR;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.state = {
            value: this.initValue(props)
        };

        this.initValue = ::this.initValue;
        this.wheelHandler = ::this.wheelHandler;

    }

    initValue(props) {

        if (!props) {
            return;
        }

        const {value, selectMode} = props;

        if (!selectMode) {
            return;
        }

        if (value) {
            return value;
        }

        switch (selectMode) {
            case GroupList.SelectMode.MULTI_SELECT:
                return [];
            case GroupList.SelectMode.SINGLE_SELECT:
                return null;
            default:
                return value;
        }

    }

    wheelHandler(e) {
        const {shouldPreventContainerScroll, onWheel} = this.props;
        shouldPreventContainerScroll && Event.preventContainerScroll(e);
        onWheel && onWheel(e);
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.value !== this.state.value) {
            this.setState({
                value: this.initValue(nextProps)
            });
        }
    }

    render() {

        const {

                children, className, style, data, disabled,

                ...restProps

            } = this.props,
            {value} = this.state,

            listClassName = (className ? ' ' + className : '');

        return (

                {
                    data && data.length > 0 ?
                        data.map((item, index) => {

                            if (item === GroupList.SEPARATOR) {
                                return

;
                            }

                            return (

{item.name}

                                    <List {...restProps}
                                          data={item.children}/>

                            );

                        })
                        :
                        null
                }

                {children}

        );

    }
};

GroupList.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * The theme.
     */
    theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * Children passed into the ListItem.
     */
    data: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.shape({

        // group name
        name: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        children: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.shape({

            /**
             * The CSS class name of the list button.
             */
            className: PropTypes.string,

            /**
             * Override the styles of the list button.
             */
            style: PropTypes.object,

            /**
             * The theme of the list button.
             */
            theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

            /**
             * The text value of the list button.Type can be string or number.
             */
            value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

            /**
             * The list item's display text. Type can be string, number or bool.
             */
            text: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

            /**
             * The desc value of the list button. Type can be string or number.
             */
            desc: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

            /**
             * If true,the list item will be disabled.
             */
            disabled: PropTypes.bool,

            /**
             * If true,the button will be have loading effect.
             */
            isLoading: PropTypes.bool,

            /**
             * If true,the element's ripple effect will be disabled.
             */
            disableTouchRipple: PropTypes.bool,

            /**
             * Use this property to display an icon. It will display on the left.
             */
            iconCls: PropTypes.string,

            /**
             * Use this property to display an icon. It will display on the right.
             */
            rightIconCls: PropTypes.string,

            /**
             * The message of tip.
             */
            tip: PropTypes.string,

            /**
             * The position of tip.
             */
            tipPosition: PropTypes.oneOf(Util.enumerateValue(Tip.Position)),

            /**
             * If true,the item will have center displayed ripple effect.
             */
            rippleDisplayCenter: PropTypes.bool,

            /**
             * You can create a complicated renderer callback instead of value and desc prop.
             */
            itemRenderer: PropTypes.func,

            /**
             * Callback function fired when a list item touch-tapped.
             */
            onTouchTap: PropTypes.func

        }), PropTypes.string, PropTypes.number]))

    }), PropTypes.symbol])).isRequired,

    /**
     * The id field name in data. (default: "id")
     */
    idField: PropTypes.string,

    /**
     * The value field name in data. (default: "value")
     */
    valueField: PropTypes.string,

    /**
     * The display field name in data. (default: "text")
     */
    displayField: PropTypes.string,

    /**
     * The description field name in data. (default: "desc")
     */
    descriptionField: PropTypes.string,

    /**
     * If true, the list will be disabled.
     */
    disabled: PropTypes.bool,

    /**
     * If true, the list will be at loading status.
     */
    isLoading: PropTypes.bool,

    /**
     * The mode of listItem.Can be normal,checkbox.
     */
    selectMode: PropTypes.oneOf(Util.enumerateValue(SelectMode)),

    shouldPreventContainerScroll: PropTypes.bool,

    /**
     * You can create a complicated renderer callback instead of value and desc prop.
     */
    renderer: PropTypes.func,

    /**
     * Callback function fired when the list-item select.
     */
    onItemTouchTap: PropTypes.func,

    /**
     * Callback function fired when the list changed.
     */
    onChange: PropTypes.func,

    /**
     * Callback function fired when wrapper wheeled.
     */
    onWheel: PropTypes.func

};

GroupList.defaultProps = {

    className: null,
    style: null,
    theme: Theme.DEFAULT,

    data: [],

    idField: 'id',
    valueField: 'value',
    displayField: 'text',
    descriptionField: 'desc',
    disabled: false,
    selectMode: SelectMode.NORMAL,
    shouldPreventContainerScroll: true

};<|endoftext|>


<commit_before>(function(root, definition) {
    if (typeof define === 'function' && define.amd) {
        define(['equation-tokenizer/equation-tokenizer'], definition);
    } else if (typeof exports === 'object') {
        var tokenize = require('../equation-tokenizer/equation-tokenizer');
        module.exports = definition(tokenize);
    } else {
        root.infix2postfix = definition(root.tokenize_equation);
    }
})(this, function(tokenize) {
    function precedence(a, b) {
        if ('*/%'.indexOf(a) > -1 && '+-'.indexOf(b) > -1) {
            return -1;
        } else if ('+-'.indexOf(a) > -1 && '*/%'.indexOf(b) > -1) {
            return 1;
        }
        return 0;
    }

    function convert(equation, keep_tokens) {
        var tokens = equation instanceof Array ? equation : tokenize(equation, true);
        var stack = [];
        var postfix = [];

        tokens.forEach(function(token) {
            if (token.type === 'operand') {
                postfix.push(token);
            } else if (token.type === 'operator') {
                if (!stack.length) {
                    stack.push(token);
                } else {
                    var top = stack.pop();
                    var _token = token;
                    while (top && top.value !== '(') {
                        if (precedence(token.value, top.value) < 0) {
                            stack.push(top, token);
                            _token = null;
                            break;
                        }
                        postfix.push(top);
                        top = stack.pop();
                    }
                    if (_token) {
                        stack.push(_token);
                    }
                }
            } else if (token.type === 'group') {
                if (token.value === '(') {
                    stack.push(token);
                } else if (token.value === ')') {
                    var top = stack.pop();
                    while (top && top.value !== '(') {
                        postfix.push(top);
                        top = stack.pop();
                    }
                }
            }
        });

        while (stack.length) {
            postfix.push(stack.pop());
        }

        if (!keep_tokens) {
            var values = [];
            postfix.forEach(function(token) {
                values.push(token.value);
            });
            return values.join(' ');
        }
        return postfix;
    }

    return convert;
});<commit_msg>modified how precedences are checked<commit_after>(function(root, definition) {
    if (typeof define === 'function' && define.amd) {
        define(['equation-tokenizer/equation-tokenizer'], definition);
    } else if (typeof exports === 'object') {
        var tokenize = require('../equation-tokenizer/equation-tokenizer');
        module.exports = definition(tokenize);
    } else {
        root.infix2postfix = definition(root.tokenize_equation);
    }
})(this, function(tokenize) {
    var precedences = { '^': 3, '*': 2, '/': 2, '%': 2, '+': 1, '-': 1 };

    function precedence(a, b) {
        if (precedences[a] > precedences[b]) {
            return -1;
        } else if (precedences[b] > precedences[a]) {
            return 1;
        }
        return 0;
    }

    function convert(equation, keep_tokens) {
        var tokens = equation instanceof Array ? equation : tokenize(equation, true);
        var stack = [];
        var postfix = [];

        tokens.forEach(function(token) {
            if (token.type === 'operand') {
                postfix.push(token);
            } else if (token.type === 'operator') {
                if (!stack.length) {
                    stack.push(token);
                } else {
                    var top = stack.pop();
                    var _token = token;
                    while (top && top.value !== '(') {
                        if (precedence(token.value, top.value) < 0) {
                            stack.push(top, token);
                            _token = null;
                            break;
                        }
                        postfix.push(top);
                        top = stack.pop();
                    }
                    if (_token) {
                        stack.push(_token);
                    }
                }
            } else if (token.type === 'group') {
                if (token.value === '(') {
                    stack.push(token);
                } else if (token.value === ')') {
                    var top = stack.pop();
                    while (top && top.value !== '(') {
                        postfix.push(top);
                        top = stack.pop();
                    }
                }
            }
        });

        while (stack.length) {
            postfix.push(stack.pop());
        }

        if (!keep_tokens) {
            var values = [];
            postfix.forEach(function(token) {
                values.push(token.value);
            });
            return values.join(' ');
        }
        return postfix;
    }

    return convert;
});<|endoftext|>


<commit_before>'use strict'; // eslint-disable-line

const async = require('async');
const AWS = require('aws-sdk');
const http = require('http');

const Logger = require('werelogs').Logger;
const errors = require('arsenal').errors;
const MongoClient = require('arsenal').storage
    .metadata.mongoclient.MongoClientInterface;

const BackbeatConsumer = require('../../lib/BackbeatConsumer');
const QueueEntry = require('../../lib/models/QueueEntry');
const DeleteOpQueueEntry = require('../../lib/models/DeleteOpQueueEntry');
const BucketQueueEntry = require('../../lib/models/BucketQueueEntry');
const BucketMdQueueEntry = require('../../lib/models/BucketMdQueueEntry');
const ObjectQueueEntry = require('../../lib/models/ObjectQueueEntry');
const { getAccountCredentials } =
    require('../../lib/credentials/AccountCredentials');

// TODO - ADD PREFIX BASED ON SOURCE
// april 6, 2018

/**
 * @class MongoQueueProcessor
 *
 * @classdesc Background task that processes entries from the
 * ingestion for kafka queue and pushes entries to mongo
 */
class MongoQueueProcessor {

    /**
     * @constructor
     * @param {Object} kafkaConfig - kafka configuration object
     * @param {String} kafkaConfig.hosts - list of kafka brokers
     *   as "host:port[,host:port...]"
     * @param {Object} s3Config - s3 config
     * @param {String} s3Config.host - host ip
     * @param {String} s3Config.port - port
     * @param {Object} mongoProcessorConfig - mongo processor configuration
     *   object
     * @param {String} mongoProcessorConfig.topic - topic name
     * @param {String} mongoProcessorConfig.groupId - kafka
     *   consumer group ID
     * @param {number} [mongoProcessorConfig.retry.timeoutS] -
     *  retry timeout in secs.
     * @param {number} [mongoProcessorConfig.retry.maxRetries] -
     *  max retries before giving up
     * @param {Object} [mongoProcessorConfig.retry.backoff] -
     *  backoff params
     * @param {number} [mongoProcessorConfig.retry.backoff.min] -
     *  min. backoff in ms.
     * @param {number} [mongoProcessorConfig.retry.backoff.max] -
     *  max. backoff in ms.
     * @param {number} [mongoProcessorConfig.retry.backoff.jitter] -
     *  randomness
     * @param {number} [mongoProcessorConfig.retry.backoff.factor] -
     *  backoff factor
     * @param {Object} mongoClientConfig - config for connecting to mongo
     * @param {Object} serviceAuth - ingestion service auth
     * @param {String} site - site name
     */
    constructor(kafkaConfig, s3Config, mongoProcessorConfig, mongoClientConfig,
                serviceAuth, site) {
        this.kafkaConfig = kafkaConfig;
        this.mongoProcessorConfig = mongoProcessorConfig;
        this.mongoClientConfig = mongoClientConfig;
        this._serviceAuth = serviceAuth;
        this.site = site;

        this._s3Endpoint = `http://${s3Config.host}:${s3Config.port}`;
        this._s3Client = null;
        this._consumer = null;
        this.logger =
            new Logger(`Backbeat:Ingestion:MongoProcessor:${this.site}`);
        this.mongoClientConfig.logger = this.logger;
        this._mongoClient = new MongoClient(this.mongoClientConfig);
    }

    /**
     * Return an S3 client instance using the given account credentials.
     * @param {Object} accountCreds - Object containing account credentials
     * @param {String} accountCreds.accessKeyId - The account access key
     * @param {String} accountCreds.secretAccessKey - The account secret key
     * @return {AWS.S3} The S3 client instance to make requests with
     */
    _getS3Client(accountCreds) {
        return new AWS.S3({
            endpoint: this._s3Endpoint,
            credentials: {
                accessKeyId: accountCreds.accessKeyId,
                secretAccessKey: accountCreds.secretAccessKey,
            },
            sslEnabled: false,
            s3ForcePathStyle: true,
            signatureVersion: 'v4',
            httpOptions: {
                agent: new http.Agent({ keepAlive: true }),
                timeout: 0,
            },
            maxRetries: 0,
        });
    }

    /**
     * Start kafka consumer
     *
     * @return {undefined}
     */
    start() {
        this.logger.info('starting mongo queue processor');
        const credentials = getAccountCredentials(this._serviceAuth,
                                                  this.logger);
        this._s3Client = this._getS3Client(credentials);
        this._mongoClient.setup(err => {
            if (err) {
                this.logger.error('could not connect to MongoDB', { err });
                process.exit(1);
            }
            let consumerReady = false;
            this._consumer = new BackbeatConsumer({
                topic: this.mongoProcessorConfig.topic,
                groupId: `${this.mongoProcessorConfig.groupId}-${this.site}`,
                kafka: { hosts: this.kafkaConfig.hosts },
                queueProcessor: this.processKafkaEntry.bind(this),
            });
            this._consumer.on('error', () => {
                if (!consumerReady) {
                    this.logger.fatal('error starting mongo queue processor');
                    process.exit(1);
                }
            });
            this._consumer.on('ready', () => {
                consumerReady = true;
                this._consumer.subscribe();
                this.logger.info('mongo queue processor is ready');
            });
        });
    }

    /**
     * Stop kafka consumer and commit current offset
     *
     * @param {function} done - callback
     * @return {undefined}
     */
    stop(done) {
        if (!this._consumer) {
            return setImmediate(done);
        }
        return this._consumer.close(done);
    }

    /**
     * Update ingested entry metadata fields: owner-id, owner-display-name
     * @param {ObjectQueueEntry} entry - object queue entry object
     * @param {object} ownerInfo - owner details
     * @return {undefined}
     */
    _updateOwnerMD(entry, ownerInfo) {
        // zenko bucket owner information is being set on ingested md
        entry.setOwnerDisplayName(ownerInfo.ownerDisplayName);
        entry.setOwnerId(ownerInfo.ownerId);
    }

    /**
     * Update ingested entry metadata fields: dataStoreName
     * @param {ObjectQueueEntry} entry - object queue entry object
     * @param {string} location - owner details
     * @return {undefined}
     */
    _updateObjectDataStoreName(entry, location) {
        entry.setDataStoreName(location);
    }

    /**
     * Update ingested entry metadata location field. Each location change
     * includes: key, dataStoreName, dataStoreType, dataStoreVersionId
     * @param {ObjectQueueEntry} entry - object queue entry object
     * @param {string} location - zenko storage location name
     * @return {undefined}
     */
    _updateLocations(entry, location) {
        const locations = entry.getLocation();
        const editLocations = locations.map(l => {
            const newValues = {
                key: entry.getObjectKey(),
                dataStoreName: location,
                dataStoreType: 'aws_s3',
            };
            if (entry.getVersionId()) {
                newValues.dataStoreVersionId = entry.getEncodedVersionId();
            }
            return Object.assign({}, l, newValues);
        });
        entry.setLocation(editLocations);
    }

    /**
     * Process a delete object entry
     * @param {DeleteOpQueueEntry} sourceEntry - delete object entry
     * @param {function} done - callback(error)
     * @return {undefined}
     */
    _processDeleteOpQueueEntry(sourceEntry, done) {
        const bucket = sourceEntry.getBucket();
        const key = sourceEntry.getObjectVersionedKey();

        // Always call deleteObject with version params undefined so
        // that mongoClient will use deleteObjectNoVer which just deletes
        // the object without further manipulation/actions.
        // S3 takes care of the versioning logic so consuming the queue
        // is sufficient to replay the version logic in the consumer.
        return this._mongoClient.deleteObject(bucket, key, undefined,
            this.logger, err => {
                if (err) {
                    this.logger.error('error deleting object metadata ' +
                    'from mongo', { bucket, key, error: err.message });
                    return done(err);
                }
                this.logger.info('object metadata deleted from mongo',
                { bucket, key });
                return done();
            });
    }

    /**
     * Process an object entry
     * @param {ObjectQueueEntry} sourceEntry - object metadata entry
     * @param {string} location - zenko storage location name
     * @param {object} ownerInfo - owner details
     * @param {function} done - callback(error)
     * @return {undefined}
     */
    _processObjectQueueEntry(sourceEntry, location, ownerInfo, done) {
        const bucket = sourceEntry.getBucket();
        // always use versioned key so putting full version state to mongo
        const key = sourceEntry.getObjectVersionedKey();

        // update necessary metadata fields before saving to Zenko MongoDB
        this._updateOwnerMD(sourceEntry, ownerInfo);
        this._updateObjectDataStoreName(sourceEntry, location);
        this._updateLocations(sourceEntry, location);

        const objVal = sourceEntry.getValue();
        // Always call putObject with version params undefined so
        // that mongoClient will use putObjectNoVer which just puts
        // the object without further manipulation/actions.
        // S3 takes care of the versioning logic so consuming the queue
        // is sufficient to replay the version logic in the consumer.
        return this._mongoClient.putObject(bucket, key, objVal, undefined,
            this.logger, err => {
                if (err) {
                    this.logger.error('error putting object metadata ' +
                    'to mongo', { error: err });
                    return done(err);
                }
                this.logger.info('object metadata put to mongo',
                { key });
                return done();
            });
    }

    /**
     * Put kafka queue entry into mongo
     *
     * @param {object} kafkaEntry - entry generated by ingestion populator
     * @param {string} kafkaEntry.key - kafka entry key
     * @param {string} kafkaEntry.value - kafka entry value
     * @param {function} done - callback function
     * @return {undefined}
     */
    processKafkaEntry(kafkaEntry, done) {
        const sourceEntry = QueueEntry.createFromKafkaEntry(kafkaEntry);
        if (sourceEntry.error) {
            this.logger.error('error processing source entry',
                              { error: sourceEntry.error });
            return process.nextTick(() => done(errors.InternalError));
        }
        // if entry is for another site, simply skip/ignore
        if (this.site !== kafkaEntry.bucket) {
            return process.nextTick(done);
        }
        if (sourceEntry instanceof BucketMdQueueEntry) {
            this.logger.warn('skipping bucket md queue entry', {
                method: 'MongoQueueProcessor.processKafkaEntry',
                entry: sourceEntry.getLogInfo(),
            });
            return process.nextTick(done);
        } else if (sourceEntry instanceof BucketQueueEntry) {
            this.logger.warn('skipping bucket queue entry', {
                method: 'MongoQueueProcessor.processKafkaEntry',
                entry: sourceEntry.getLogInfo(),
            });
            return process.nextTick(done);
        }

        const bucketName = sourceEntry.getBucket();
        return async.series([
            next => this._mongoClient.getBucketAttributes(bucketName,
                this.logger, (err, data) => {
                    if (err) {
                        this.logger.error('error getting bucket owner ' +
                        'details', {
                            method: 'MongoQueueProcessor.processKafkaEntry',
                            entry: sourceEntry.getLogInfo(),
                        });
                        return done(err);
                    }
                    const ownerInfo = {
                        ownerId: data._owner,
                        ownerDisplayName: data._ownerDisplayName,
                    };
                    return next(null, ownerInfo);
                }),
            next => this._s3Client.getBucketLocation({ Bucket: bucketName },
                (err, data) => {
                    if (err) {
                        this.logger.error('error getting bucket location ' +
                        'constraint', {
                            method: 'MongoQueueProcessor.processKafkaEntry',
                            error: err,
                        });
                        return done(err);
                    }
                    const location = data.LocationConstraint;
                    return next(null, location);
                }),
        ], (err, results) => {
            if (err) {
                return done(err);
            }
            const ownerInfo = results[0];
            const location = results[1];
            // if entry is for another site, simply skip/ignore
            if (this.site !== location) {
                return process.nextTick(done);
            }

            if (sourceEntry instanceof DeleteOpQueueEntry) {
                return this._processDeleteOpQueueEntry(sourceEntry, done);
            }
            if (sourceEntry instanceof ObjectQueueEntry) {
                return this._processObjectQueueEntry(sourceEntry, location,
                    ownerInfo, done);
            }
            this.logger.warn('skipping unknown source entry',
                            { entry: sourceEntry.getLogInfo() });
            return process.nextTick(done);
        });
    }

    isReady() {
        return this._consumer && this._consumer.isReady();
    }
}

module.exports = MongoQueueProcessor;
<commit_msg>bf: ZENKO-1428 remove mongoProcessor bucket filter<commit_after>'use strict'; // eslint-disable-line

const async = require('async');
const AWS = require('aws-sdk');
const http = require('http');

const Logger = require('werelogs').Logger;
const errors = require('arsenal').errors;
const MongoClient = require('arsenal').storage
    .metadata.mongoclient.MongoClientInterface;

const BackbeatConsumer = require('../../lib/BackbeatConsumer');
const QueueEntry = require('../../lib/models/QueueEntry');
const DeleteOpQueueEntry = require('../../lib/models/DeleteOpQueueEntry');
const BucketQueueEntry = require('../../lib/models/BucketQueueEntry');
const BucketMdQueueEntry = require('../../lib/models/BucketMdQueueEntry');
const ObjectQueueEntry = require('../../lib/models/ObjectQueueEntry');
const { getAccountCredentials } =
    require('../../lib/credentials/AccountCredentials');

// TODO - ADD PREFIX BASED ON SOURCE
// april 6, 2018

/**
 * @class MongoQueueProcessor
 *
 * @classdesc Background task that processes entries from the
 * ingestion for kafka queue and pushes entries to mongo
 */
class MongoQueueProcessor {

    /**
     * @constructor
     * @param {Object} kafkaConfig - kafka configuration object
     * @param {String} kafkaConfig.hosts - list of kafka brokers
     *   as "host:port[,host:port...]"
     * @param {Object} s3Config - s3 config
     * @param {String} s3Config.host - host ip
     * @param {String} s3Config.port - port
     * @param {Object} mongoProcessorConfig - mongo processor configuration
     *   object
     * @param {String} mongoProcessorConfig.topic - topic name
     * @param {String} mongoProcessorConfig.groupId - kafka
     *   consumer group ID
     * @param {number} [mongoProcessorConfig.retry.timeoutS] -
     *  retry timeout in secs.
     * @param {number} [mongoProcessorConfig.retry.maxRetries] -
     *  max retries before giving up
     * @param {Object} [mongoProcessorConfig.retry.backoff] -
     *  backoff params
     * @param {number} [mongoProcessorConfig.retry.backoff.min] -
     *  min. backoff in ms.
     * @param {number} [mongoProcessorConfig.retry.backoff.max] -
     *  max. backoff in ms.
     * @param {number} [mongoProcessorConfig.retry.backoff.jitter] -
     *  randomness
     * @param {number} [mongoProcessorConfig.retry.backoff.factor] -
     *  backoff factor
     * @param {Object} mongoClientConfig - config for connecting to mongo
     * @param {Object} serviceAuth - ingestion service auth
     * @param {String} site - site name
     */
    constructor(kafkaConfig, s3Config, mongoProcessorConfig, mongoClientConfig,
                serviceAuth, site) {
        this.kafkaConfig = kafkaConfig;
        this.mongoProcessorConfig = mongoProcessorConfig;
        this.mongoClientConfig = mongoClientConfig;
        this._serviceAuth = serviceAuth;
        this.site = site;

        this._s3Endpoint = `http://${s3Config.host}:${s3Config.port}`;
        this._s3Client = null;
        this._consumer = null;
        this.logger =
            new Logger(`Backbeat:Ingestion:MongoProcessor:${this.site}`);
        this.mongoClientConfig.logger = this.logger;
        this._mongoClient = new MongoClient(this.mongoClientConfig);
    }

    /**
     * Return an S3 client instance using the given account credentials.
     * @param {Object} accountCreds - Object containing account credentials
     * @param {String} accountCreds.accessKeyId - The account access key
     * @param {String} accountCreds.secretAccessKey - The account secret key
     * @return {AWS.S3} The S3 client instance to make requests with
     */
    _getS3Client(accountCreds) {
        return new AWS.S3({
            endpoint: this._s3Endpoint,
            credentials: {
                accessKeyId: accountCreds.accessKeyId,
                secretAccessKey: accountCreds.secretAccessKey,
            },
            sslEnabled: false,
            s3ForcePathStyle: true,
            signatureVersion: 'v4',
            httpOptions: {
                agent: new http.Agent({ keepAlive: true }),
                timeout: 0,
            },
            maxRetries: 0,
        });
    }

    /**
     * Start kafka consumer
     *
     * @return {undefined}
     */
    start() {
        this.logger.info('starting mongo queue processor');
        const credentials = getAccountCredentials(this._serviceAuth,
                                                  this.logger);
        this._s3Client = this._getS3Client(credentials);
        this._mongoClient.setup(err => {
            if (err) {
                this.logger.error('could not connect to MongoDB', { err });
                process.exit(1);
            }
            let consumerReady = false;
            this._consumer = new BackbeatConsumer({
                topic: this.mongoProcessorConfig.topic,
                groupId: `${this.mongoProcessorConfig.groupId}-${this.site}`,
                kafka: { hosts: this.kafkaConfig.hosts },
                queueProcessor: this.processKafkaEntry.bind(this),
            });
            this._consumer.on('error', () => {
                if (!consumerReady) {
                    this.logger.fatal('error starting mongo queue processor');
                    process.exit(1);
                }
            });
            this._consumer.on('ready', () => {
                consumerReady = true;
                this._consumer.subscribe();
                this.logger.info('mongo queue processor is ready');
            });
        });
    }

    /**
     * Stop kafka consumer and commit current offset
     *
     * @param {function} done - callback
     * @return {undefined}
     */
    stop(done) {
        if (!this._consumer) {
            return setImmediate(done);
        }
        return this._consumer.close(done);
    }

    /**
     * Update ingested entry metadata fields: owner-id, owner-display-name
     * @param {ObjectQueueEntry} entry - object queue entry object
     * @param {object} ownerInfo - owner details
     * @return {undefined}
     */
    _updateOwnerMD(entry, ownerInfo) {
        // zenko bucket owner information is being set on ingested md
        entry.setOwnerDisplayName(ownerInfo.ownerDisplayName);
        entry.setOwnerId(ownerInfo.ownerId);
    }

    /**
     * Update ingested entry metadata fields: dataStoreName
     * @param {ObjectQueueEntry} entry - object queue entry object
     * @param {string} location - owner details
     * @return {undefined}
     */
    _updateObjectDataStoreName(entry, location) {
        entry.setDataStoreName(location);
    }

    /**
     * Update ingested entry metadata location field. Each location change
     * includes: key, dataStoreName, dataStoreType, dataStoreVersionId
     * @param {ObjectQueueEntry} entry - object queue entry object
     * @param {string} location - zenko storage location name
     * @return {undefined}
     */
    _updateLocations(entry, location) {
        const locations = entry.getLocation();
        const editLocations = locations.map(l => {
            const newValues = {
                key: entry.getObjectKey(),
                dataStoreName: location,
                dataStoreType: 'aws_s3',
            };
            if (entry.getVersionId()) {
                newValues.dataStoreVersionId = entry.getEncodedVersionId();
            }
            return Object.assign({}, l, newValues);
        });
        entry.setLocation(editLocations);
    }

    /**
     * Process a delete object entry
     * @param {DeleteOpQueueEntry} sourceEntry - delete object entry
     * @param {function} done - callback(error)
     * @return {undefined}
     */
    _processDeleteOpQueueEntry(sourceEntry, done) {
        const bucket = sourceEntry.getBucket();
        const key = sourceEntry.getObjectVersionedKey();

        // Always call deleteObject with version params undefined so
        // that mongoClient will use deleteObjectNoVer which just deletes
        // the object without further manipulation/actions.
        // S3 takes care of the versioning logic so consuming the queue
        // is sufficient to replay the version logic in the consumer.
        return this._mongoClient.deleteObject(bucket, key, undefined,
            this.logger, err => {
                if (err) {
                    this.logger.error('error deleting object metadata ' +
                    'from mongo', { bucket, key, error: err.message });
                    return done(err);
                }
                this.logger.info('object metadata deleted from mongo',
                { bucket, key });
                return done();
            });
    }

    /**
     * Process an object entry
     * @param {ObjectQueueEntry} sourceEntry - object metadata entry
     * @param {string} location - zenko storage location name
     * @param {object} ownerInfo - owner details
     * @param {function} done - callback(error)
     * @return {undefined}
     */
    _processObjectQueueEntry(sourceEntry, location, ownerInfo, done) {
        const bucket = sourceEntry.getBucket();
        // always use versioned key so putting full version state to mongo
        const key = sourceEntry.getObjectVersionedKey();

        // update necessary metadata fields before saving to Zenko MongoDB
        this._updateOwnerMD(sourceEntry, ownerInfo);
        this._updateObjectDataStoreName(sourceEntry, location);
        this._updateLocations(sourceEntry, location);

        const objVal = sourceEntry.getValue();
        // Always call putObject with version params undefined so
        // that mongoClient will use putObjectNoVer which just puts
        // the object without further manipulation/actions.
        // S3 takes care of the versioning logic so consuming the queue
        // is sufficient to replay the version logic in the consumer.
        return this._mongoClient.putObject(bucket, key, objVal, undefined,
            this.logger, err => {
                if (err) {
                    this.logger.error('error putting object metadata ' +
                    'to mongo', { error: err });
                    return done(err);
                }
                this.logger.info('object metadata put to mongo',
                { key });
                return done();
            });
    }

    /**
     * Put kafka queue entry into mongo
     *
     * @param {object} kafkaEntry - entry generated by ingestion populator
     * @param {string} kafkaEntry.key - kafka entry key
     * @param {string} kafkaEntry.value - kafka entry value
     * @param {function} done - callback function
     * @return {undefined}
     */
    processKafkaEntry(kafkaEntry, done) {
        const sourceEntry = QueueEntry.createFromKafkaEntry(kafkaEntry);
        if (sourceEntry.error) {
            this.logger.error('error processing source entry',
                              { error: sourceEntry.error });
            return process.nextTick(() => done(errors.InternalError));
        }
        if (sourceEntry instanceof BucketMdQueueEntry) {
            this.logger.warn('skipping bucket md queue entry', {
                method: 'MongoQueueProcessor.processKafkaEntry',
                entry: sourceEntry.getLogInfo(),
            });
            return process.nextTick(done);
        } else if (sourceEntry instanceof BucketQueueEntry) {
            this.logger.warn('skipping bucket queue entry', {
                method: 'MongoQueueProcessor.processKafkaEntry',
                entry: sourceEntry.getLogInfo(),
            });
            return process.nextTick(done);
        }

        const bucketName = sourceEntry.getBucket();
        return async.series([
            next => this._mongoClient.getBucketAttributes(bucketName,
                this.logger, (err, data) => {
                    if (err) {
                        this.logger.error('error getting bucket owner ' +
                        'details', {
                            method: 'MongoQueueProcessor.processKafkaEntry',
                            entry: sourceEntry.getLogInfo(),
                        });
                        return done(err);
                    }
                    const ownerInfo = {
                        ownerId: data._owner,
                        ownerDisplayName: data._ownerDisplayName,
                    };
                    return next(null, ownerInfo);
                }),
            next => this._s3Client.getBucketLocation({ Bucket: bucketName },
                (err, data) => {
                    if (err) {
                        this.logger.error('error getting bucket location ' +
                        'constraint', {
                            method: 'MongoQueueProcessor.processKafkaEntry',
                            error: err,
                        });
                        return done(err);
                    }
                    const location = data.LocationConstraint;
                    return next(null, location);
                }),
        ], (err, results) => {
            if (err) {
                return done(err);
            }
            const ownerInfo = results[0];
            const location = results[1];
            // if entry is for another site, simply skip/ignore
            if (this.site !== location) {
                return process.nextTick(done);
            }

            if (sourceEntry instanceof DeleteOpQueueEntry) {
                return this._processDeleteOpQueueEntry(sourceEntry, done);
            }
            if (sourceEntry instanceof ObjectQueueEntry) {
                return this._processObjectQueueEntry(sourceEntry, location,
                    ownerInfo, done);
            }
            this.logger.warn('skipping unknown source entry',
                            { entry: sourceEntry.getLogInfo() });
            return process.nextTick(done);
        });
    }

    isReady() {
        return this._consumer && this._consumer.isReady();
    }
}

module.exports = MongoQueueProcessor;
<|endoftext|>


<commit_before>import React, {PropTypes, Component} from 'react'
import '../tap_events'
import {Table, TableBody, TableHeader,
    TableHeaderColumn, TableRow, TableRowColumn} from 'material-ui/Table';
import IconMenu from 'material-ui/IconMenu';
import MenuItem from 'material-ui/MenuItem';
import Dialog from 'material-ui/Dialog';
import RaisedButton from 'material-ui/RaisedButton';
import NavigationMoreVert from 'material-ui/svg-icons/navigation/more-vert';
import ArrowDown from 'material-ui/svg-icons/hardware/keyboard-arrow-down'
import ArrowUp from 'material-ui/svg-icons/hardware/keyboard-arrow-up'
import UncheckedBox from 'material-ui/svg-icons/toggle/check-box-outline-blank'
import CheckedBox from 'material-ui/svg-icons/toggle/check-box'
import Warning from 'material-ui/svg-icons/alert/warning'
import Check from 'material-ui/svg-icons/navigation/check'
import IconButton from 'material-ui/IconButton';
import CloudDownload from 'material-ui/svg-icons/file/cloud-download'
import styles from '../../styles/StatusDownload.css'
import { Link, IndexLink } from 'react-router';
import Checkbox from 'material-ui/Checkbox'
import LinearProgress from 'material-ui/LinearProgress';
import CustomScrollbar from '../CustomScrollbar';
import TaskError from './TaskError'
import ProviderError from './ProviderError'

export class ProviderRow extends React.Component {
    constructor(props) {
        super(props)
        this.handleDownload = this.handleDownload.bind(this);
        this.handleToggle = this.handleToggle.bind(this);
        this.onChangeCheck = this.onChangeCheck.bind(this);
        this.state = {
            providerTasks: [],
            openTable: false,
            selectedRows: { },
            fileSize: null,
            providerDesc: '',
            providerDialogOpen: false,
            cloneDialogOpen: false,

        }
    }

    componentWillMount(){
        //set state on the provider
        let t = {};
        let uid = this.props.provider.uid;
        t[uid] = false;
        this.setState({selectedRows:t})
    }

    componentWillReceiveProps(nextProps) {
        let fileSize = 0.000;
        nextProps.provider.tasks.forEach((task) => {
            if (task.result != null ){
                if (task.display != false && task.result.size) {
                    let textReplace = task.result.size.replace(' MB', '');
                    let number = textReplace;
                    fileSize = Number(fileSize) + Number(number);
                    this.setState({fileSize: fileSize.toFixed(3)});
                }
            }
        })

        if(nextProps.selectedProviders != this.state.selectedRows) {
            this.setState({selectedRows : nextProps.selectedProviders})
        }
    }

    handleToggle() {
        this.setState({openTable: !this.state.openTable});
    }

    handleDownload()  {
        let downloadUids = [];
        let selectedTasks = {...this.state.selectedRows};
        Object.keys(selectedTasks).forEach((keyName, keyIndex) => {
            if (selectedTasks[keyName] == true) {
                downloadUids.push(keyName);
            }
        });

        let tasks = this.props.provider.tasks;
        let downloadUrls = [];
        downloadUids.forEach((uid) => {
            let a = tasks.find(x => x.uid === uid)
            downloadUrls.push(a.result.url);
        })
        downloadUrls.forEach((value, idx) => {
            // setTimeout(() => {
            //     window.location.href = value;
            // }, idx * 1000);
            window.open(value, '_blank');
        });
    }

    onChangeCheck(e, checked){
        const selectedRows = {...this.state.selectedRows};
        selectedRows[e.target.name] = checked;

        // update state
        this.setState({
            selectedRows
        });
        this.props.onSelectionToggle(selectedRows);
    }

    getTextFontSize() {
        if(window.innerWidth <= 575) {
            return '10px';
        }
        else if (window.innerWidth <= 767) {
            return '11px';
        }
        else if (window.innerWidth <= 991) {
            return '12px';
        }
        else if(window.innerWidth <= 1199) {
            return '13px';
        }
        else {
            return '14px';
        }
    }

    handleCloudDownload(url) {
        window.open(url, '_blank');
    }

    handleProviderCloudDownload(providerUid) {
        let downloadUrls = [];
        this.props.provider.tasks.forEach((column) => {
            if(column.display == true) {
                let url = column.result.url;
                downloadUrls.push(url);
            }
        })
        downloadUrls.forEach((value, idx) => {
            window.open(value, '_blank');
        });
    }

    getTaskStatus(task) {
        //TODO: Take out the hard code error here
        //task.status = "INCOMPLETE";
        switch (task.status) {
            case "SUCCESS":
                return <Check style={{fill:'#55ba63', verticalAlign: 'middle', marginBottom: '2px'}}/>;
            case "INCOMPLETE":
                return <TaskError task={task}/>
            case "PENDING":
                return "WAITING";
            case "RUNNING":
                return <LinearProgress mode="determinate" value={task.progress}/>{task.progress == 100 ? '' : task.progress + ' %'};
            case "CANCELED":
                return <Warning style={{marginLeft:'10px', display:'inlineBlock', fill:'#f4d225', verticalAlign: 'bottom'}}/>;
            default:
                return "";
        }
    }

    getProviderStatus(provider) {
        //TODO: Take out the hard code error here
        //provider.status = 'INCOMPLETE'
        switch (provider.status) {
            case "COMPLETED":
                return <Check style={{fill:'#55ba63', verticalAlign: 'middle', marginBottom: '2px'}}/>;
            case "INCOMPLETE":
                return <ProviderError provider={provider} key={provider.uid}/>;
            case "PENDING":
                return "WAITING";
            case "RUNNING":
                return "IN PROGRESS";
            case "CANCELED":
                return CANCELED<Warning style={{marginLeft:'10px', display:'inlineBlock', fill:'#f4d225', verticalAlign: 'bottom'}}/>
            default:
                return "";
        }
    }

    getTaskLink(task) {
        if(task.result == null){
            return {task.name}
        }
        else {
            return {task.name}
        }
    }

    getTaskDownloadIcon(task) {
        if(task.result == null){
            return <CloudDownload key={task.result == null ? '' : task.result.url} style={{marginLeft:'10px', display:'inlineBlock', fill:'gray', verticalAlign: 'middle'}}/>
        }
        else {
            return <CloudDownload  onClick={() => {this.handleCloudDownload(task.result.url)}} key={task.result.url} style={{marginLeft:'10px', cursor: 'pointer', display:'inlineBlock', fill:'#4598bf', verticalAlign: 'middle'}}/>
        }
    }

    getProviderLink(provider) {
        if(provider.status != "COMPLETED") {
            return {provider.name}
        }
        else {
            return  {this.handleProviderCloudDownload(provider.uid)}} style={{display:'inlineBlock', borderTopWidth:'10px', borderBottomWidth:'10px', borderLeftWidth:'10px', color:'#4598bf', cursor: 'pointer'}}>{provider.name}
        }
    }

    getProviderDownloadIcon(provider) {
        if(provider.status != "COMPLETED"){
            return <CloudDownload key={provider.uid} style={{marginLeft:'10px', display:'inlineBlock', fill:'gray', verticalAlign: 'middle'}}/>
        }
        else {
            return <CloudDownload  onClick={() => {this.handleProviderCloudDownload(provider.uid)}} key={provider.uid} style={{marginLeft:'10px', cursor: 'pointer', display:'inlineBlock', fill:'#4598bf', verticalAlign: 'middle'}}/>
        }
    }

    getTableCellWidth() {
        if(window.innerWidth <= 767) {
            return '80px';
        }
        else {
            return '120px';
        }
    }

    getToggleCellWidth() {
        if(window.innerWidth <= 767) {
            return '30px';
        }
        else {
            return '50px';
        }
    }

    handleProviderClose = () => {
        this.setState({providerDialogOpen: false});

    };

    handleProviderOpen(runProviders) {
        let propsProvider = this.props.providers.find(x => x.slug === runProviders.slug);
        let providerDesc = propsProvider.service_description;
        this.setState({providerDesc, providerDialogOpen: true});
    };

    render() {
        const style = {
              textDecoration: 'underline'
             }
        const textFontSize = this.getTextFontSize();
        const tableCellWidth = this.getTableCellWidth();
        const toggleCellWidth = this.getToggleCellWidth();
        const {provider, ...rowProps} = this.props;

        let menuItems = [];
        let cancelMenuDisabled;
        if(this.props.provider.status == 'PENDING' || this.props.provider.status == 'RUNNING') {
            cancelMenuDisabled = false;
        }
        else {
            cancelMenuDisabled = true;
        }
        menuItems.push(<MenuItem
            key={'cancel'}
            disabled={cancelMenuDisabled}
            style={{fontSize: '12px'}}
            primaryText="Cancel"
            onClick={() => {this.props.onProviderCancel(this.props.provider.uid)}}
        />,<MenuItem
        key={'viewProviderData'}
        style={{fontSize: '12px'}}
        primaryText='View Data Source'
        onClick={this.handleProviderOpen.bind(this, this.props.provider)}
    />);

        const providerInfoActions = [
            <RaisedButton
                style={{margin: '10px'}}
                labelStyle={{color: 'whitesmoke', fontWeight: 'bold'}}
                buttonStyle={{backgroundColor: '#4598bf'}}
                disableTouchRipple={true}
                label="Close"
                primary={false}
                onTouchTap={this.handleProviderClose.bind(this)}
            />,
        ];

        const tasks = provider.tasks.filter((task) => {
            return task.display != false;
        });

        let tableData;
        if(this.state.openTable == true){
            tableData = <TableBody
                displayRowCheckbox={false}
                deselectOnClickaway={false}
                showRowHover={false}
                className={styles.tableRowHighlight}
            >
                {tasks.map((task) => (

                    <TableRow selectable={false} style={{height: '20px'}} displayBorder={true} key={task.uid} >
                    <TableRowColumn style={{paddingRight: '12px', paddingLeft: '12px', width: '44px'}}>

                    </TableRowColumn>
                        <TableRowColumn style={{paddingRight: '12px', paddingLeft: '12px', fontSize: textFontSize}}>
                            {this.getTaskLink(task)}
                            {this.getTaskDownloadIcon(task)}
                        </TableRowColumn>
                    <TableRowColumn style={{width: tableCellWidth, paddingRight: '0px', paddingLeft: '0px', textAlign: 'center', fontSize: textFontSize}}>{task.result == null ? '' : task.result.size}</TableRowColumn>
                    <TableRowColumn style={{width: tableCellWidth, paddingRight: '10px', paddingLeft: '10px', textAlign: 'center', fontSize: textFontSize, fontWeight: 'bold'}}>{this.getTaskStatus(task)}</TableRowColumn>
                    <TableRowColumn style={{paddingRight: '0px', paddingLeft: '0px', width: '20px',textAlign: 'center', fontSize: textFontSize}}></TableRowColumn>
                    <TableRowColumn style={{paddingRight: '0px', paddingLeft: '0px', width: toggleCellWidth, textAlign: 'center', fontSize: textFontSize}}></TableRowColumn>
                    </TableRow>

                ))}

            </TableBody>

        }
        else{
            tableData = <TableBody/>
        }

        return (

                <TableHeader
                    displaySelectAll={false}
                    adjustForCheckbox={false}
                    enableSelectAll={false}
                    >
                    <TableRow displayBorder={true}>
                        <TableHeaderColumn style={{paddingRight: '12px', paddingLeft: '12px', width:'44px'}}>
                            <Checkbox
                                disabled={this.props.provider.status != "COMPLETED"}
                                checked={this.props.selectedProviders[this.props.provider.uid] ? true : false}
                                name={this.props.provider.uid}
                                onCheck={this.onChangeCheck}
                                checkedIcon={<CheckedBox style={{fill: '#4598bf'}}/>}
                                uncheckedIcon={<UncheckedBox style={{fill: '#4598bf'}}/>}
                            />
                        </TableHeaderColumn>
                        <TableHeaderColumn style={{paddingRight: '12px', paddingLeft: '12px', whiteSpace: 'normal', color: 'black', fontWeight: 'bold', fontSize: textFontSize}}>
                            {this.getProviderLink(this.props.provider)}
                            {this.getProviderDownloadIcon(this.props.provider)}
                        </TableHeaderColumn>
                        <TableHeaderColumn style={{width: tableCellWidth, paddingRight: '0px', paddingLeft: '0px', textAlign: 'center', color: 'black!important', fontSize: textFontSize}}>
                            {this.state.fileSize == null ? '' : this.state.fileSize + " MB"}
                        </TableHeaderColumn>
                        <TableHeaderColumn style={{width: tableCellWidth, paddingRight: '0px', paddingLeft: '0px', textAlign: 'center', color: 'black!important', fontSize: textFontSize}}>
                            {this.getProviderStatus(this.props.provider)}

                        </TableHeaderColumn>
                        <TableHeaderColumn style={{paddingRight: '0px', paddingLeft: '0px', width: '20px',textAlign: 'right'}}>
                            {menuItems.length > 0 ?
                                <IconMenu
                                    iconButtonElement={
                                        <IconButton
                                            style={{padding: '0px', width: '20px', verticalAlign: 'middle'}}
                                            iconStyle={{color: '#4598bf'}}>
                                            <NavigationMoreVert />
                                        </IconButton>}
                                    anchorOrigin={{horizontal: 'middle', vertical: 'center'}}
                                    targetOrigin={{horizontal: 'right', vertical: 'top'}}
                                >
                                    {menuItems}
                                </IconMenu>
                            :
                                null
                            }<Dialog
                            contentStyle={{width:'70%', minWidth:'300px', maxWidth:'610px'}}
                            actions={providerInfoActions}
                            modal={false}
                            open={this.state.providerDialogOpen}
                            onRequestClose={this.handleProviderClose.bind(this)}
                        >
                            {this.props.provider.name}
                                <CustomScrollbar style={{height: '200px', overflowX: 'hidden', width:'100%'}}>

{this.state.providerDesc}

                                </CustomScrollbar>

                        </Dialog>
                        </TableHeaderColumn>
                        <TableHeaderColumn style={{paddingRight: '0px', paddingLeft: '0px', width: toggleCellWidth, textAlign: 'left'}}>
                            <IconButton disableTouchRipple={true} onTouchTap={this.handleToggle} iconStyle={{fill: '4598bf'}}>
                                {this.state.openTable ? <ArrowDown/> : <ArrowUp/>}
                            </IconButton>

                        </TableHeaderColumn>
                    </TableRow>
                </TableHeader>
                            {tableData}

        )
    }
}

ProviderRow.propTypes = {
    provider: PropTypes.object.isRequired,
    onSelectionToggle: PropTypes.func,
    selectedProviders: PropTypes.object,
    onProviderCancel: PropTypes.func.isRequired,
    providers: PropTypes.array.isRequired
}

export default ProviderRow;

<commit_msg>for some reason this file was not pushed.<commit_after>import React, {PropTypes, Component} from 'react'
import '../tap_events'
import moment from 'moment'
import {Table, TableBody, TableHeader,
    TableHeaderColumn, TableRow, TableRowColumn} from 'material-ui/Table';
import IconMenu from 'material-ui/IconMenu';
import MenuItem from 'material-ui/MenuItem';
import Dialog from 'material-ui/Dialog';
import RaisedButton from 'material-ui/RaisedButton';
import NavigationMoreVert from 'material-ui/svg-icons/navigation/more-vert';
import ArrowDown from 'material-ui/svg-icons/hardware/keyboard-arrow-down'
import ArrowUp from 'material-ui/svg-icons/hardware/keyboard-arrow-up'
import UncheckedBox from 'material-ui/svg-icons/toggle/check-box-outline-blank'
import CheckedBox from 'material-ui/svg-icons/toggle/check-box'
import Warning from 'material-ui/svg-icons/alert/warning'
import Check from 'material-ui/svg-icons/navigation/check'
import IconButton from 'material-ui/IconButton';
import CloudDownload from 'material-ui/svg-icons/file/cloud-download'
import styles from '../../styles/StatusDownload.css'
import { Link, IndexLink } from 'react-router';
import Checkbox from 'material-ui/Checkbox'
import LinearProgress from 'material-ui/LinearProgress';
import CustomScrollbar from '../CustomScrollbar';
import TaskError from './TaskError'
import ProviderError from './ProviderError'

export class ProviderRow extends React.Component {
    constructor(props) {
        super(props)
        this.handleDownload = this.handleDownload.bind(this);
        this.handleToggle = this.handleToggle.bind(this);
        this.onChangeCheck = this.onChangeCheck.bind(this);
        this.state = {
            providerTasks: [],
            openTable: false,
            selectedRows: { },
            fileSize: null,
            providerDesc: '',
            providerDialogOpen: false,
            cloneDialogOpen: false,

        }
    }

    componentWillMount(){
        //set state on the provider
        let t = {};
        let uid = this.props.provider.uid;
        t[uid] = false;
        this.setState({selectedRows:t})
    }

    componentWillReceiveProps(nextProps) {
        let fileSize = 0.000;
        nextProps.provider.tasks.forEach((task) => {
            if (task.result != null ){
                if (task.display != false && task.result.size) {
                    let textReplace = task.result.size.replace(' MB', '');
                    let number = textReplace;
                    fileSize = Number(fileSize) + Number(number);
                    this.setState({fileSize: fileSize.toFixed(3)});
                }
            }
        })

        if(nextProps.selectedProviders != this.state.selectedRows) {
            this.setState({selectedRows : nextProps.selectedProviders})
        }
    }

    handleToggle() {
        this.setState({openTable: !this.state.openTable});
    }

    handleDownload()  {
        let downloadUids = [];
        let selectedTasks = {...this.state.selectedRows};
        Object.keys(selectedTasks).forEach((keyName, keyIndex) => {
            if (selectedTasks[keyName] == true) {
                downloadUids.push(keyName);
            }
        });

        let tasks = this.props.provider.tasks;
        let downloadUrls = [];
        downloadUids.forEach((uid) => {
            let a = tasks.find(x => x.uid === uid)
            downloadUrls.push(a.result.url);
        })
        downloadUrls.forEach((value, idx) => {
            // setTimeout(() => {
            //     window.location.href = value;
            // }, idx * 1000);
            window.open(value, '_blank');
        });
    }

    onChangeCheck(e, checked){
        const selectedRows = {...this.state.selectedRows};
        selectedRows[e.target.name] = checked;

        // update state
        this.setState({
            selectedRows
        });
        this.props.onSelectionToggle(selectedRows);
    }

    getTextFontSize() {
        if(window.innerWidth <= 575) {
            return '10px';
        }
        else if (window.innerWidth <= 767) {
            return '11px';
        }
        else if (window.innerWidth <= 991) {
            return '12px';
        }
        else if(window.innerWidth <= 1199) {
            return '13px';
        }
        else {
            return '14px';
        }
    }

    handleCloudDownload(url) {
        window.open(url, '_blank');
    }

    handleProviderCloudDownload(providerUid) {
        let downloadUrls = [];
        this.props.provider.tasks.forEach((column) => {
            if(column.display == true) {
                let url = column.result.url;
                downloadUrls.push(url);
            }
        })
        downloadUrls.forEach((value, idx) => {
            window.open(value, '_blank');
        });
    }

    getTaskStatus(task) {
        //TODO: Take out the hard code error here
        //task.status = "INCOMPLETE";
        switch (task.status) {
            case "SUCCESS":
                return <Check style={{fill:'#55ba63', verticalAlign: 'middle', marginBottom: '2px'}}/>;
            case "INCOMPLETE":
                return <TaskError task={task}/>
            case "PENDING":
                return "WAITING";
            case "RUNNING":
                return <LinearProgress mode="determinate" value={task.progress}/>{task.progress == 100 ? '' : task.progress + ' %'};
            case "CANCELED":
                return <Warning style={{marginLeft:'10px', display:'inlineBlock', fill:'#f4d225', verticalAlign: 'bottom'}}/>;
            default:
                return "";
        }
    }

    getProviderStatus(provider) {
        //TODO: Take out the hard code error here
        //provider.status = 'INCOMPLETE'
        switch (provider.status) {
            case "COMPLETED":
                return <Check style={{fill:'#55ba63', verticalAlign: 'middle', marginBottom: '2px'}}/>;
            case "INCOMPLETE":
                return <ProviderError provider={provider} key={provider.uid}/>;
            case "PENDING":
                return "WAITING";
            case "RUNNING":
                return "IN PROGRESS";
            case "CANCELED":
                return CANCELED<Warning style={{marginLeft:'10px', display:'inlineBlock', fill:'#f4d225', verticalAlign: 'bottom'}}/>
            default:
                return "";
        }
    }

    getTaskLink(task) {
        if(task.result == null){
            return {task.name}
        }
        else {
            return {task.name}
        }
    }

    getTaskDownloadIcon(task) {
        if(task.result == null){
            return <CloudDownload key={task.result == null ? '' : task.result.url} style={{marginLeft:'10px', display:'inlineBlock', fill:'gray', verticalAlign: 'middle'}}/>
        }
        else {
            return <CloudDownload  onClick={() => {this.handleCloudDownload(task.result.url)}} key={task.result.url} style={{marginLeft:'10px', cursor: 'pointer', display:'inlineBlock', fill:'#4598bf', verticalAlign: 'middle'}}/>
        }
    }

    getProviderLink(provider) {
        if(provider.status != "COMPLETED") {
            return {provider.name}
        }
        else {
            return  {this.handleProviderCloudDownload(provider.uid)}} style={{display:'inlineBlock', borderTopWidth:'10px', borderBottomWidth:'10px', borderLeftWidth:'10px', color:'#4598bf', cursor: 'pointer'}}>{provider.name}
        }
    }

    getProviderDownloadIcon(provider) {
        if(provider.status != "COMPLETED"){
            return <CloudDownload key={provider.uid} style={{marginLeft:'10px', display:'inlineBlock', fill:'gray', verticalAlign: 'middle'}}/>
        }
        else {
            return <CloudDownload  onClick={() => {this.handleProviderCloudDownload(provider.uid)}} key={provider.uid} style={{marginLeft:'10px', cursor: 'pointer', display:'inlineBlock', fill:'#4598bf', verticalAlign: 'middle'}}/>
        }
    }

    getTableCellWidth() {
        if(window.innerWidth <= 767) {
            return '80px';
        }
        else {
            return '120px';
        }
    }

    getToggleCellWidth() {
        if(window.innerWidth <= 767) {
            return '30px';
        }
        else {
            return '50px';
        }
    }

    handleProviderClose = () => {
        this.setState({providerDialogOpen: false});

    };

    handleProviderOpen(runProviders) {
        let propsProvider = this.props.providers.find(x => x.slug === runProviders.slug);
        let providerDesc = propsProvider.service_description;
        this.setState({providerDesc, providerDialogOpen: true});
    };

    render() {
        const style = {
              textDecoration: 'underline'
             }
        const textFontSize = this.getTextFontSize();
        const tableCellWidth = this.getTableCellWidth();
        const toggleCellWidth = this.getToggleCellWidth();
        const {provider, ...rowProps} = this.props;

        let menuItems = [];
        let cancelMenuDisabled;
        if(this.props.provider.status == 'PENDING' || this.props.provider.status == 'RUNNING') {
            cancelMenuDisabled = false;
        }
        else {
            cancelMenuDisabled = true;
        }
        menuItems.push(<MenuItem
            key={'cancel'}
            disabled={cancelMenuDisabled}
            style={{fontSize: '12px'}}
            primaryText="Cancel"
            onClick={() => {this.props.onProviderCancel(this.props.provider.uid)}}
        />,<MenuItem
        key={'viewProviderData'}
        style={{fontSize: '12px'}}
        primaryText='View Data Source'
        onClick={this.handleProviderOpen.bind(this, this.props.provider)}
    />);

        const providerInfoActions = [
            <RaisedButton
                style={{margin: '10px'}}
                labelStyle={{color: 'whitesmoke', fontWeight: 'bold'}}
                buttonStyle={{backgroundColor: '#4598bf'}}
                disableTouchRipple={true}
                label="Close"
                primary={false}
                onTouchTap={this.handleProviderClose.bind(this)}
            />,
        ];

        const tasks = provider.tasks.filter((task) => {
            return task.display != false;
        });

        let tableData;
        if(this.state.openTable == true){
            tableData = <TableBody
                displayRowCheckbox={false}
                deselectOnClickaway={false}
                showRowHover={false}
                className={styles.tableRowHighlight}
            >
                {tasks.map((task) => (

                    <TableRow selectable={false} style={{height: '20px'}} displayBorder={true} key={task.uid} >
                    <TableRowColumn style={{paddingRight: '12px', paddingLeft: '12px', width: '44px'}}>

                    </TableRowColumn>
                        <TableRowColumn style={{paddingRight: '12px', paddingLeft: '12px', fontSize: textFontSize}}>
                            {this.getTaskLink(task)}
                            {this.getTaskDownloadIcon(task)}
                        </TableRowColumn>
                    <TableRowColumn style={{width: tableCellWidth, paddingRight: '0px', paddingLeft: '0px', textAlign: 'center', fontSize: textFontSize}}>{task.result == null ? '' : task.result.size}</TableRowColumn>
                    <TableRowColumn style={{width: tableCellWidth, paddingRight: '10px', paddingLeft: '10px', textAlign: 'center', fontSize: textFontSize, fontWeight: 'bold'}}>{this.getTaskStatus(task)}</TableRowColumn>
                    <TableRowColumn style={{paddingRight: '0px', paddingLeft: '0px', width: '20px',textAlign: 'center', fontSize: textFontSize}}></TableRowColumn>
                    <TableRowColumn style={{paddingRight: '0px', paddingLeft: '0px', width: toggleCellWidth, textAlign: 'center', fontSize: textFontSize}}></TableRowColumn>
                    </TableRow>

                ))}

            </TableBody>

        }
        else{
            tableData = <TableBody/>
        }

        return (

                <TableHeader
                    displaySelectAll={false}
                    adjustForCheckbox={false}
                    enableSelectAll={false}
                    >
                    <TableRow displayBorder={true}>
                        <TableHeaderColumn style={{paddingRight: '12px', paddingLeft: '12px', width:'44px'}}>
                            <Checkbox
                                disabled={this.props.provider.status != "COMPLETED"}
                                checked={this.props.selectedProviders[this.props.provider.uid] ? true : false}
                                name={this.props.provider.uid}
                                onCheck={this.onChangeCheck}
                                checkedIcon={<CheckedBox style={{fill: '#4598bf'}}/>}
                                uncheckedIcon={<UncheckedBox style={{fill: '#4598bf'}}/>}
                            />
                        </TableHeaderColumn>
                        <TableHeaderColumn style={{paddingRight: '12px', paddingLeft: '12px', whiteSpace: 'normal', color: 'black', fontWeight: 'bold', fontSize: textFontSize}}>
                            {this.getProviderLink(this.props.provider)}
                            {this.getProviderDownloadIcon(this.props.provider)}
                        </TableHeaderColumn>
                        <TableHeaderColumn style={{width: tableCellWidth, paddingRight: '0px', paddingLeft: '0px', textAlign: 'center', color: 'black!important', fontSize: textFontSize}}>
                            {this.state.fileSize == null ? '' : this.state.fileSize + " MB"}
                        </TableHeaderColumn>
                        <TableHeaderColumn style={{width: tableCellWidth, paddingRight: '0px', paddingLeft: '0px', textAlign: 'center', color: 'black!important', fontSize: textFontSize}}>
                            {this.getProviderStatus(this.props.provider)}

                        </TableHeaderColumn>
                        <TableHeaderColumn style={{paddingRight: '0px', paddingLeft: '0px', width: '20px',textAlign: 'right'}}>
                            {menuItems.length > 0 ?
                                <IconMenu
                                    iconButtonElement={
                                        <IconButton
                                            style={{padding: '0px', width: '20px', verticalAlign: 'middle'}}
                                            iconStyle={{color: '#4598bf'}}>
                                            <NavigationMoreVert />
                                        </IconButton>}
                                    anchorOrigin={{horizontal: 'middle', vertical: 'center'}}
                                    targetOrigin={{horizontal: 'right', vertical: 'top'}}
                                >
                                    {menuItems}
                                </IconMenu>
                            :
                                null
                            }
                        </TableHeaderColumn>
                        <TableHeaderColumn style={{paddingRight: '0px', paddingLeft: '0px', width: toggleCellWidth, textAlign: 'left'}}>
                            <IconButton disableTouchRipple={true} onTouchTap={this.handleToggle} iconStyle={{fill: '4598bf'}}>
                                {this.state.openTable ? <ArrowDown/> : <ArrowUp/>}
                            </IconButton>
                        </TableHeaderColumn>
                    </TableRow>
                </TableHeader>
                            {tableData}

        )
    }
}

ProviderRow.propTypes = {
    provider: PropTypes.object.isRequired,
    onSelectionToggle: PropTypes.func,
    selectedProviders: PropTypes.object,
    onProviderCancel: PropTypes.func.isRequired,
}

export default ProviderRow;

<|endoftext|>


<commit_before>import {Loading} from 'element-ui';

export var mixin = {
  data: function () {
    return {
      currentPage: 1,
      pageSize: 25,
      pageSizeList: pageSizeList,

      selectedItems: [],

      searchTerm: null,
      searchForm: {},

      tableData: [],
      datatablesParameters: {
        draw: 0,
        columns: [],
        order: [],
        start: 0,
        length: 25,
        search: {
          value: null,
          regex: false
        },
        _: null,
      },
      loading: null,
      _draw: null,
    };
  },
  mounted: function () {
    this.initializeDataTablesParameters();
    this.queryTableData();
  },
  methods: {
    showLoading: function (target) {
      this.loading = Loading.service({
        target: target,
        fullscreen: false,
        lock: false,
        text: '读取中...'
      });
    },
    hideLoading: function () {
      this.loading.close();
    },
    queryTableData: function () {
      this.showLoading('.datatable-loading-section');
      axios.get(this.resource, {
        params: this.buildDataTablesParameters(),
        paramsSerializer: (params) => {
          var parameters = JSON.parse(JSON.stringify(params));
          delete parameters.order;
          delete parameters.columns;
          delete parameters.search;
          params.columns.forEach((element, index) => {
            if (!element.data) {
              return;
            }
            parameters['columns[' + index + '][data]'] = element.data;
            parameters['columns[' + index + '][name]'] = element.name;
            parameters['columns[' + index + '][searchable]'] = element.searchable ? element.searchable : true;
            parameters['columns[' + index + '][orderable]'] = element.orderable ? element.orderable : true;
            parameters['columns[' + index + '][search][value]'] = element.search.value ? element.search.value : null;
            parameters['columns[' + index + '][search][regex]'] = element.search.regex ? element.search.regex : false;
            if (element.search.hasOwnProperty('advance')) {
              for (var operator in element.search.advance) {
                if (element.search.advance.hasOwnProperty(operator)) {
                  parameters['columns[' + index + '][search][advance][' + operator + ']'] = val;
                }
              }
            }
          });
          params.order.forEach(function (element, index) {
            parameters['order[' + index + '][column]'] = element.column;
            parameters['order[' + index + '][dir]'] = element.dir ? element.dir : 'asc';
          });
          parameters['search[value]'] = params.search.value !== undefined ? params.search.value : null;
          parameters['search[regex]'] = params.search.regex ? params.search.regex : false;
          var parameterString = [];
          for (var key in parameters) {
            if (parameters.hasOwnProperty(key)) {
              if ([undefined, null, ''].indexOf(parameters[key]) === -1) {
                parameterString.push(key + '=' + parameters[key]);
              }
              else {
                parameterString.push(key + '=');
              }
            }
          }
          parameterString = encodeURI(parameterString.join('&'));
          return parameterString;
        }
      })
        .then(result => {
          if (this._draw == result.data.draw) {
            this.tableData = result.data.data;
            this.hideLoading();
          }
        })
        .catch(result => {
          this.hideLoading();
        });
    },
    onSubmitSearch: function () {
      alert('onSubmitSearch');
    },
    onCreate: function () {
      alert('onCreate');
    },
    onBundleDelete: function () {
      alert('onBundleDelete');
    },
    handleClick: function () {
      alert('handleClick');
    },
    handleSizeChange: function () {
      this.datatablesParameters.length = this.pageSize;
      this.queryTableData();
    },
    handleCurrentChange: function () {
      alert('handleCurrentChange');
    },
    initializeDataTablesParameters: function () {
      this.$refs.table.columns.forEach((column, index, columns) => {
        if (!column.property) {
          return;
        }
        this.datatablesParameters.columns.push({
          data: column.property,
          name: column.property,
          searchable: true,
          orderable: column.sortable,
          search: {
            value: null,
            regex: false,
            advance: {}
          },
        });
      });
    },
    buildDataTablesParameters: function () {
      this.datatablesParameters.draw++;
      this._draw = this.datatablesParameters.draw;
      this.datatablesParameters._ = new Date().getTime();
      return this.datatablesParameters;
    }
  }
};

export function loadTableData (resource) {

}

export function onDelete () {

}
export function onBundle () {

}

export var pageSizeList = [
  {
    label: 25,
    value: 25
  },
  {
    label: 50,
    value: 50
  },
  {
    label: 100,
    value: 100
  },
  {
    label: '全部',
    value: -1
  }
];<commit_msg>pagination & page size<commit_after>import { Loading } from 'element-ui';

export var mixin = {
  data: function () {
    return {
      pagination: {
        currentPage: 1,
        totalCount: 0,
        pageSize: 25,
        pageSizeList: pageSizeList,
      },

      selectedItems: [],

      searchTerm: null,
      searchForm: {},

      tableData: [],
      datatablesParameters: {
        draw: 0,
        columns: [],
        order: [],
        start: 0,
        length: 25,
        search: {
          value: null,
          regex: false
        },
        _: null,
      },
      loading: null,
      _draw: null,
    };
  },
  mounted: function () {
    this.initializeDataTablesParameters();
    this.queryTableData();
  },
  methods: {
    showLoading: function (target) {
      this.loading = Loading.service({
        target: target,
        fullscreen: false,
        lock: false,
        text: '读取中...'
      });
    },
    hideLoading: function () {
      this.loading.close();
    },
    queryTableData: function () {
      if (this.loading && this.loading.visible) {
        return false;
      }
      this.showLoading('.datatable-loading-section');
      axios.get(this.resource, {
        params: this.buildDataTablesParameters(),
        paramsSerializer: (params) => {
          var parameters = JSON.parse(JSON.stringify(params));
          delete parameters.order;
          delete parameters.columns;
          delete parameters.search;
          params.columns.forEach((element, index) => {
            if (!element.data) {
              return;
            }
            parameters['columns[' + index + '][data]'] = element.data;
            parameters['columns[' + index + '][name]'] = element.name;
            parameters['columns[' + index + '][searchable]'] = element.searchable ? element.searchable : true;
            parameters['columns[' + index + '][orderable]'] = element.orderable == 'custom' ? true : false;
            parameters['columns[' + index + '][search][value]'] = element.search.value ? element.search.value : null;
            parameters['columns[' + index + '][search][regex]'] = element.search.regex ? element.search.regex : false;
            if (element.search.hasOwnProperty('advance')) {
              for (var operator in element.search.advance) {
                if (element.search.advance.hasOwnProperty(operator)) {
                  parameters['columns[' + index + '][search][advance][' + operator + ']'] = val;
                }
              }
            }
          });
          params.order.forEach(function (element, index) {
            parameters['order[' + index + '][column]'] = isNaN(element.column) ? params.columns.findIndex(column => {
              return column.data == element.column;
            }) : parseInt(element.column);
            parameters['order[' + index + '][dir]'] = element.dir ? element.dir : 'asc';
          });
          parameters['search[value]'] = params.search.value !== undefined ? params.search.value : null;
          parameters['search[regex]'] = params.search.regex ? params.search.regex : false;
          var parameterString = [];
          for (var key in parameters) {
            if (parameters.hasOwnProperty(key)) {
              if ([undefined, null, ''].indexOf(parameters[key]) === -1) {
                parameterString.push(key + '=' + parameters[key]);
              }
              else {
                parameterString.push(key + '=');
              }
            }
          }
          parameterString = encodeURI(parameterString.join('&'));
          return parameterString;
        }
      })
        .then(result => {
          if (this._draw == result.data.draw) {
            this.tableData = result.data.data;
            this.pagination.totalCount = result.data.recordsFiltered;
            this.hideLoading();
          }
        })
        .catch(result => {
          this.hideLoading();
        });
    },
    onSubmitSearch: function () {
      alert('onSubmitSearch');
    },
    onCreate: function () {
      alert('onCreate');
    },
    onBundleDelete: function () {
      alert('onBundleDelete');
    },
    onSortChange: function ({column, prop, order}) {
      this.datatablesParameters.order = [{'column': prop, 'dir': (order == 'ascending' ? 'asc' : 'desc')}];
      this.queryTableData();
    },
    handleClick: function () {
      alert('handleClick');
    },
    handleSizeChange: function () {
      this.datatablesParameters.length = this.pagination.pageSize;
      this.queryTableData();
    },
    handlePageChange: function (page) {
      this.pagination.currentPage = page;
      this.datatablesParameters.start = (page - 1) * this.pagination.pageSize;
      this.queryTableData();
    },
    initializeDataTablesParameters: function () {
      this.$refs.table.columns.forEach((column, index, columns) => {
        if (!column.property) {
          return;
        }
        this.datatablesParameters.columns.push({
          data: column.property,
          name: column.property,
          searchable: true,
          orderable: column.sortable,
          search: {
            value: null,
            regex: false,
            advance: {}
          },
        });
      });
    },
    buildDataTablesParameters: function () {
      this.datatablesParameters.draw++;
      this._draw = this.datatablesParameters.draw;
      this.datatablesParameters._ = new Date().getTime();
      return this.datatablesParameters;
    }
  }
};

export function loadTableData (resource) {

}

export function onDelete () {

}
export function onBundle () {

}

export var pageSizeList = [
  {
    label: 25,
    value: 25
  },
  {
    label: 50,
    value: 50
  },
  {
    label: 100,
    value: 100
  },
  {
    label: '全部',
    value: -1
  }
];<|endoftext|>