Source: @@components/Yasgui.js

/**
 * @file Container for the YASGUI SPARQL editor tool. Reflects changes made to the application model and allows
 * for direct query edits.
 * @module @@components/Yasgui
 */
import React, { Component } from 'react';
import { connect, Provider } from 'react-redux';
import {
	getQuery,
	getEndpoint,
	getLimit,
	getLimitEnabled,
	getInstance,
	getCartesianProduct,
	getModelQuery
} from '@@selectors';
import styled from '@emotion/styled';
import YASGUI from '@triply/yasgui';
import * as ModelState from '@@app-state/model/state';
import * as YasguiState from '@@app-state/yasgui/state';
import { dispatchSet, getState, store } from '@@app-state';
import { Alert, InputNumber, Modal, Switch, Space } from 'antd';
import * as SettingsState from '@@app-state/settings/state';
import { translated } from '@@localization';
import "@triply/yasgui/build/yasgui.min.css";
import { sparqlProxy, useProxy } from '@@constants/api';

const YasguiContainer = styled.div`
	width: fit-content;
	min-width: 512px;
	overflow: auto;
	.yasqe {
		text-align: left;
	}
`;

const yasguiRoot = document.createElement('div');
const yasgui = new YASGUI(yasguiRoot, useProxy ? {
	corsProxy: sparqlProxy
} : {});

dispatchSet(YasguiState.instance, yasgui);

class Yasgui extends Component {
	constructor(props) {
		super(props);
		this.yasgui = yasgui;
	}

	update() {
		this.tab().setQuery(this.props.query);
		this.tab().setEndpoint(this.props.endpoint);
		this.autoformatting = true;
		this.tab().yasqe.autoformat();
		this.autoformatting = false;
	}

	tab() {
		return this.yasgui.getTab();
	}

	onQueryChange = (_, {origin}) => {
		if (origin && origin !== 'setValue' && !this.autoformatting) {
			dispatchSet(ModelState.query, this.tab().getQuery());
		}
	}

	componentDidUpdate(prevProps, prevState, snapshot) {
		if (prevProps.query !== this.props.query && !this.props.modelQuery) { // If modelQuery exists, it's being already edited, no need to update
			this.update();
		}
	}

	componentDidMount() {
		this.yasguiContainer.appendChild(yasguiRoot);
		this.update();
		this.tab().getYasqe().on('change', this.onQueryChange);
	}

	componentWillUnmount() {
		this.tab().getYasqe().off('change', this.onQueryChange);
	}

	updateLimit = limit => {
		dispatchProps.updateLimit(limit);
	};

	toggleLimit = checked => {
		dispatchProps.toggleLimit(checked);
	};

	render() {
		const {limit, limitEnabled, cartesianProduct, modelQuery} = this.props;
		return <>
			{
				modelQuery &&
				<div style={{margin: '-12px 0 12px 0'}}>
					<Alert type='error' showIcon={false} message={translated('Current SPARQL Query has been manually edited, making any changes in the application will remove these edits.')} banner />
				</div>
			}
			{
				cartesianProduct &&
				<div style={{margin: '-12px 0 12px 0'}}>
					<Alert message={translated('Current selection is not a connected graph and might result in querying a cartesian product.')} banner />
				</div>
			}
			<Space direction="vertical">
				<div>{translated('Maximum number of results (limit):')} <InputNumber value={limit} onChange={this.updateLimit} /></div>
				<div>{translated('Use limit:')} <Switch checked={limitEnabled} onChange={this.toggleLimit}/></div>
				<YasguiContainer ref={ref => this.yasguiContainer = ref}/>
			</Space>
		</>;
	}
}

const mapStateToProps = appState => ({
	query: getQuery(appState),
	endpoint: getEndpoint(appState),
	limit: getLimit(appState),
	limitEnabled: getLimitEnabled(appState),
	cartesianProduct: getCartesianProduct(appState),
	modelQuery: getModelQuery(appState)
});

const dispatchProps = {
	updateLimit: dispatchSet(SettingsState.limit),
	toggleLimit: dispatchSet(SettingsState.limitEnabled),
};
const ConnectedComponent = connect(mapStateToProps, null)(Yasgui);

const YasguiTool = <Provider store={store}><ConnectedComponent/></Provider>;

export const openYasguiModal = ({runQuery}) => {
	Modal.info({icon: null, width: 'fit-content', maskClosable: true, content: YasguiTool});

	const state = getState();
	if (runQuery && getQuery(state)) {
		setTimeout(() => getInstance(state).getTab().query(), 500);
	}
}