Some improvements imported from IVIS (https://github.com/smartarch/ivis-core/tree/devel)
Builtin Zone-MTA upgraded Bug fix - URLs in campaign would not work if they contained non-ASCII character
This commit is contained in:
parent
65d3aed29d
commit
82251d1cb9
6 changed files with 217 additions and 43 deletions
|
@ -11,7 +11,7 @@ export function createComponentMixin(opts) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function withComponentMixins(mixins, delegateFuns) {
|
export function withComponentMixins(mixins, delegateFuns, delegateStaticFuns) {
|
||||||
const mixinsClosure = new Set();
|
const mixinsClosure = new Set();
|
||||||
for (const mixin of mixins) {
|
for (const mixin of mixins) {
|
||||||
console.assert(mixin);
|
console.assert(mixin);
|
||||||
|
@ -53,6 +53,7 @@ export function withComponentMixins(mixins, delegateFuns) {
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetClassWithCtors.displayName = TargetClass.name;
|
TargetClassWithCtors.displayName = TargetClass.name;
|
||||||
|
|
||||||
TargetClassWithCtors.prototype = TargetClass.prototype;
|
TargetClassWithCtors.prototype = TargetClass.prototype;
|
||||||
|
@ -61,6 +62,20 @@ export function withComponentMixins(mixins, delegateFuns) {
|
||||||
TargetClassWithCtors[attr] = TargetClass[attr];
|
TargetClassWithCtors[attr] = TargetClass[attr];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addStaticMethodsToClass(clazz) {
|
||||||
|
if (delegateStaticFuns) {
|
||||||
|
for (const staticFuncName of delegateStaticFuns) {
|
||||||
|
if (!clazz[staticFuncName]) {
|
||||||
|
Object.defineProperty(
|
||||||
|
clazz,
|
||||||
|
staticFuncName,
|
||||||
|
Object.getOwnPropertyDescriptor(TargetClass, staticFuncName)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function incorporateMixins(DecoratedInner) {
|
function incorporateMixins(DecoratedInner) {
|
||||||
for (const mixin of mixinsClosure.values()) {
|
for (const mixin of mixinsClosure.values()) {
|
||||||
if (mixin.decoratorFn) {
|
if (mixin.decoratorFn) {
|
||||||
|
@ -102,6 +117,7 @@ export function withComponentMixins(mixins, delegateFuns) {
|
||||||
|
|
||||||
this._decoratorInnerInstanceRefFn = node => this._decoratorInnerInstance = node
|
this._decoratorInnerInstanceRefFn = node => this._decoratorInnerInstance = node
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let innerFn = parentProps => {
|
let innerFn = parentProps => {
|
||||||
const props = {
|
const props = {
|
||||||
|
@ -136,6 +152,7 @@ export function withComponentMixins(mixins, delegateFuns) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addStaticMethodsToClass(ComponentMixinsOuter);
|
||||||
return ComponentMixinsOuter;
|
return ComponentMixinsOuter;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -163,6 +180,7 @@ export function withComponentMixins(mixins, delegateFuns) {
|
||||||
return innerFn(props);
|
return innerFn(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addStaticMethodsToClass(ComponentContextProvider);
|
||||||
return ComponentContextProvider;
|
return ComponentContextProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,8 +76,7 @@ export default class Files extends Component {
|
||||||
this.setFlashMessage('info', message);
|
this.setFlashMessage('info', message);
|
||||||
})
|
})
|
||||||
.catch(res => this.setFlashMessage('danger', t('fileUploadFailed') + ' ' + res.message));
|
.catch(res => this.setFlashMessage('danger', t('fileUploadFailed') + ' ' + res.message));
|
||||||
}
|
} else {
|
||||||
else{
|
|
||||||
this.setFlashMessage('info', t('noFilesToUpload'));
|
this.setFlashMessage('info', t('noFilesToUpload'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -304,6 +304,7 @@ class StaticField extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
@withComponentMixins([
|
@withComponentMixins([
|
||||||
|
withTranslation,
|
||||||
withFormStateOwner
|
withFormStateOwner
|
||||||
])
|
])
|
||||||
class InputField extends Component {
|
class InputField extends Component {
|
||||||
|
@ -313,18 +314,38 @@ class InputField extends Component {
|
||||||
placeholder: PropTypes.string,
|
placeholder: PropTypes.string,
|
||||||
type: PropTypes.string,
|
type: PropTypes.string,
|
||||||
help: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
help: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
||||||
format: PropTypes.string
|
format: PropTypes.string,
|
||||||
|
// TODO FOR MAILTRAIN added dropdown with hints under input
|
||||||
|
withHints: PropTypes.array,
|
||||||
|
disabled: PropTypes.bool
|
||||||
}
|
}
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
type: 'text'
|
type: 'text'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.state = {showHints: false};
|
||||||
|
this.textInput = React.createRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
onFocus() {
|
||||||
|
this.setState({showHints: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
onBlur() {
|
||||||
|
this.setState({showHints: false});
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const props = this.props;
|
const props = this.props;
|
||||||
|
const t = props.t;
|
||||||
const owner = this.getFormStateOwner();
|
const owner = this.getFormStateOwner();
|
||||||
const id = this.props.id;
|
const id = props.id;
|
||||||
const htmlId = 'form_' + id;
|
const htmlId = 'form_' + id;
|
||||||
|
const enableHints = !!(props.withHints && !props.disabled);
|
||||||
|
|
||||||
|
|
||||||
let type = 'text';
|
let type = 'text';
|
||||||
if (props.type === 'password') {
|
if (props.type === 'password') {
|
||||||
|
@ -342,9 +363,78 @@ class InputField extends Component {
|
||||||
const value = owner.getFormValue(id);
|
const value = owner.getFormValue(id);
|
||||||
if (value === null || value === undefined) console.log(`Warning: InputField ${id} is ${value}`);
|
if (value === null || value === undefined) console.log(`Warning: InputField ${id} is ${value}`);
|
||||||
|
|
||||||
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
let hintsFuns = {};
|
||||||
<input type={type} value={owner.getFormValue(id)} placeholder={props.placeholder} id={htmlId} className={className} aria-describedby={htmlId + '_help'} onChange={evt => owner.updateFormValue(id, evt.target.value)}/>
|
if (enableHints) {
|
||||||
|
hintsFuns['onFocus'] = ::this.onFocus;
|
||||||
|
hintsFuns['onBlur'] = ::this.onBlur;
|
||||||
|
}
|
||||||
|
|
||||||
|
let inputContent = (
|
||||||
|
<input ref={this.textInput}
|
||||||
|
type={type}
|
||||||
|
value={owner.getFormValue(id)}
|
||||||
|
placeholder={props.placeholder}
|
||||||
|
id={htmlId}
|
||||||
|
className={className}
|
||||||
|
aria-describedby={htmlId + '_help'}
|
||||||
|
onChange={evt => owner.updateFormValue(id, evt.target.value)}
|
||||||
|
disabled={props.disabled}
|
||||||
|
{...hintsFuns}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (enableHints) {
|
||||||
|
inputContent = (
|
||||||
|
<div className="input-group">
|
||||||
|
{inputContent}
|
||||||
|
<div className="input-group-append" onMouseDown={evt => evt.preventDefault()}>
|
||||||
|
<Button label={t('Hints')} className="btn-secondary"
|
||||||
|
onClickAsync={evt => {
|
||||||
|
if (!this.state.showHints) {
|
||||||
|
this.textInput.current.focus();
|
||||||
|
} else {
|
||||||
|
this.textInput.current.blur();
|
||||||
|
}
|
||||||
|
}}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
let hintsDropdown = null;
|
||||||
|
if (this.state.showHints) {
|
||||||
|
const hints = [];
|
||||||
|
for (const hint of props.withHints) {
|
||||||
|
hints.push(
|
||||||
|
<li
|
||||||
|
key={hint}
|
||||||
|
className={`list-group-item list-group-item-action list-group-item-light ${styles.inputHint}`}
|
||||||
|
onClick={evt => {
|
||||||
|
this.textInput.current.blur();
|
||||||
|
owner.updateFormValue(id, hint);
|
||||||
|
}}
|
||||||
|
onMouseDown={evt => evt.preventDefault()}
|
||||||
|
>
|
||||||
|
{hint}
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
hintsDropdown = (
|
||||||
|
<div className={`list-group ${styles.inputHints}`}>
|
||||||
|
{hints}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
inputContent = (
|
||||||
|
<div className={styles.inputContainer}>
|
||||||
|
{inputContent}
|
||||||
|
{hintsDropdown}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help, inputContent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,7 +461,11 @@ class CheckBox extends Component {
|
||||||
|
|
||||||
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
||||||
<div className={`form-group form-check my-2 ${this.props.className}`}>
|
<div className={`form-group form-check my-2 ${this.props.className}`}>
|
||||||
<input className={inputClassName} type="checkbox" checked={owner.getFormValue(id)} id={htmlId} aria-describedby={htmlId + '_help'} onChange={evt => owner.updateFormValue(id, !owner.getFormValue(id))}/>
|
<input className={inputClassName} type="checkbox"
|
||||||
|
checked={owner.getFormValue(id)}
|
||||||
|
id={htmlId}
|
||||||
|
aria-describedby={htmlId + '_help'}
|
||||||
|
onChange={evt => owner.updateFormValue(id, !owner.getFormValue(id))}/>
|
||||||
<label className={styles.checkboxText} htmlFor={htmlId}>{props.text}</label>
|
<label className={styles.checkboxText} htmlFor={htmlId}>{props.text}</label>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -427,7 +521,11 @@ class CheckBoxGroup extends Component {
|
||||||
|
|
||||||
let number = options.push(
|
let number = options.push(
|
||||||
<div key={option.key} className="form-group form-check my-2">
|
<div key={option.key} className="form-group form-check my-2">
|
||||||
<input id={optId} type="checkbox" className={optClassName} checked={selection.includes(option.key)} onChange={evt => this.onChange(option.key)}/>
|
<input id={optId}
|
||||||
|
type="checkbox"
|
||||||
|
className={optClassName}
|
||||||
|
checked={selection.includes(option.key)}
|
||||||
|
onChange={evt => this.onChange(option.key)}/>
|
||||||
<label className="form-check-label" htmlFor={optId}>{option.label}</label>
|
<label className="form-check-label" htmlFor={optId}>{option.label}</label>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -475,7 +573,12 @@ class RadioGroup extends Component {
|
||||||
|
|
||||||
let number = options.push(
|
let number = options.push(
|
||||||
<div key={option.key} className="form-group form-check my-2">
|
<div key={option.key} className="form-group form-check my-2">
|
||||||
<input id={optId} type="radio" className={optClassName} name={htmlId} checked={value === option.key} onChange={evt => owner.updateFormValue(id, option.key)}/>
|
<input id={optId}
|
||||||
|
type="radio"
|
||||||
|
className={optClassName}
|
||||||
|
name={htmlId}
|
||||||
|
checked={value === option.key}
|
||||||
|
onChange={evt => owner.updateFormValue(id, option.key)}/>
|
||||||
<label className="form-check-label" htmlFor={optId}>{option.label}</label>
|
<label className="form-check-label" htmlFor={optId}>{option.label}</label>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -524,7 +627,12 @@ class TextArea extends Component {
|
||||||
const className = owner.addFormValidationClass('form-control ' + (props.className || ''), id);
|
const className = owner.addFormValidationClass('form-control ' + (props.className || ''), id);
|
||||||
|
|
||||||
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
||||||
<textarea id={htmlId} placeholder={props.placeholder} value={owner.getFormValue(id) || ''} className={className} aria-describedby={htmlId + '_help'} onChange={this.onChange}></textarea>
|
<textarea id={htmlId}
|
||||||
|
placeholder={props.placeholder}
|
||||||
|
value={owner.getFormValue(id) || ''}
|
||||||
|
className={className}
|
||||||
|
aria-describedby={htmlId + '_help'}
|
||||||
|
onChange={this.onChange}></textarea>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -577,7 +685,8 @@ class ColorPicker extends Component {
|
||||||
<div>
|
<div>
|
||||||
<div className="input-group">
|
<div className="input-group">
|
||||||
<div className={styles.colorPickerSwatchWrapper} onClick={::this.toggle}>
|
<div className={styles.colorPickerSwatchWrapper} onClick={::this.toggle}>
|
||||||
<div className={styles.colorPickerSwatchColor} style={{background: `rgba(${ color.r }, ${ color.g }, ${ color.b }, ${ color.a })`}}/>
|
<div className={styles.colorPickerSwatchColor}
|
||||||
|
style={{background: `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a})`}}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{this.state.opened &&
|
{this.state.opened &&
|
||||||
|
@ -611,7 +720,8 @@ class DatePicker extends Component {
|
||||||
birthday: PropTypes.bool,
|
birthday: PropTypes.bool,
|
||||||
dateFormat: PropTypes.string,
|
dateFormat: PropTypes.string,
|
||||||
formatDate: PropTypes.func,
|
formatDate: PropTypes.func,
|
||||||
parseDate: PropTypes.func
|
parseDate: PropTypes.func,
|
||||||
|
disabled: PropTypes.bool
|
||||||
}
|
}
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
|
@ -695,11 +805,17 @@ class DatePicker extends Component {
|
||||||
|
|
||||||
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
||||||
<>
|
<>
|
||||||
<div className="input-group">
|
<div className={props.disabled ? '' : "input-group"}>
|
||||||
<input type="text" value={selectedDateStr} placeholder={placeholder} id={htmlId} className={className} aria-describedby={htmlId + '_help'} onChange={evt => owner.updateFormValue(id, evt.target.value)}/>
|
<input type="text" value={selectedDateStr} placeholder={placeholder} id={htmlId}
|
||||||
|
className={className} aria-describedby={htmlId + '_help'}
|
||||||
|
onChange={evt => owner.updateFormValue(id, evt.target.value)}
|
||||||
|
disabled={props.disabled}/>
|
||||||
|
{!props.disabled &&
|
||||||
<div className="input-group-append">
|
<div className="input-group-append">
|
||||||
<Button iconTitle={t('openCalendar')} className="btn-secondary" icon="calendar-alt" onClickAsync={::this.toggleDayPicker}/>
|
<Button iconTitle={t('openCalendar')} className="btn-secondary" icon="calendar-alt"
|
||||||
|
onClickAsync={::this.toggleDayPicker}/>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
{this.state.opened &&
|
{this.state.opened &&
|
||||||
<div className={styles.dayPickerWrapper}>
|
<div className={styles.dayPickerWrapper}>
|
||||||
|
@ -758,7 +874,12 @@ class Dropdown extends Component {
|
||||||
const className = owner.addFormValidationClass('form-control ' + (props.className || ''), id);
|
const className = owner.addFormValidationClass('form-control ' + (props.className || ''), id);
|
||||||
|
|
||||||
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
||||||
<select id={htmlId} className={className} aria-describedby={htmlId + '_help'} value={owner.getFormValue(id)} onChange={evt => owner.updateFormValue(id, evt.target.value)} disabled={props.disabled}>
|
<select id={htmlId}
|
||||||
|
className={className}
|
||||||
|
aria-describedby={htmlId + '_help'}
|
||||||
|
value={owner.getFormValue(id)}
|
||||||
|
onChange={evt => owner.updateFormValue(id, evt.target.value)}
|
||||||
|
disabled={props.disabled}>
|
||||||
{options}
|
{options}
|
||||||
</select>
|
</select>
|
||||||
);
|
);
|
||||||
|
@ -835,7 +956,12 @@ class TreeTableSelect extends Component {
|
||||||
const className = owner.addFormValidationClass('', id);
|
const className = owner.addFormValidationClass('', id);
|
||||||
|
|
||||||
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
||||||
<TreeTable className={className} data={props.data} dataUrl={props.dataUrl} selectMode={TreeSelectMode.SINGLE} selection={owner.getFormValue(id)} onSelectionChangedAsync={::this.onSelectionChangedAsync} />
|
<TreeTable className={className}
|
||||||
|
data={props.data}
|
||||||
|
dataUrl={props.dataUrl}
|
||||||
|
selectMode={TreeSelectMode.SINGLE}
|
||||||
|
selection={owner.getFormValue(id)}
|
||||||
|
onSelectionChangedAsync={::this.onSelectionChangedAsync}/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -932,15 +1058,31 @@ class TableSelect extends Component {
|
||||||
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
||||||
<div>
|
<div>
|
||||||
<div className={(props.disabled ? '' : 'input-group ') + styles.tableSelectDropdown}>
|
<div className={(props.disabled ? '' : 'input-group ') + styles.tableSelectDropdown}>
|
||||||
<input type="text" className={className} value={this.state.selectedLabel} onClick={::this.toggleOpen} readOnly={!props.disabled} disabled={props.disabled}/>
|
<input type="text"
|
||||||
|
className={className}
|
||||||
|
value={this.state.selectedLabel}
|
||||||
|
onClick={::this.toggleOpen}
|
||||||
|
readOnly={!props.disabled}
|
||||||
|
disabled={props.disabled}/>
|
||||||
{!props.disabled &&
|
{!props.disabled &&
|
||||||
<div className="input-group-append">
|
<div className="input-group-append">
|
||||||
<Button label={t('select')} className="btn-secondary" onClickAsync={::this.toggleOpen}/>
|
<Button label={t('select')} className="btn-secondary" onClickAsync={::this.toggleOpen}/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.tableSelectTable + (this.state.open ? '' : ' ' + styles.tableSelectTableHidden)}>
|
<div
|
||||||
<Table ref={node => this.table = node} data={props.data} dataUrl={props.dataUrl} columns={props.columns} selectMode={props.selectMode} selectionAsArray={this.props.selectionAsArray} withHeader={props.withHeader} selectionKeyIndex={props.selectionKeyIndex} selection={owner.getFormValue(id)} onSelectionDataAsync={::this.onSelectionDataAsync} onSelectionChangedAsync={::this.onSelectionChangedAsync}/>
|
className={styles.tableSelectTable + (this.state.open ? '' : ' ' + styles.tableSelectTableHidden)}>
|
||||||
|
<Table ref={node => this.table = node}
|
||||||
|
data={props.data}
|
||||||
|
dataUrl={props.dataUrl}
|
||||||
|
columns={props.columns}
|
||||||
|
selectMode={props.selectMode}
|
||||||
|
selectionAsArray={this.props.selectionAsArray}
|
||||||
|
withHeader={props.withHeader}
|
||||||
|
selectionKeyIndex={props.selectionKeyIndex}
|
||||||
|
selection={owner.getFormValue(id)}
|
||||||
|
onSelectionDataAsync={::this.onSelectionDataAsync}
|
||||||
|
onSelectionChangedAsync={::this.onSelectionChangedAsync}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -948,7 +1090,17 @@ class TableSelect extends Component {
|
||||||
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<Table ref={node => this.table = node} data={props.data} dataUrl={props.dataUrl} columns={props.columns} pageLength={props.pageLength} selectMode={props.selectMode} selectionAsArray={this.props.selectionAsArray} withHeader={props.withHeader} selectionKeyIndex={props.selectionKeyIndex} selection={owner.getFormValue(id)} onSelectionChangedAsync={::this.onSelectionChangedAsync}/>
|
<Table ref={node => this.table = node}
|
||||||
|
data={props.data}
|
||||||
|
dataUrl={props.dataUrl}
|
||||||
|
columns={props.columns}
|
||||||
|
pageLength={props.pageLength}
|
||||||
|
selectMode={props.selectMode}
|
||||||
|
selectionAsArray={this.props.selectionAsArray}
|
||||||
|
withHeader={props.withHeader}
|
||||||
|
selectionKeyIndex={props.selectionKeyIndex}
|
||||||
|
selection={owner.getFormValue(id)}
|
||||||
|
onSelectionChangedAsync={::this.onSelectionChangedAsync}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -376,6 +376,11 @@ export class SectionContent extends Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.historyUnlisten = props.history.listen((location, action) => {
|
this.historyUnlisten = props.history.listen((location, action) => {
|
||||||
|
// I don't think it is ever needed on replace action, or at least it will be better than not showing the msg,
|
||||||
|
// and without it this won't work because first it goes to '/' -> '/workspaces' so replacing immediately
|
||||||
|
if (action === "REPLACE") return;
|
||||||
|
if (location.state && location.state.preserveFlashMessage) return;
|
||||||
|
|
||||||
// noinspection JSIgnoredPromiseFromCall
|
// noinspection JSIgnoredPromiseFromCall
|
||||||
this.closeFlashMessage();
|
this.closeFlashMessage();
|
||||||
});
|
});
|
||||||
|
@ -434,7 +439,7 @@ export class SectionContent extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
navigateToWithFlashMessage(path, severity, text) {
|
navigateToWithFlashMessage(path, severity, text) {
|
||||||
this.props.history.push(path);
|
this.props.history.push(path, {preserveFlashMessage: true});
|
||||||
this.setFlashMessage(severity, text);
|
this.setFlashMessage(severity, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,7 @@ async function updateLinks(source, tagLanguage, mergeTags, campaign, list, subsc
|
||||||
const urls = new Map(); // url -> {id, cid} (as returned by add)
|
const urls = new Map(); // url -> {id, cid} (as returned by add)
|
||||||
for (const url of urlsToBeReplaced) {
|
for (const url of urlsToBeReplaced) {
|
||||||
// url might include variables, need to rewrite those just as we do with message content
|
// url might include variables, need to rewrite those just as we do with message content
|
||||||
const expanedUrl = tools.formatCampaignTemplate(url, tagLanguage, mergeTags, false, campaign, list, subscription);
|
const expanedUrl = encodeURI(tools.formatCampaignTemplate(url, tagLanguage, mergeTags, false, campaign, list, subscription));
|
||||||
const link = await addOrGet(campaign.id, expanedUrl);
|
const link = await addOrGet(campaign.id, expanedUrl);
|
||||||
urls.set(url, link);
|
urls.set(url, link);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"zone-mta": "^1.16.6",
|
"zone-mta": "^2.2.1",
|
||||||
"zonemta-delivery-counters": "^1.0.1",
|
"zonemta-delivery-counters": "^1.0.1",
|
||||||
"zonemta-limiter": "^1.0.0",
|
"zonemta-limiter": "^1.0.0",
|
||||||
"zonemta-loop-breaker": "^1.0.2"
|
"zonemta-loop-breaker": "^1.0.2"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue