<commit_before>/**
 * PostSearcherAutoSuggest component.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import {
	Combobox,
	ComboboxInput,
	ComboboxPopover,
	ComboboxList,
	ComboboxOption,
} from '@reach/combobox';

/**
 * WordPress dependencies
 */
import { useState, useEffect, useCallback, useRef } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { ENTER, ESCAPE } from '@wordpress/keycodes';

/**
 * Internal dependencies
 */
import API from 'googlesitekit-api';
import Data from 'googlesitekit-data';
import { useDebouncedState } from '../hooks/useDebouncedState';
import { useFeature } from '../hooks/useFeature';
import { CORE_SITE } from '../googlesitekit/datastore/site/constants';

const { useSelect } = Data;

export default function PostSearcherAutoSuggest( {
	id,
	match,
	setMatch,
	isLoading,
	showDropdown = true,
	setIsLoading,
	setIsActive = () => {},
	autoFocus,
	setCanSubmit = () => {},
	onClose = () => {},
	placeholder = '',
} ) {
	const [ searchTerm, setSearchTerm ] = useState( '' );

	// eslint-disable-next-line camelcase
	const postTitleFromMatch = match?.post_title;
	/**
	 * As a fix for #4562, we should hide the loading indicator
	 * after pressing enter/return key on a URL Entity Search Result.
	 *
	 * In the useEffect condition we check for:
	 * `debouncedValue !== postTitleFromMatch` to set the loading state to true.
	 * However, the `debouncedValue` is always delayed. Hence this condition is always true.
	 * Hence the loading state is to true.
	 * Therefore, we need to set the debounce delay/timer value to `0` if the
	 * `searchTerm === postTitleFromMatch` to not to set the loading state to true.
	 */
	const debouncedValue = useDebouncedState(
		searchTerm,
		searchTerm === postTitleFromMatch ? 0 : 200
	);

	const [ results, setResults ] = useState( [] );
	const noResultsMessage = __( 'No results found', 'google-site-kit' );

	const unifiedDashboardEnabled = useFeature( 'unifiedDashboard' );

	const currentEntityTitle = useSelect( ( select ) =>
		select( CORE_SITE ).getCurrentEntityTitle()
	);

	const postTitle = useRef( null );

	const onFocus = useCallback( () => {
		setIsActive( true );
	}, [ setIsActive ] );

	const onBlur = useCallback( () => {
		// When a result is selected using pointer, the onBlur event gets fired before the onSelect,
		// thus removing the dropdown from the tree and missing the click completely. The timeout
		// ensures that the click event will be fired before isActive is set to false.
		setTimeout( () => {
			setIsActive( false );
			setSearchTerm( postTitle.current ?? currentEntityTitle ?? '' );
		}, 100 );
	}, [ currentEntityTitle, setIsActive ] );

	const onSelectCallback = useCallback(
		( value ) => {
			if ( Array.isArray( results ) && value !== noResultsMessage ) {
				const foundMatch = results.find(
					( post ) =>
						post.post_title.toLowerCase() === value.toLowerCase()
				);
				if ( foundMatch ) {
					postTitle.current = foundMatch.post_title;
					setCanSubmit( true );
					setMatch( foundMatch );
					setSearchTerm( foundMatch.post_title );
				} else {
					postTitle.current = null;
				}
			} else {
				postTitle.current = null;
				setCanSubmit( false );
			}
		},
		[ results, setCanSubmit, setMatch, noResultsMessage, setSearchTerm ]
	);

	const onInputChange = useCallback(
		( event ) => {
			setCanSubmit( false );
			setSearchTerm( event.target.value );
		},
		[ setCanSubmit ]
	);

	useEffect( () => {
		if (
			debouncedValue !== '' &&
			debouncedValue !== currentEntityTitle &&
			debouncedValue?.toLowerCase() !== postTitleFromMatch?.toLowerCase()
		) {
			setIsLoading?.( true );
			/**
			 * Create AbortController instance to pass
			 * the signal property to the API.get() method.
			 */
			const controller =
				typeof AbortController === 'undefined'
					? undefined
					: new AbortController();
			API.get(
				'core',
				'search',
				'post-search',
				{ query: encodeURIComponent( debouncedValue ) },
				{ useCache: false, signal: controller?.signal }
			)
				.then( ( res ) => setResults( res ) )
				.catch( () => setResults( [] ) )
				.finally( () => setIsLoading?.( false ) );

			// Clean-up abort
			return () => controller?.abort();
		}
	}, [
		debouncedValue,
		setIsLoading,
		currentEntityTitle,
		postTitleFromMatch,
	] );

	useEffect( () => {
		if ( ! searchTerm ) {
			setResults( [] );
		}
	}, [ searchTerm ] );

	useEffect( () => {
		if ( currentEntityTitle ) {
			setSearchTerm( currentEntityTitle );
		}
	}, [ currentEntityTitle ] );

	const onKeyDown = useCallback(
		( e ) => {
			if ( ! unifiedDashboardEnabled ) {
				return;
			}
			if ( e.keyCode === ESCAPE ) {
				return onClose();
			}

			if ( e.keyCode === ENTER ) {
				return onSelectCallback( searchTerm );
			}
		},
		[ onClose, onSelectCallback, searchTerm, unifiedDashboardEnabled ]
	);

	return (
		<Combobox
			className="autocomplete__wrapper"
			onSelect={ onSelectCallback }
		>
			<ComboboxInput
				id={ id }
				className="autocomplete__input autocomplete__input--default"
				type="text"
				onBlur={ onBlur }
				onChange={ onInputChange }
				onFocus={ onFocus }
				placeholder={ placeholder }
				onKeyDown={ onKeyDown }
				value={ searchTerm }
				/* eslint-disable-next-line jsx-a11y/no-autofocus */
				autoFocus={ autoFocus }
			/>

			{ ( ! unifiedDashboardEnabled || ! isLoading ) &&
				showDropdown &&
				debouncedValue !== currentEntityTitle &&
				debouncedValue !== '' &&
				results.length === 0 && (
					<ComboboxPopover portal={ false }>
						<ComboboxList className="autocomplete__menu autocomplete__menu--inline">
							<ComboboxOption
								value={ noResultsMessage }
								className="autocomplete__option autocomplete__option--no-results"
							/>
						</ComboboxList>
					</ComboboxPopover>
				) }

			{ showDropdown &&
				debouncedValue !== '' &&
				debouncedValue !== currentEntityTitle &&
				results.length > 0 && (
					<ComboboxPopover portal={ false }>
						<ComboboxList className="autocomplete__menu autocomplete__menu--inline">
							{ results.map( ( { ID, post_title: title } ) => (
								<ComboboxOption
									key={ ID }
									value={ title }
									className="autocomplete__option"
								/>
							) ) }
						</ComboboxList>
					</ComboboxPopover>
				) }
		</Combobox>
	);
}

PostSearcherAutoSuggest.propTypes = {
	id: PropTypes.string,
	match: PropTypes.object,
	setCanSubmit: PropTypes.func,
	setMatch: PropTypes.func,
	isLoading: PropTypes.bool,
	setIsLoading: PropTypes.func,
	onKeyDown: PropTypes.func,
	autoFocus: PropTypes.bool,
	placeholder: PropTypes.string,
};
<commit_msg>Fix PostSearcherAutoSuggest selection handling.<commit_after>/**
 * PostSearcherAutoSuggest component.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import {
	Combobox,
	ComboboxInput,
	ComboboxPopover,
	ComboboxList,
	ComboboxOption,
} from '@reach/combobox';

/**
 * WordPress dependencies
 */
import { useState, useEffect, useCallback, useRef } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { ENTER, ESCAPE } from '@wordpress/keycodes';

/**
 * Internal dependencies
 */
import API from 'googlesitekit-api';
import Data from 'googlesitekit-data';
import { useDebouncedState } from '../hooks/useDebouncedState';
import { useFeature } from '../hooks/useFeature';
import { CORE_SITE } from '../googlesitekit/datastore/site/constants';

const { useSelect } = Data;

export default function PostSearcherAutoSuggest( {
	id,
	match,
	setMatch,
	isLoading,
	showDropdown = true,
	setIsLoading,
	setIsActive = () => {},
	autoFocus,
	setCanSubmit = () => {},
	onClose = () => {},
	placeholder = '',
} ) {
	const [ searchTerm, setSearchTerm ] = useState( '' );

	// eslint-disable-next-line camelcase
	const postTitleFromMatch = match?.post_title;
	/**
	 * As a fix for #4562, we should hide the loading indicator
	 * after pressing enter/return key on a URL Entity Search Result.
	 *
	 * In the useEffect condition we check for:
	 * `debouncedValue !== postTitleFromMatch` to set the loading state to true.
	 * However, the `debouncedValue` is always delayed. Hence this condition is always true.
	 * Hence the loading state is to true.
	 * Therefore, we need to set the debounce delay/timer value to `0` if the
	 * `searchTerm === postTitleFromMatch` to not to set the loading state to true.
	 */
	const debouncedValue = useDebouncedState(
		searchTerm,
		searchTerm === postTitleFromMatch ? 0 : 200
	);

	const [ results, setResults ] = useState( [] );
	const noResultsMessage = __( 'No results found', 'google-site-kit' );

	const unifiedDashboardEnabled = useFeature( 'unifiedDashboard' );

	const currentEntityTitle = useSelect( ( select ) =>
		select( CORE_SITE ).getCurrentEntityTitle()
	);

	const postTitle = useRef( null );

	const onFocus = useCallback( () => {
		setIsActive( true );
	}, [ setIsActive ] );

	const onBlur = useCallback(
		( event ) => {
			if (
				! event.relatedTarget?.classList.contains(
					'autocomplete__option--result'
				)
			) {
				setIsActive( false );
				setSearchTerm( postTitle.current ?? currentEntityTitle ?? '' );
			}
		},
		[ currentEntityTitle, setIsActive ]
	);

	const onSelectCallback = useCallback(
		( value ) => {
			if ( Array.isArray( results ) && value !== noResultsMessage ) {
				const foundMatch = results.find(
					( post ) =>
						post.post_title.toLowerCase() === value.toLowerCase()
				);
				if ( foundMatch ) {
					postTitle.current = foundMatch.post_title;
					setCanSubmit( true );
					setMatch( foundMatch );
					setSearchTerm( foundMatch.post_title );
				} else {
					postTitle.current = null;
				}
			} else {
				postTitle.current = null;
				setCanSubmit( false );
			}
		},
		[ results, setCanSubmit, setMatch, noResultsMessage, setSearchTerm ]
	);

	const onInputChange = useCallback(
		( event ) => {
			setCanSubmit( false );
			setSearchTerm( event.target.value );
		},
		[ setCanSubmit ]
	);

	useEffect( () => {
		if (
			debouncedValue !== '' &&
			debouncedValue !== currentEntityTitle &&
			debouncedValue?.toLowerCase() !== postTitleFromMatch?.toLowerCase()
		) {
			setIsLoading?.( true );
			/**
			 * Create AbortController instance to pass
			 * the signal property to the API.get() method.
			 */
			const controller =
				typeof AbortController === 'undefined'
					? undefined
					: new AbortController();
			API.get(
				'core',
				'search',
				'post-search',
				{ query: encodeURIComponent( debouncedValue ) },
				{ useCache: false, signal: controller?.signal }
			)
				.then( ( res ) => setResults( res ) )
				.catch( () => setResults( [] ) )
				.finally( () => setIsLoading?.( false ) );

			// Clean-up abort
			return () => controller?.abort();
		}
	}, [
		debouncedValue,
		setIsLoading,
		currentEntityTitle,
		postTitleFromMatch,
	] );

	useEffect( () => {
		if ( ! searchTerm ) {
			setResults( [] );
		}
	}, [ searchTerm ] );

	useEffect( () => {
		if ( currentEntityTitle ) {
			setSearchTerm( currentEntityTitle );
		}
	}, [ currentEntityTitle ] );

	const onKeyDown = useCallback(
		( e ) => {
			if ( ! unifiedDashboardEnabled ) {
				return;
			}
			if ( e.keyCode === ESCAPE ) {
				return onClose();
			}

			if ( e.keyCode === ENTER ) {
				return onSelectCallback( searchTerm );
			}
		},
		[ onClose, onSelectCallback, searchTerm, unifiedDashboardEnabled ]
	);

	return (
		<Combobox
			className="autocomplete__wrapper"
			onSelect={ onSelectCallback }
		>
			<ComboboxInput
				id={ id }
				className="autocomplete__input autocomplete__input--default"
				type="text"
				onBlur={ onBlur }
				onChange={ onInputChange }
				onFocus={ onFocus }
				placeholder={ placeholder }
				onKeyDown={ onKeyDown }
				value={ searchTerm }
				/* eslint-disable-next-line jsx-a11y/no-autofocus */
				autoFocus={ autoFocus }
			/>

			{ ( ! unifiedDashboardEnabled || ! isLoading ) &&
				showDropdown &&
				debouncedValue !== currentEntityTitle &&
				debouncedValue !== '' &&
				results.length === 0 && (
					<ComboboxPopover portal={ false }>
						<ComboboxList className="autocomplete__menu autocomplete__menu--inline">
							<ComboboxOption
								value={ noResultsMessage }
								className="autocomplete__option autocomplete__option--no-results"
							/>
						</ComboboxList>
					</ComboboxPopover>
				) }

			{ showDropdown &&
				debouncedValue !== '' &&
				debouncedValue !== currentEntityTitle &&
				results.length > 0 && (
					<ComboboxPopover portal={ false }>
						<ComboboxList className="autocomplete__menu autocomplete__menu--inline">
							{ results.map( ( { ID, post_title: title } ) => (
								<ComboboxOption
									key={ ID }
									value={ title }
									className="autocomplete__option autocomplete__option--result"
								/>
							) ) }
						</ComboboxList>
					</ComboboxPopover>
				) }
		</Combobox>
	);
}

PostSearcherAutoSuggest.propTypes = {
	id: PropTypes.string,
	match: PropTypes.object,
	setCanSubmit: PropTypes.func,
	setMatch: PropTypes.func,
	isLoading: PropTypes.bool,
	setIsLoading: PropTypes.func,
	onKeyDown: PropTypes.func,
	autoFocus: PropTypes.bool,
	placeholder: PropTypes.string,
};
<|endoftext|>


<commit_before>define(module, function(exports, require) {

  var util = require('util');
  var qp = require('qp-utility');

  var log = function log() {
    console.log.apply(console, arguments);
  };

  log.ns = 'qp-library/log';

  log.clear = function() {
    if (process.platform === 'win32') {
      process.stdout.write('\033c');
    } else {
      process.stdout.write('\u001B[2J\u001B[0;0f');
    }
  };

  log.dir = function(o, options) {
    console.log(util.inspect(o, options || { showHidden: false, depth: null, colors: true }));
  };

  log.blue_white = function(s) { return '\x1b[47m\x1b[34m' + s + '\x1b[0m\x1b[0m'; };
  log.red = function(s) { return '\x1b[31m' + s + '\x1b[0m'; };
  log.green = function(s) { return '\x1b[32m' + s + '\x1b[0m'; };
  log.yellow = function(s) { return '\x1b[33m' + s + '\x1b[0m'; };
  log.blue = function(s) { return '\x1b[34m' + s + '\x1b[0m'; };
  log.magenta = function(s) { return '\x1b[35m' + s + '\x1b[0m'; };
  log.cyan = function(s) { return '\x1b[36m' + s + '\x1b[0m'; };
  log.white = function(s) { return '\x1b[37m' + s + '\x1b[0m'; };

  exports(log);

});
<commit_msg>log - basic log file output<commit_after>define(module, function(exports, require) {

  var util = require('util');
  var qp = require('qp-utility');
  var fss = require('qp-library/fss');
  var os = require('os');

  var log = function log() {
    console.log.apply(console, arguments);
  };

  log.ns = 'qp-library/log';

  log.clear = function() {
    if (process.platform === 'win32') {
      process.stdout.write('\033c');
    } else {
      process.stdout.write('\u001B[2J\u001B[0;0f');
    }
  };

  log.dir = function(o, options) {
    console.log(util.inspect(o, options || { showHidden: false, depth: null, colors: true }));
  };

  log.file = function(log_file, o, eol_count) {
    fss.append(log_file, JSON.stringify(o, null, '  ') + qp.repeat(os.EOL, eol_count || 0));
  };

  log.blue_white = function(s) { return '\x1b[47m\x1b[34m' + s + '\x1b[0m\x1b[0m'; };
  log.red = function(s) { return '\x1b[31m' + s + '\x1b[0m'; };
  log.green = function(s) { return '\x1b[32m' + s + '\x1b[0m'; };
  log.yellow = function(s) { return '\x1b[33m' + s + '\x1b[0m'; };
  log.blue = function(s) { return '\x1b[34m' + s + '\x1b[0m'; };
  log.magenta = function(s) { return '\x1b[35m' + s + '\x1b[0m'; };
  log.cyan = function(s) { return '\x1b[36m' + s + '\x1b[0m'; };
  log.white = function(s) { return '\x1b[37m' + s + '\x1b[0m'; };

  exports(log);

});
<|endoftext|>


<commit_before>/*
 * Copyright 2015-2016 OpenCB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {LitElement, html} from "/web_modules/lit-element.js";
import UtilsNew from "../../utilsNew.js";
import {NotificationQueue} from "../Notification.js";
import {RestResponse} from "../../clients/rest-response.js";

export default class OpencgaLogin extends LitElement {

    constructor() {
        super();

        this._init();
    }
    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            opencgaSession: {
                type: Object
            },
            buttonText: {
                type: String
            },
            userName: {
                type: String
            },
            password: {
                type: String
            },
            notifyEventMessage: {
                type: String
            }
        };
    }

    _init() {
        this.userName = "";
        this.password = "";
        this.buttonText = "Sign in";
        this.notifyEventMessage = "messageevent";
        this.signingIn = false;
    }

    firstUpdated(changedProperties) {
        $("#formLogin").validator("update");
        $("#formLogin").validator().on("submit", e => this.submitLogin(e));
    }

    submitLogin(e) {
        //console.log("e", e);
        if (e.isDefaultPrevented()) {
            console.error("submitLogin() Error", e);
            // handle the invalid form...
            // this._clearHtmlDom(true);
        } else {
            // everything looks good!
            e.preventDefault();
            //this.dispatchEvent(new CustomEvent("signingIn"));

            const user = this.querySelector("#opencgaUser").value;
            const pass = this.querySelector("#opencgaPassword").value;
            const _this = this;

            try {
                //in case a previous error has prevented the creation of opencgaSession object (in opencgaClient.createSession()), this would be undefined
                if (this.opencgaSession) {
                    this.opencgaSession.opencgaClient.login(user, pass)
                        .then(restResponse => {

                            if (restResponse instanceof RestResponse) {
                                if (restResponse.getEvents?.("ERROR")?.length) {
                                    this.errorState = restResponse.getEvents("ERROR");
                                    new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");
                                } else if (restResponse) {
                                    this.querySelector("#opencgaUser").value = "";
                                    this.querySelector("#opencgaPassword").value = "";
                                    console.log("response", restResponse)
                                    const token = restResponse.getResult(0).token;
                                    const decoded = jwt_decode(token); // TODO expose as module
                                    const dateExpired = new Date(decoded.exp * 1000);
                                    const validTimeSessionId = moment(dateExpired, "YYYYMMDDHHmmss").format("D MMM YY HH:mm:ss"); // TODO expose as module

                                    this.dispatchEvent(new CustomEvent("login", {
                                        detail: {
                                            userId: user,
                                            token: token
                                        },
                                        bubbles: true,
                                        composed: true
                                    }));

                                    new NotificationQueue().push("Welcome, " + user, "Your session is valid until " + validTimeSessionId, UtilsNew.MESSAGE_SUCCESS);

                                }
                            } else {
                                this.errorState = [{name: "Generic Server Error", message: "Unexpected response format. Please check your host is up and running."}];
                                new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");
                            }
                        })
                        .catch(response => {
                            // response isn't necessarily a restResponse instance
                            if (response instanceof RestResponse) {
                                if (response.getEvents?.("ERROR")?.length) {
                                    this.errorState = response.getEvents("ERROR");
                                    new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");
                                } else {
                                    this.errorState = [{name: "Generic Server Error", message: JSON.stringify(response)}];
                                    new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");

                                    this.dispatchEvent(new CustomEvent(_this.notifyEventMessage, {
                                        detail: {
                                            title: this.errorState[0].name,
                                            message: this.errorState[0].message,
                                            type: UtilsNew.MESSAGE_ERROR
                                        },
                                        bubbles: true,
                                        composed: true
                                    }));
                                }
                            } else if (response instanceof Error) {
                                this.errorState = [{name: response.name, message: response.message}];
                                new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");
                            } else {
                                this.errorState = [{name: "Generic Error", message: JSON.JSON.stringify(response)}];
                                new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");
                            }
                        }).finally(() => this.requestUpdate());
                } else {
                    new NotificationQueue().push("Error retrieving OpencgaSession", null, "ERROR");
                }
            } catch (e) {
                this.errorState = [{name: "Generic Error", message: "Please contact your administrator."}];

            }

        }

    }

    checkEnterKey(e) {
        if (e.keyCode === 13) {
            // this.login();
        }
    }

    render() {
        return html`

                    <form id="formLogin" data-toggle="validator" class="form-horizontal" role="form">

                            User ID

                                <input id="opencgaUser" value="${this.userName}" type="text" pattern="^[_\\-A-z0-9@\\.]+$" class="form-control input-login"
                                       placeholder="User ID (case sensitive)" aria-label="Recipient's username" aria-describedby="username" required data-required-error="This field is required">

                            Password

                                <input id="opencgaPassword" value="${this.password}" type="password" maxlength="30" class="form-control input-login"
                                       placeholder="Password" aria-describedby="password" required>

                            <button type="submit" class="btn btn-lg btn-primary btn-block ripple">${this.buttonText}</button>

                    </form>

        ${this.errorState?.length ? html`

                ${this.errorState.map( error => html`<p><strong>${error.name}</strong></p><p>${error.message}</p>`)}

        ` : null}
        `;
    }

}

customElements.define("opencga-login", OpencgaLogin);

<commit_msg>opencga-login small fixes<commit_after>/*
 * Copyright 2015-2016 OpenCB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {LitElement, html} from "/web_modules/lit-element.js";
import UtilsNew from "../../utilsNew.js";
import {NotificationQueue} from "../Notification.js";
import {RestResponse} from "../../clients/rest-response.js";

export default class OpencgaLogin extends LitElement {

    constructor() {
        super();

        this._init();
    }
    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            opencgaSession: {
                type: Object
            },
            buttonText: {
                type: String
            },
            userName: {
                type: String
            },
            password: {
                type: String
            },
            notifyEventMessage: {
                type: String
            }
        };
    }

    _init() {
        this.userName = "";
        this.password = "";
        this.buttonText = "Sign in";
        this.signingIn = false;
    }

    firstUpdated(changedProperties) {
        $("#formLogin").validator("update");
        $("#formLogin").validator().on("submit", e => this.submitLogin(e));
    }

    submitLogin(e) {
        // console.log("e", e);
        if (e.isDefaultPrevented()) {
            console.error("submitLogin() Error", e);
            // handle the invalid form...
            // this._clearHtmlDom(true);
        } else {
            // everything looks good!
            e.preventDefault();
            // this.dispatchEvent(new CustomEvent("signingIn"));

            const user = this.querySelector("#opencgaUser").value;
            const pass = this.querySelector("#opencgaPassword").value;

            try {
                // in case a previous error has prevented the creation of opencgaSession object (in opencgaClient.createSession()), this would be undefined
                if (this.opencgaSession) {
                    this.opencgaSession.opencgaClient.login(user, pass)
                        .then(restResponse => {

                            if (restResponse instanceof RestResponse) {
                                if (restResponse.getEvents?.("ERROR")?.length) {
                                    this.errorState = restResponse.getEvents("ERROR");
                                    new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");
                                } else if (restResponse) {
                                    this.querySelector("#opencgaUser").value = "";
                                    this.querySelector("#opencgaPassword").value = "";
                                    //console.log("response", restResponse);
                                    const token = restResponse.getResult(0).token;
                                    const decoded = jwt_decode(token); // TODO expose as module
                                    const dateExpired = new Date(decoded.exp * 1000);
                                    const validTimeSessionId = moment(dateExpired, "YYYYMMDDHHmmss").format("D MMM YY HH:mm:ss"); // TODO expose as module
                                    this.dispatchEvent(new CustomEvent("login", {
                                        detail: {
                                            userId: user,
                                            token: token
                                        },
                                        bubbles: true,
                                        composed: true
                                    }));
                                    new NotificationQueue().push("Welcome, " + user, "Your session is valid until " + validTimeSessionId, UtilsNew.MESSAGE_SUCCESS);

                                }
                            } else {
                                this.errorState = [{name: "Generic Server Error", message: "Unexpected response format. Please check your host is up and running."}];
                                new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");
                            }
                        })
                        .catch(response => {
                            // response isn't necessarily a restResponse instance
                            if (response instanceof RestResponse) {
                                if (response.getEvents?.("ERROR")?.length) {
                                    this.errorState = response.getEvents("ERROR");
                                    new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");
                                } else {
                                    this.errorState = [{name: "Generic Server Error", message: JSON.stringify(response)}];
                                    new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");
                                    /* this.dispatchEvent(new CustomEvent(_this.notifyEventMessage, {
                                        detail: {
                                            title: this.errorState[0].name,
                                            message: this.errorState[0].message,
                                            type: UtilsNew.MESSAGE_ERROR
                                        },
                                        bubbles: true,
                                        composed: true
                                    }));*/
                                }
                            } else if (response instanceof Error) {
                                this.errorState = [{name: response.name, message: response.message}];
                                new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");
                            } else {
                                this.errorState = [{name: "Generic Error", message: JSON.JSON.stringify(response)}];
                                new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");
                            }
                        }).finally(() => this.requestUpdate());
                } else {
                    new NotificationQueue().push("Error retrieving OpencgaSession", null, "ERROR");
                }
            } catch (e) {
                this.errorState = [{name: "Generic Error", message: "Please contact your administrator."}];

            }

        }

    }

    checkEnterKey(e) {
        if (e.keyCode === 13) {
            // this.login();
        }
    }

    render() {
        return html`

                    <form id="formLogin" data-toggle="validator" class="form-horizontal" role="form">

                            User ID

                                <input id="opencgaUser" value="${this.userName}" type="text" pattern="^[_\\-A-z0-9@\\.]+$" class="form-control input-login"
                                       placeholder="User ID (case sensitive)" aria-label="Recipient's username" aria-describedby="username" required data-required-error="This field is required">

                            Password

                                <input id="opencgaPassword" value="${this.password}" type="password" maxlength="30" class="form-control input-login"
                                       placeholder="Password" aria-describedby="password" required>

                            <button type="submit" class="btn btn-lg btn-primary btn-block ripple">${this.buttonText}</button>

                    </form>

        ${this.errorState?.length ? html`

                ${this.errorState.map(error => html`<p><strong>${error.name}</strong></p><p>${error.message}</p>`)}

        ` : null}
        `;
    }

}

customElements.define("opencga-login", OpencgaLogin);

<|endoftext|>


<commit_before>var RepeatingFieldItemView = Backbone.View.extend({
  initialize: function(id, value) {
    this.id    = id;
    this.value = value;
  },

  render: function() {
    var $input = $('<input/>');
    $input.val(this.value);
    this.el = $('

');
    this.el.append($input);

    return this;
  }
});

var RepeatingFieldView = Backbone.View.extend({

  initialize: function() {
    this.items = [];

    if (this.options.description) {
      this.description = this.options.description;
    }

    if (this.options.parentId) {
      this.parentId = this.options.parentId;
    }

    this.url = '/formdata/rightsnote/' + this.parentId + '/';
    this.waitingForInput = false;
  },

  newLinkEl: function() {
    var $linkEl = $('
New ' + this.description + '
')
      , self = this;

    $linkEl.click(function() {
      if (!self.waitingForInput) {
      self.waitingForInput = true;
      var $input = $('<input/>')
        , $div = $('
');
      $div.append($input);
      $(self.el).append($div);
      $input.on('change', function() {
        var value = $input.val();
        $.ajax({
          url: self.url,
          type: 'POST',
          data: {'value': value},
          success: function(result) {
            self.waitingForInput = false;
            alert('Added.');
            self.render();
          }
        });
      });

      }
    });

    return $linkEl;
  },

  appendDelHandlerToField: function(fieldEl, id) {
    var $delHandle = $('X')
      , self = this;

    $(fieldEl).append($delHandle);

    $delHandle.click(function() {
      $.ajax({
        url: self.url + '/' + id,
        type: 'DELETE',
        data: {'id': id},
        success: function(result) {
          alert('Deleted.');
          self.render();
        }
      });
    });
  },

  render: function() {
    var self = this;
    $.ajax({
      url: self.url,
      type: 'GET',
      success: function(result) {
        $(self.el)
          .empty()
          .append(self.newLinkEl());
        for(var index in result.results) {
          var fieldData = result.results[index]
            , field = new RepeatingFieldItemView(fieldData.id, fieldData.value)
            , fieldEl = field.render().el;

          self.appendDelHandlerToField(fieldEl, fieldData.id);

          $(self.el).append(fieldEl);
        }
      }
    });
    return this;
  }
});
<commit_msg>Made new button appear disabled when adding and got rid of alert.<commit_after>var RepeatingFieldItemView = Backbone.View.extend({
  initialize: function(id, value) {
    this.id    = id;
    this.value = value;
  },

  render: function() {
    var $input = $('<input/>');
    $input.val(this.value);
    this.el = $('

');
    this.el.append($input);

    return this;
  }
});

var RepeatingFieldView = Backbone.View.extend({

  initialize: function() {
    this.items = [];

    if (this.options.description) {
      this.description = this.options.description;
    }

    if (this.options.parentId) {
      this.parentId = this.options.parentId;
    }

    this.url = '/formdata/rightsnote/' + this.parentId + '/';
    this.waitingForInput = false;
  },

  newLinkEl: function() {
    var $linkEl = $('
New ' + this.description + '
')
      , self = this;

    $linkEl.click(function() {
      $(this).attr('disabled', 'true');
      if (!self.waitingForInput) {
      self.waitingForInput = true;
      var $input = $('<input/>')
        , $div = $('
');
      $div.append($input);
      $(self.el).append($div);
      $input.on('change', function() {
        var value = $input.val();
        $.ajax({
          url: self.url,
          type: 'POST',
          data: {'value': value},
          success: function(result) {
            $(self).attr('disabled', 'false');
            self.waitingForInput = false;
            self.render();
          }
        });
      });

      }
    });

    return $linkEl;
  },

  appendDelHandlerToField: function(fieldEl, id) {
    var $delHandle = $('X')
      , self = this;

    $(fieldEl).append($delHandle);

    $delHandle.click(function() {
      $.ajax({
        url: self.url + '/' + id,
        type: 'DELETE',
        data: {'id': id},
        success: function(result) {
          alert('Deleted.');
          self.render();
        }
      });
    });
  },

  render: function() {
    var self = this;
    $.ajax({
      url: self.url,
      type: 'GET',
      success: function(result) {
        $(self.el)
          .empty()
          .append(self.newLinkEl());
        for(var index in result.results) {
          var fieldData = result.results[index]
            , field = new RepeatingFieldItemView(fieldData.id, fieldData.value)
            , fieldEl = field.render().el;

          self.appendDelHandlerToField(fieldEl, fieldData.id);

          $(self.el).append(fieldEl);
        }
      }
    });
    return this;
  }
});
<|endoftext|>


<commit_before>let ArraySet = require('./ArraySet'),
    DFARunner = require('./DFARunner');

class DFANode {
    constructor(nfa_node_set, id) {
        this.nfa_node_set = nfa_node_set;
        this.id = id;
        this.transitions = {};
        this.acceptState = -1;
    }

    getTransition(ch) {
        return (this.transitions.hasOwnProperty(ch)) ? this.transitions[ch] : null;
    }

    setTransition(ch, dfa_node) {
        this.transitions[ch] = dfa_node;
    }

    toString() {
        var items = this.nfa_node_set.items;

        return items
            .sort((a, b) => a.index - b.index)
            .map(item => String(item.id))
            .join(",");
    }
}

class NFAGraphConverter {
    constructor() {
        this.nfa_nodes = null;
        this.dfa_nodes = null;
    }

    createDFANode(nfa_node_set) {
        let id = this.dfa_nodes.length;
        let node = new DFANode(nfa_node_set, id);

        this.dfa_nodes.push(node);

        return node;
    }

    convert(nfa) {
        this.nfa_nodes = nfa.getNodes();
        this.dfa_nodes = [];

        this.createDFANode(
            this.getEpsilonReachable(
                nfa.start
            )
        );

        // keep processing dfa nodes until we reach the end of the list. Note
        // that the list may grow with each iteration, so we can't cache the
        // node list length nor use forEach
        for (var i = 0; i < this.dfa_nodes.length; i++) {
            this.processTransitions(this.dfa_nodes[i]);
        }

        return new DFARunner(this.generateTable());
    }

    getEpsilonReachable(nfa_node) {
        var result = new ArraySet();

        // we can always get to ourself
        result.add(nfa_node);

        // keep expanding the result set, adding epsilon reachable nodes for
        // each new node added to the set
        for (var i = 0; i < result.size; i++) {
            var current_node = result.item(i);

            current_node.epsilon.forEach(item => result.add(item));
        }

        return result;
    }

    getTransitionReachable(nfa_node, ch) {
        var result;

        if (nfa_node.hasCharacter(ch)) {
            result = this.getEpsilonReachable(nfa_node.next);
        }
        else {
            result = new ArraySet();
        }

        return result;
    }

    getDfaNodeByReachableStates(reachable) {
        var result = null;

        for (var i = 0; i < this.dfa_nodes.length; i++) {
            var dfa_node = this.dfa_nodes[i];

            if (dfa_node.nfa_node_set.equals(reachable)) {
                result = dfa_node;
                break;
            }
        }

        return result;
    }

    processTransitions(dfa_node) {
        var nfa_nodes = dfa_node.nfa_node_set;

        for (var i = 0; i < 256; i++) {
            var reachable = new ArraySet();
            var ch = String.fromCharCode(i);

            for (var j = 0; j < nfa_nodes.size; j++) {
                var nfa_node = nfa_nodes.item(j);

                reachable.union(this.getTransitionReachable(nfa_node, ch));

                if (nfa_node.acceptState != -1 && dfa_node.acceptState != nfa_node.acceptState) {
                    var current = dfa_node.acceptState;
                    var candidate = nfa_node.acceptState;
                    var newValue = (current != -1) ? Math.min(current, candidate) : candidate;

                    if (current != newValue) {
                        dfa_node.acceptState = newValue;
                        //print("(" + current + "," + candidate + ") => " + newValue);
                    }
                }
            }

            if (reachable.size > 0) {
                var target_dfa_node = this.getDfaNodeByReachableStates(reachable);

                if (target_dfa_node === null) {
                    target_dfa_node = this.createDFANode(reachable);
                }

                dfa_node.setTransition(ch, target_dfa_node);
            }
            else {
                dfa_node.setTransition(ch, null);
            }
        }
    }

    generateTable() {
        var table = [];

        function emitMORLE(dfa_node) {
            var emitCount = 0,
                lastValue = null,
                count = 0;

            var result = [];

            function emit() {
                if (lastValue == -1) {
                    result.push(-count);
                }
                else if (count == 1) {
                    result.push(lastValue);
                }
                else {
                    result.push((count << 8) | lastValue);
                }

                emitCount++;
            }

            for (var i = 0; i < 256; i++) {
                var ch = String.fromCharCode(i);
                var target_node = dfa_node.getTransition(ch);
                var value = (target_node === null) ? -1 : target_node.id;

                if (lastValue === null) {
                    lastValue = value;
                    count = 1;
                } else if (lastValue == value) {
                    count++;
                } else {
                    emit();

                    lastValue = value;
                    count = 1;
                }
            }

            emit();

            return result;
        }

        this.dfa_nodes.forEach(dfa_node => {
            var acceptState = dfa_node.acceptState;

            // Minus One Run-Length Encoding
            var entry = emitMORLE(dfa_node);

            table.push([entry, acceptState]);
        });

        return table;
    }
}

module.exports = NFAGraphConverter;
<commit_msg>Minor stylistic change<commit_after>let ArraySet = require('./ArraySet'),
    DFARunner = require('./DFARunner');

class DFANode {
    constructor(nfa_node_set, id) {
        this.nfa_node_set = nfa_node_set;
        this.id = id;
        this.transitions = {};
        this.acceptState = -1;
    }

    getTransition(ch) {
        return (this.transitions.hasOwnProperty(ch)) ? this.transitions[ch] : null;
    }

    setTransition(ch, dfa_node) {
        this.transitions[ch] = dfa_node;
    }

    toString() {
        var items = this.nfa_node_set.items;

        return items
            .sort((a, b) => a.index - b.index)
            .map(item => String(item.id))
            .join(",");
    }
}

class NFAGraphConverter {
    constructor() {
        this.nfa_nodes = null;
        this.dfa_nodes = null;
    }

    createDFANode(nfa_node_set) {
        let id = this.dfa_nodes.length;
        let node = new DFANode(nfa_node_set, id);

        this.dfa_nodes.push(node);

        return node;
    }

    convert(nfa) {
        this.nfa_nodes = nfa.getNodes();
        this.dfa_nodes = [];

        this.createDFANode(
            this.getEpsilonReachable(
                nfa.start
            )
        );

        // keep processing dfa nodes until we reach the end of the list. Note
        // that the list may grow with each iteration, so we can't cache the
        // node list length nor use forEach
        for (var i = 0; i < this.dfa_nodes.length; i++) {
            this.processTransitions(this.dfa_nodes[i]);
        }

        return new DFARunner(this.generateTable());
    }

    getEpsilonReachable(nfa_node) {
        var result = new ArraySet();

        // we can always get to ourself
        result.add(nfa_node);

        // keep expanding the result set, adding epsilon reachable nodes for
        // each new node added to the set
        for (var i = 0; i < result.size; i++) {
            var current_node = result.item(i);

            current_node.epsilon.forEach(item => result.add(item));
        }

        return result;
    }

    getTransitionReachable(nfa_node, ch) {
        var result;

        if (nfa_node.hasCharacter(ch)) {
            result = this.getEpsilonReachable(nfa_node.next);
        }
        else {
            result = new ArraySet();
        }

        return result;
    }

    getDfaNodeByReachableStates(reachable) {
        var result = null;

        for (var i = 0; i < this.dfa_nodes.length; i++) {
            var dfa_node = this.dfa_nodes[i];

            if (dfa_node.nfa_node_set.equals(reachable)) {
                result = dfa_node;
                break;
            }
        }

        return result;
    }

    processTransitions(dfa_node) {
        var nfa_nodes = dfa_node.nfa_node_set;

        for (var i = 0; i < 256; i++) {
            var reachable = new ArraySet();
            var ch = String.fromCharCode(i);

            for (var j = 0; j < nfa_nodes.size; j++) {
                var nfa_node = nfa_nodes.item(j);

                reachable.union(this.getTransitionReachable(nfa_node, ch));

                if (nfa_node.acceptState != -1 && dfa_node.acceptState != nfa_node.acceptState) {
                    var current = dfa_node.acceptState;
                    var candidate = nfa_node.acceptState;
                    var newValue = (current != -1) ? Math.min(current, candidate) : candidate;

                    if (current != newValue) {
                        dfa_node.acceptState = newValue;
                        //print("(" + current + "," + candidate + ") => " + newValue);
                    }
                }
            }

            if (reachable.size > 0) {
                var target_dfa_node = this.getDfaNodeByReachableStates(reachable);

                if (target_dfa_node === null) {
                    target_dfa_node = this.createDFANode(reachable);
                }

                dfa_node.setTransition(ch, target_dfa_node);
            }
            else {
                dfa_node.setTransition(ch, null);
            }
        }
    }

    generateTable() {
        var table = [];

        function emitMORLE(dfa_node) {
            var emitCount = 0,
                lastValue = null,
                count = 0;

            var result = [];

            function emit() {
                if (lastValue == -1) {
                    result.push(-count);
                }
                else if (count == 1) {
                    result.push(lastValue);
                }
                else {
                    result.push((count << 8) | lastValue);
                }

                emitCount++;
            }

            for (var i = 0; i < 256; i++) {
                var ch = String.fromCharCode(i);
                var target_node = dfa_node.getTransition(ch);
                var value = (target_node === null) ? -1 : target_node.id;

                if (lastValue === null) {
                    lastValue = value;
                    count = 1;
                }
                else if (lastValue == value) {
                    count++;
                }
                else {
                    emit();

                    lastValue = value;
                    count = 1;
                }
            }

            emit();

            return result;
        }

        this.dfa_nodes.forEach(dfa_node => {
            var acceptState = dfa_node.acceptState;

            // Minus One Run-Length Encoding
            var entry = emitMORLE(dfa_node);

            table.push([entry, acceptState]);
        });

        return table;
    }
}

module.exports = NFAGraphConverter;
<|endoftext|>


<commit_before>angular.module('DashboardGraphs')
  .directive('jobStatusGraph', ['$rootScope', '$compile', '$location' , '$window', 'Wait', 'adjustGraphSize', 'jobStatusGraphData',
        function ($rootScope, $compile , $location, $window, Wait, adjustGraphSize, jobStatusGraphData) {
            return {
              restrict: 'E',
              templateUrl: '/static/partials/job_status_graph.html',
              link: link
            };

          function link(scope, element, attr) {
            var html, url, job_status_chart,
            period="month",
            job_type="all";

            var cleanup = angular.noop;

            var data;
            scope.$watch(attr.data, function(value) {
              if (value) {
                scope.$emit('graphDataReady', value);
              }
            });

            scope.$on('$destroy', cleanup);

            cleanup = _.compose(
              [ cleanup,
            ]);

            function createGraph(period, jobtype){
              jobStatusGraphData.get(period, jobtype).then(function(data) {
                scope.$emit('graphDataReady', data);
              });
            }

            var w = angular.element($window);

            angular.element($window).on('resize', function() {
              adjustGraphSize(job_status_chart, element);
            });

            element.on('$destroy', function() {
              angular.element($window).off('resize', adjustGraphSize);
            });

            if (scope.removeGraphDataReady) {
              scope.removeGraphDataReady();
            }

            var job_status_chart;
            scope.removeGraphDataReady = scope.$on('graphDataReady', function (e, data) {

              var timeFormat, graphData = [
                {
                "color": "#00aa00",
                "key": "Successful",
                "values": data.jobs.successful
              },
              {
                "key" : "Failed" ,
                "color" : "#aa0000",
                "values": data.jobs.failed
              }
              ];

              if(period==="day"){
                timeFormat="%H:%M";
              }
              else {
                timeFormat = '%m/%d';
              }
              graphData.map(function(series) {
                series.values = series.values.map(function(d) {
                  return {
                    x: d[0],
                    y: d[1]
                  };
                });
                return series;
              });

              job_status_chart = nv.models.lineChart()
              .margin({top: 5, right: 75, bottom: 50, left: 85})  //Adjust chart margins to give the x-axis some breathing room.
              .x(function(d,i) { return i; })
              .useInteractiveGuideline(true)  //We want nice looking tooltips and a guideline!
              .showLegend(true)       //Show the legend, allowing users to turn on/off line series.
              .showYAxis(true)        //Show the y-axis
              .showXAxis(true)        //Show the x-axis
              //  .width(width)
              // .height(height)
              ;

              var width = $('.graph-container').width(); // nv.utils.windowSize().width/3,
              var height = $('.graph-container').height()*0.7; //nv.utils.windowSize().height/5,

              job_status_chart.xAxis
              .axisLabel("Time")//.showMaxMin(true)
              .tickFormat(function(d) {
                var dx = graphData[0].values[d] && graphData[0].values[d].x || 0;
                return dx ? d3.time.format(timeFormat)(new Date(Number(dx+'000'))) : '';
              });

              job_status_chart.yAxis     //Chart y-axis settings
              .axisLabel('Jobs')
              .tickFormat(d3.format('.f'));

              d3.select(element.find('svg')[0])
              .datum(graphData)
              // .attr('width', width)
              // .attr('height', height)
              // .transition().duration(100)
              .call(job_status_chart)
              .style({
                // 'width': width,
                // 'height': height,
                "font-family": 'Open Sans',
                "font-style": "normal",
                "font-weight":400,
                "src": "url(/static/fonts/OpenSans-Regular.ttf)"
              });

              // when the Period drop down filter is used, create a new graph based on the
              d3.selectAll(element.find(".n"))
              .on("click", function() {
                period = this.getAttribute("id");
                $('#period-dropdown').replaceWith(""+this.text+"\n");

                createGraph(period, job_type);
              });

              //On click, update with new data
              d3.selectAll(element.find(".m"))
              .on("click", function() {
                job_type = this.getAttribute("id");
                $('#type-dropdown').replaceWith(""+this.text+"\n");

                createGraph(period, job_type);
              });

              adjustGraphSize(job_status_chart, element);

              return job_status_chart;

            });
          }
        }]);
<commit_msg>Fix errors resizing job status graph<commit_after>angular.module('DashboardGraphs')
  .directive('jobStatusGraph', ['$rootScope', '$compile', '$location' , '$window', 'Wait', 'adjustGraphSize', 'jobStatusGraphData',
        function ($rootScope, $compile , $location, $window, Wait, adjustGraphSize, jobStatusGraphData) {
            return {
              restrict: 'E',
              templateUrl: '/static/partials/job_status_graph.html',
              link: link
            };

          function link(scope, element, attr) {
            var html;
            var url;
            var job_status_chart;
            var job_status_chart;
            var cleanup = angular.noop;

            scope.period="month";
            scope.jobType="all";

            var data;
            scope.$watch(attr.data, function(value) {
              if (value) {
                createGraph(value, scope.period, scope.jobType);
              }
            });

            function createGraph(data, period, jobtype){

              scope.period = period;
              scope.jobType = jobtype;

                var timeFormat, graphData = [
                  {
                  "color": "#00aa00",
                  "key": "Successful",
                  "values": data.jobs.successful
                },
                {
                  "key" : "Failed" ,
                  "color" : "#aa0000",
                  "values": data.jobs.failed
                }
                ];

                if(period==="day") {
                  timeFormat="%H:%M";
                }
                else {
                  timeFormat = '%m/%d';
                }
                graphData.map(function(series) {
                  series.values = series.values.map(function(d) {
                    return {
                      x: d[0],
                      y: d[1]
                    };
                  });
                  return series;
                });

                job_status_chart = nv.models.lineChart()
                .margin({top: 5, right: 75, bottom: 50, left: 85})  //Adjust chart margins to give the x-axis some breathing room.
                .x(function(d,i) { return i; })
                .useInteractiveGuideline(true)  //We want nice looking tooltips and a guideline!
                .showLegend(true)       //Show the legend, allowing users to turn on/off line series.
                .showYAxis(true)        //Show the y-axis
                .showXAxis(true)        //Show the x-axis
                //  .width(width)
                // .height(height)
                ;

                var width = $('.graph-container').width(); // nv.utils.windowSize().width/3,
                var height = $('.graph-container').height()*0.7; //nv.utils.windowSize().height/5,

                job_status_chart.xAxis
                .axisLabel("Time")//.showMaxMin(true)
                .tickFormat(function(d) {
                  var dx = graphData[0].values[d] && graphData[0].values[d].x || 0;
                  return dx ? d3.time.format(timeFormat)(new Date(Number(dx+'000'))) : '';
                });

                job_status_chart.yAxis     //Chart y-axis settings
                .axisLabel('Jobs')
                .tickFormat(d3.format('.f'));

                d3.select(element.find('svg')[0])
                .datum(graphData)
                // .attr('width', width)
                // .attr('height', height)
                // .transition().duration(100)
                .call(job_status_chart)
                .style({
                  // 'width': width,
                  // 'height': height,
                  "font-family": 'Open Sans',
                  "font-style": "normal",
                  "font-weight":400,
                  "src": "url(/static/fonts/OpenSans-Regular.ttf)"
                });

                // when the Period drop down filter is used, create a new graph based on the
                d3.selectAll(element.find(".n"))
                .on("click", function() {
                  period = this.getAttribute("id");
                  $('#period-dropdown').replaceWith(""+this.text+"\n");

                  createGraph(data, period, job_type);
                });

                //On click, update with new data
                d3.selectAll(element.find(".m"))
                .on("click", function() {
                  job_type = this.getAttribute("id");
                  $('#type-dropdown').replaceWith(""+this.text+"\n");

                  createGraph(data, period, job_type);
                });

                adjustGraphSize(job_status_chart, element);

            }

            var w = angular.element($window);

            angular.element($window).on('resize', function() {
              adjustGraphSize(job_status_chart, element);
            });

            element.on('$destroy', function() {
              angular.element($window).off('resize', adjustGraphSize);
            });

            if (scope.removeGraphDataReady) {
              scope.removeGraphDataReady();
            }

            scope.removeGraphDataReady = scope.$on('graphDataReady', function (e, data) {

              return job_status_chart;

            });
          }
        }]);
<|endoftext|>


<commit_before>(function(){

var ui = angular.module('axelor.ui');
var widgets = {};
var registry = {};

/**
 * Perform common compile operations.
 *
 * example:
 *    ui.formCompile.call(this, element, attrs)
 */
ui.formCompile = function(element, attrs, linkerFn) {

	var showTitle = attrs.showTitle || this.showTitle,
		title = attrs.title || attrs.field;

	attrs.$set('show-title', showTitle, true, 'x-show-title');
	if (title) {
		attrs.$set('title', title, true, 'x-title');
	}
	if (this.cellCss) {
		attrs.$set('x-cell-css', this.cellCss);
	}

	function link(scope, element, attrs, controller) {

		element.addClass(this.css).parent().addClass(this.cellCss);
		element.data('$attrs', attrs); // store the attrs object for event handlers

		if (element.is('.input-append,.picker-input')) { // focus the first input field
			element.on('click', '.btn, i', function(){
				element.find('input:first').focus();
			});
		}

		var field = scope.getViewDef ? scope.getViewDef(element) || {}: {};
		var props = _.pick(field, ['readonly', 'required', 'hidden']);
		var state = _.clone(props);

		if (field.css) {
			element.addClass(field.css);
		}

		scope.$events = {};
		scope.field = field || {};

		scope.attr = function(name) {
			if (arguments.length > 1) {
				state[name] = arguments[1];
			}
			return state[name];
		};

		function resetState() {
			state = _.clone(props);
		}

		scope.$on("on:new", function(){
			resetState();
		});
		scope.$on("on:edit", function(){
			resetState();
		});

		scope.isRequired = function() {
			return this.attr("required") || false;
		};

		scope.isReadonly = function() {
			var parent = this.$parent;
			if (parent && parent.isReadonly && parent.isReadonly()) {
				return true;
			}
			if (!scope.isEditable()) {
				return true;
			}
			return this.attr("readonly") || false;
		};

		scope.isHidden = function() {
			return this.attr("hidden") || false;
		};

		scope.fireAction = function(name, success, error) {
			var handler = this.$events[name];
			if (handler) {
				return handler().then(success, error);
			}
		};

		if (angular.isFunction(this._link_internal)) {
			this._link_internal.call(this, scope, element, attrs, controller);
		}
		if (angular.isFunction(linkerFn) && angular.isFunction(this.transcludeSelect)) {
			var ref = this.transcludeSelect(element);
			linkerFn(scope.$new(), function(clone){
				ref.append(clone);
			});
		}
		if (angular.isFunction(this.init)) {
			this.init.call(this, scope);
		}
		if (angular.isFunction(this.link)) {
			this.link.call(this, scope, element, attrs, controller);
		}

		this.prepare(scope, element, attrs, controller);
	}

	return angular.bind(this, link);
};

ui.formDirective = function(name, object) {

	if (object.compile === undefined) {
		object.compile = angular.bind(object, function(element, attrs){
			return ui.formCompile.apply(this, arguments);
		});
	}

	if (object.restrict === undefined) {
		object.restrict = 'EA';
	}

	if (object.template && object.replace == undefined) {
		object.replace = true;
	}

	if (object.cellCss === undefined) {
		object.cellCss = 'form-item';
	}

	if (object.scope === undefined) {
		object.scope = true;
	}

	if (object.require === undefined) {
		object.require = '?ngModel';
	}

	function prepare_templates($compile) {

		object.prepare = angular.bind(object, function(scope, element, attrs, model) {

			var self = this;

			if (this.template_editable == null && this.template_readonly == null) {
				return;
			}

			scope.$elem_editable = null;
			scope.$elem_readonly = null;

			function showEditable() {
				if (!self.template_editable) {
					return false;
				}
				if (scope.$elem_editable == null) {
					scope.$elem_editable = $compile(self.template_editable)(scope);
					if (self.link_editable) {
						self.link_editable.call(self, scope, scope.$elem_editable, attrs, model);
					}
					if (scope.validate) {
						model.$parsers.unshift(function(viewValue) {
							var valid = scope.validate(viewValue);
							model.$setValidity('valid', valid);
							return valid ? viewValue : undefined;
						});
					}
				}
				if (scope.$elem_readonly) {
					scope.$elem_readonly.detach();
				}
				element.append(scope.$elem_editable);
				if (scope.$render_editable) scope.$render_editable();
				return true;
			}

			function showReadonly() {
				if (!self.template_readonly) {
					return false;
				}
				if (scope.$elem_readonly == null) {
					scope.$elem_readonly = $compile(self.template_readonly)(scope);
					if (self.link_readonly) {
						self.link_readonly.call(self, scope, scope.$elem_readonly, attrs, model);
					}
				}
				if (scope.$elem_editable) {
					scope.$elem_editable.detach();
				}
				element.append(scope.$elem_readonly);
				return true;
			}

			scope.$watch("isReadonly()", function(readonly) {
				element.toggleClass("readonly", readonly);
				if (readonly && showReadonly()) {
					return;
				}
				return showEditable();
			});
			scope.$watch("isHidden()", function(hidden) {
				var elem = element,
					parent = elem.parent('td'),
					label = elem.data('label') || $(),
					label_parent = label.parent('td');
				if (parent.size() == 0)
					parent = elem;
				if (label_parent.size())
					label = label_parent;
				return hidden ? parent.add(label).hide() : parent.add(label).show();
			});
			scope.$watch("isRequired()", function(required) {
				var elem = element,
					label = elem.data('label') || $();

				if (label) {
					required ? label.addClass('required') : label.removeClass('required');
				}
				attrs.$set('required', required);
			});

		});

		return object;
	}

	return ui.directive(name, ['$compile', function($compile) {
		return prepare_templates($compile);
	}]);
};

var FormItem = {

	css: 'form-item',

	cellCss: 'form-item'
};

var FormInput = {

	_link_internal: function(scope, element, attrs, model) {

		scope.format = function(value) {
			return value;
		};

		scope.parse = function(value) {
			return value;
		};

		scope.validate = function(value) {
			return true;
		};

		scope.setValue = function(value, fireOnChange) {

			var val = this.parse(value);
			var txt = this.format(value);
			var onChange = this.$events.onChange;

			model.$setViewValue(val);
			scope.text = txt;

			setTimeout(function(){
				model.$render();
			});

			if (onChange && fireOnChange) {
				setTimeout(onChange);
			}
		};

		scope.getValue = function() {
			if (model != null) {
				return model.$viewValue;
			}
			return null;
		};

		scope.getText = function() {
			return this.text;
		};

		scope.initValue = function(value) {
			this.text = this.format(value);
		};

		model.$render = function() {
			scope.initValue(scope.getValue());
			if (scope.$render_editable) {
				scope.$render_editable();
			}
			if (scope.$render_readonly) {
				scope.$render_readonly();
			}
		};
	},

	link: function(scope, element, attrs, model) {

	},

	link_editable: function(scope, element, attrs, model) {

		scope.$render_editable = function() {
			var value = this.format(this.getValue());
			element.val(value);
		};

		if (element.is(':input')) {

			var onChange = scope.$events.onChange || angular.noop,
				onChangePending = false;

			element.change(function(e){
				scope.setValue(element.val());
				scope.$apply();
				onChangePending = true;
			});

			element.blur(function(e){
				if (onChangePending) {
					onChangePending = false;
					setTimeout(onChange);
				}
			});
		}

		scope.$render_editable();
	},

	link_readonly: function(scope, element, attrs, model) {

	},

	template_editable: '<input type="text">',

	template_readonly: '{{text}}',

	template: ''
};

function inherit(array) {

	var args = _.chain(array).rest(1).flatten(true).value();
	var last = _.last(args);
	var base = null;
	var obj = {};

	_.chain(args).each(function(source, index) {
		if (_.isString(source)) {
			source = widgets[source];
		}
		if (index === args.length - 2) {
			base = source;
		}
		_.extend(obj, source);
	});

	if (base == null) {
		return obj;
	}

	function overridden(name) {
		return name !== "controller" &&
			_.isFunction(last[name]) && !last[name].$inject &&
			_.isFunction(base[name]);
	};

	for(var name in last) {
		if (overridden(name)) {
			obj[name] = (function(name, fn){
				return function() {
					var tmp = this._super;
					this._super = base[name];
					var ret = fn.apply(this, arguments);
					this._super = tmp;
					return ret;
				};
			})(name, obj[name]);
		}
	}

	return obj;
}

ui.formWidget = function(name, object) {
	var obj = inherit(arguments);
	var widget = _.str.titleize(name.replace(/^ui/, ''));
	var directive = "ui" + widget;

	registry[directive] = directive;
	_.each(obj.widgets, function(alias){
		registry[alias] = directive;
	});
	delete obj.widgets;

	widgets[widget] = _.clone(obj);

	ui.formDirective(directive, obj);

	return obj;
};

ui.formItem = function(name, object) {
	return ui.formWidget(name, FormItem, _.rest(arguments, 1));
};

ui.formInput = function(name, object) {
	return ui.formWidget(name, FormItem, FormInput, _.rest(arguments, 1));
};

ui.getWidget = function(type) {
	var name = _.chain(type).camelize().capitalize().value();
	var widget = registry["ui" + name] || registry[name];
	if (widget) {
		widget = widget.replace(/^ui/, '');
		return _.chain(widget).underscored().dasherize().value();
	}
	return null;
};

})(this);
<commit_msg>Fixed input value change issue.<commit_after>(function(){

var ui = angular.module('axelor.ui');
var widgets = {};
var registry = {};

/**
 * Perform common compile operations.
 *
 * example:
 *    ui.formCompile.call(this, element, attrs)
 */
ui.formCompile = function(element, attrs, linkerFn) {

	var showTitle = attrs.showTitle || this.showTitle,
		title = attrs.title || attrs.field;

	attrs.$set('show-title', showTitle, true, 'x-show-title');
	if (title) {
		attrs.$set('title', title, true, 'x-title');
	}
	if (this.cellCss) {
		attrs.$set('x-cell-css', this.cellCss);
	}

	function link(scope, element, attrs, controller) {

		element.addClass(this.css).parent().addClass(this.cellCss);
		element.data('$attrs', attrs); // store the attrs object for event handlers

		if (element.is('.input-append,.picker-input')) { // focus the first input field
			element.on('click', '.btn, i', function(){
				element.find('input:first').focus();
			});
		}

		var field = scope.getViewDef ? scope.getViewDef(element) || {}: {};
		var props = _.pick(field, ['readonly', 'required', 'hidden']);
		var state = _.clone(props);

		if (field.css) {
			element.addClass(field.css);
		}

		scope.$events = {};
		scope.field = field || {};

		scope.attr = function(name) {
			if (arguments.length > 1) {
				state[name] = arguments[1];
			}
			return state[name];
		};

		function resetState() {
			state = _.clone(props);
		}

		scope.$on("on:new", function(){
			resetState();
		});
		scope.$on("on:edit", function(){
			resetState();
		});

		scope.isRequired = function() {
			return this.attr("required") || false;
		};

		scope.isReadonly = function() {
			var parent = this.$parent;
			if (parent && parent.isReadonly && parent.isReadonly()) {
				return true;
			}
			if (!scope.isEditable()) {
				return true;
			}
			return this.attr("readonly") || false;
		};

		scope.isHidden = function() {
			return this.attr("hidden") || false;
		};

		scope.fireAction = function(name, success, error) {
			var handler = this.$events[name];
			if (handler) {
				return handler().then(success, error);
			}
		};

		if (angular.isFunction(this._link_internal)) {
			this._link_internal.call(this, scope, element, attrs, controller);
		}
		if (angular.isFunction(linkerFn) && angular.isFunction(this.transcludeSelect)) {
			var ref = this.transcludeSelect(element);
			linkerFn(scope.$new(), function(clone){
				ref.append(clone);
			});
		}
		if (angular.isFunction(this.init)) {
			this.init.call(this, scope);
		}
		if (angular.isFunction(this.link)) {
			this.link.call(this, scope, element, attrs, controller);
		}

		this.prepare(scope, element, attrs, controller);
	}

	return angular.bind(this, link);
};

ui.formDirective = function(name, object) {

	if (object.compile === undefined) {
		object.compile = angular.bind(object, function(element, attrs){
			return ui.formCompile.apply(this, arguments);
		});
	}

	if (object.restrict === undefined) {
		object.restrict = 'EA';
	}

	if (object.template && object.replace == undefined) {
		object.replace = true;
	}

	if (object.cellCss === undefined) {
		object.cellCss = 'form-item';
	}

	if (object.scope === undefined) {
		object.scope = true;
	}

	if (object.require === undefined) {
		object.require = '?ngModel';
	}

	function prepare_templates($compile) {

		object.prepare = angular.bind(object, function(scope, element, attrs, model) {

			var self = this;

			if (this.template_editable == null && this.template_readonly == null) {
				return;
			}

			scope.$elem_editable = null;
			scope.$elem_readonly = null;

			function showEditable() {
				if (!self.template_editable) {
					return false;
				}
				if (scope.$elem_editable == null) {
					scope.$elem_editable = $compile(self.template_editable)(scope);
					if (self.link_editable) {
						self.link_editable.call(self, scope, scope.$elem_editable, attrs, model);
					}
					if (scope.validate) {
						model.$parsers.unshift(function(viewValue) {
							var valid = scope.validate(viewValue);
							model.$setValidity('valid', valid);
							return valid ? viewValue : undefined;
						});
					}
				}
				if (scope.$elem_readonly) {
					scope.$elem_readonly.detach();
				}
				element.append(scope.$elem_editable);
				if (scope.$render_editable) scope.$render_editable();
				return true;
			}

			function showReadonly() {
				if (!self.template_readonly) {
					return false;
				}
				if (scope.$elem_readonly == null) {
					scope.$elem_readonly = $compile(self.template_readonly)(scope);
					if (self.link_readonly) {
						self.link_readonly.call(self, scope, scope.$elem_readonly, attrs, model);
					}
				}
				if (scope.$elem_editable) {
					scope.$elem_editable.detach();
				}
				element.append(scope.$elem_readonly);
				return true;
			}

			scope.$watch("isReadonly()", function(readonly) {
				element.toggleClass("readonly", readonly);
				if (readonly && showReadonly()) {
					return;
				}
				return showEditable();
			});
			scope.$watch("isHidden()", function(hidden) {
				var elem = element,
					parent = elem.parent('td'),
					label = elem.data('label') || $(),
					label_parent = label.parent('td');
				if (parent.size() == 0)
					parent = elem;
				if (label_parent.size())
					label = label_parent;
				return hidden ? parent.add(label).hide() : parent.add(label).show();
			});
			scope.$watch("isRequired()", function(required) {
				var elem = element,
					label = elem.data('label') || $();

				if (label) {
					required ? label.addClass('required') : label.removeClass('required');
				}
				attrs.$set('required', required);
			});

		});

		return object;
	}

	return ui.directive(name, ['$compile', function($compile) {
		return prepare_templates($compile);
	}]);
};

var FormItem = {

	css: 'form-item',

	cellCss: 'form-item'
};

var FormInput = {

	_link_internal: function(scope, element, attrs, model) {

		scope.format = function(value) {
			return value;
		};

		scope.parse = function(value) {
			return value;
		};

		scope.validate = function(value) {
			return true;
		};

		scope.setValue = function(value, fireOnChange) {

			var val = this.parse(value);
			var txt = this.format(value);
			var onChange = this.$events.onChange;

			model.$setViewValue(val);
			scope.text = txt;

			setTimeout(function(){
				model.$render();
			});

			if (onChange && fireOnChange) {
				setTimeout(onChange);
			}
		};

		scope.getValue = function() {
			if (model != null) {
				return model.$viewValue;
			}
			return null;
		};

		scope.getText = function() {
			return this.text;
		};

		scope.initValue = function(value) {
			this.text = this.format(value);
		};

		model.$render = function() {
			scope.initValue(scope.getValue());
			if (scope.$render_editable) {
				scope.$render_editable();
			}
			if (scope.$render_readonly) {
				scope.$render_readonly();
			}
		};
	},

	link: function(scope, element, attrs, model) {

	},

	link_editable: function(scope, element, attrs, model) {

		scope.$render_editable = function() {
			var value = this.format(this.getValue());
			element.val(value);
		};

		if (element.is(':input')) {

			var onChange = scope.$events.onChange || angular.noop,
				onChangePending = false;

			function listener() {
				var value = _.str.trim(element.val()) || null;
				if (value !== model.$viewValue) {
					scope.setValue(value);
					scope.$apply();
					onChangePending = true;
				}
			}

			var timeout = null;

			element.keydown(function(e) {
				var key = e.keyCode;

				// ignore
			    //    command            modifiers                   arrows
			    if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;

			    if (!timeout) {
			    	timeout = setTimeout(function(){
			    		listener();
			    		timeout = null;
			    	});
			    }
			});

			element.change(listener);

			element.blur(function(e){
				if (onChangePending) {
					onChangePending = false;
					setTimeout(onChange);
				}
			});
		}

		scope.$render_editable();
	},

	link_readonly: function(scope, element, attrs, model) {

	},

	template_editable: '<input type="text">',

	template_readonly: '{{text}}',

	template: ''
};

function inherit(array) {

	var args = _.chain(array).rest(1).flatten(true).value();
	var last = _.last(args);
	var base = null;
	var obj = {};

	_.chain(args).each(function(source, index) {
		if (_.isString(source)) {
			source = widgets[source];
		}
		if (index === args.length - 2) {
			base = source;
		}
		_.extend(obj, source);
	});

	if (base == null) {
		return obj;
	}

	function overridden(name) {
		return name !== "controller" &&
			_.isFunction(last[name]) && !last[name].$inject &&
			_.isFunction(base[name]);
	};

	for(var name in last) {
		if (overridden(name)) {
			obj[name] = (function(name, fn){
				return function() {
					var tmp = this._super;
					this._super = base[name];
					var ret = fn.apply(this, arguments);
					this._super = tmp;
					return ret;
				};
			})(name, obj[name]);
		}
	}

	return obj;
}

ui.formWidget = function(name, object) {
	var obj = inherit(arguments);
	var widget = _.str.titleize(name.replace(/^ui/, ''));
	var directive = "ui" + widget;

	registry[directive] = directive;
	_.each(obj.widgets, function(alias){
		registry[alias] = directive;
	});
	delete obj.widgets;

	widgets[widget] = _.clone(obj);

	ui.formDirective(directive, obj);

	return obj;
};

ui.formItem = function(name, object) {
	return ui.formWidget(name, FormItem, _.rest(arguments, 1));
};

ui.formInput = function(name, object) {
	return ui.formWidget(name, FormItem, FormInput, _.rest(arguments, 1));
};

ui.getWidget = function(type) {
	var name = _.chain(type).camelize().capitalize().value();
	var widget = registry["ui" + name] || registry[name];
	if (widget) {
		widget = widget.replace(/^ui/, '');
		return _.chain(widget).underscored().dasherize().value();
	}
	return null;
};

})(this);
<|endoftext|>