Remove button removed from the namespace that contains the current user.
Optimizations in how mixins are composed. The refresh should now be up to 2x faster for deeper hierarchies.
This commit is contained in:
parent
6ae9143c22
commit
a46c8fa9c3
15 changed files with 764 additions and 680 deletions
3
TODO.md
3
TODO.md
|
@ -21,3 +21,6 @@ Note that some of these may be already obsolete...
|
|||
- Add field to subscriptions which says till when the consent has been given
|
||||
- Provide a link (and merge tag) that will update the consent date to now
|
||||
- Add campaign trigger that triggers if the consent for specific subscription field is about to expire (i.e. it is greater than now - seconds)
|
||||
|
||||
### RSS Campaigns
|
||||
- Aggregated RSS campaigns
|
|
@ -2,17 +2,19 @@
|
|||
|
||||
import React from "react";
|
||||
|
||||
export function createComponentMixin(contexts, deps, decoratorFn) {
|
||||
export function createComponentMixin(opts) {
|
||||
return {
|
||||
contexts,
|
||||
deps,
|
||||
decoratorFn
|
||||
contexts: opts.contexts || [],
|
||||
deps: opts.deps || [],
|
||||
delegateFuns: opts.delegateFuns || [],
|
||||
decoratorFn: opts.decoratorFn
|
||||
};
|
||||
}
|
||||
|
||||
export function withComponentMixins(mixins, delegateFuns) {
|
||||
const mixinsClosure = new Set();
|
||||
for (const mixin of mixins) {
|
||||
console.assert(mixin);
|
||||
mixinsClosure.add(mixin);
|
||||
for (const dep of mixin.deps) {
|
||||
mixinsClosure.add(dep);
|
||||
|
@ -34,6 +36,10 @@ export function withComponentMixins(mixins, delegateFuns) {
|
|||
mixinDelegateFuns.push(...delegateFuns);
|
||||
}
|
||||
|
||||
for (const mixin of mixinsClosure.values()) {
|
||||
mixinDelegateFuns.push(...mixin.delegateFuns);
|
||||
}
|
||||
|
||||
function TargetClassWithCtors(props) {
|
||||
if (!new.target) {
|
||||
throw new TypeError();
|
||||
|
@ -55,7 +61,25 @@ export function withComponentMixins(mixins, delegateFuns) {
|
|||
TargetClassWithCtors[attr] = TargetClass[attr];
|
||||
}
|
||||
|
||||
function incorporateMixins(DecoratedInner) {
|
||||
for (const mixin of mixinsClosure.values()) {
|
||||
if (mixin.decoratorFn) {
|
||||
const res = mixin.decoratorFn(DecoratedInner, TargetClassWithCtors);
|
||||
|
||||
if (res.cls) {
|
||||
DecoratedInner = res.cls;
|
||||
}
|
||||
|
||||
if (res.ctor) {
|
||||
ctors.push(res.ctor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DecoratedInner;
|
||||
}
|
||||
|
||||
if (mixinDelegateFuns.length > 0) {
|
||||
class ComponentMixinsInner extends React.Component {
|
||||
render() {
|
||||
const props = {
|
||||
|
@ -70,23 +94,7 @@ export function withComponentMixins(mixins, delegateFuns) {
|
|||
}
|
||||
}
|
||||
|
||||
let DecoratedInner = ComponentMixinsInner;
|
||||
|
||||
for (const mixin of mixinsClosure.values()) {
|
||||
const res = mixin.decoratorFn(DecoratedInner, TargetClassWithCtors);
|
||||
|
||||
if (res.cls) {
|
||||
DecoratedInner = res.cls;
|
||||
}
|
||||
|
||||
if (res.ctor) {
|
||||
ctors.push(res.ctor);
|
||||
}
|
||||
|
||||
if (res.delegateFuns) {
|
||||
mixinDelegateFuns.push(...res.delegateFuns);
|
||||
}
|
||||
}
|
||||
const DecoratedInner = incorporateMixins(ComponentMixinsInner);
|
||||
|
||||
class ComponentMixinsOuter extends React.Component {
|
||||
constructor(props) {
|
||||
|
@ -102,7 +110,7 @@ export function withComponentMixins(mixins, delegateFuns) {
|
|||
};
|
||||
|
||||
return <DecoratedInner {...props}/>
|
||||
}
|
||||
};
|
||||
|
||||
for (const [propName, Context] of contexts.entries()) {
|
||||
const existingInnerFn = innerFn;
|
||||
|
@ -129,6 +137,35 @@ export function withComponentMixins(mixins, delegateFuns) {
|
|||
}
|
||||
|
||||
return ComponentMixinsOuter;
|
||||
|
||||
} else {
|
||||
const DecoratedInner = incorporateMixins(TargetClassWithCtors);
|
||||
|
||||
function ComponentContextProvider(props) {
|
||||
let innerFn = props => {
|
||||
return <DecoratedInner {...props}/>
|
||||
};
|
||||
|
||||
for (const [propName, Context] of contexts.entries()) {
|
||||
const existingInnerFn = innerFn;
|
||||
innerFn = parentProps => (
|
||||
<Context.Consumer>
|
||||
{
|
||||
value => existingInnerFn({
|
||||
...parentProps,
|
||||
[propName]: value
|
||||
})
|
||||
}
|
||||
</Context.Consumer>
|
||||
);
|
||||
}
|
||||
|
||||
return innerFn(props);
|
||||
}
|
||||
|
||||
return ComponentContextProvider;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,9 @@ function handleError(that, error) {
|
|||
}
|
||||
|
||||
export const ParentErrorHandlerContext = React.createContext(null);
|
||||
export const withErrorHandling = createComponentMixin([{context: ParentErrorHandlerContext, propName: 'parentErrorHandler'}], [], (TargetClass, InnerClass) => {
|
||||
export const withErrorHandling = createComponentMixin({
|
||||
contexts: [{context: ParentErrorHandlerContext, propName: 'parentErrorHandler'}],
|
||||
decoratorFn: (TargetClass, InnerClass) => {
|
||||
/* Example of use:
|
||||
this.getFormValuesFromURL(....).catch(error => this.handleError(error));
|
||||
|
||||
|
@ -35,7 +37,7 @@ export const withErrorHandling = createComponentMixin([{context: ParentErrorHand
|
|||
|
||||
const originalRender = InnerClass.prototype.render;
|
||||
|
||||
InnerClass.prototype.render = function() {
|
||||
InnerClass.prototype.render = function () {
|
||||
return (
|
||||
<ParentErrorHandlerContext.Provider value={this}>
|
||||
{originalRender.apply(this)}
|
||||
|
@ -43,11 +45,12 @@ export const withErrorHandling = createComponentMixin([{context: ParentErrorHand
|
|||
);
|
||||
}
|
||||
|
||||
InnerClass.prototype.handleError = function(error) {
|
||||
InnerClass.prototype.handleError = function (error) {
|
||||
handleError(this, error);
|
||||
};
|
||||
|
||||
return {};
|
||||
}
|
||||
});
|
||||
|
||||
export function withAsyncErrorHandler(target, name, descriptor) {
|
||||
|
|
|
@ -46,12 +46,15 @@ const FormSendMethod = HTTPMethod;
|
|||
|
||||
export const FormStateOwnerContext = React.createContext(null);
|
||||
|
||||
const withFormStateOwner = createComponentMixin([{context: FormStateOwnerContext, propName: 'formStateOwner'}], [], (TargetClass, InnerClass) => {
|
||||
InnerClass.prototype.getFormStateOwner = function() {
|
||||
const withFormStateOwner = createComponentMixin({
|
||||
contexts: [{context: FormStateOwnerContext, propName: 'formStateOwner'}],
|
||||
decoratorFn: (TargetClass, InnerClass) => {
|
||||
InnerClass.prototype.getFormStateOwner = function () {
|
||||
return this.props.formStateOwner;
|
||||
};
|
||||
|
||||
return {};
|
||||
}
|
||||
});
|
||||
|
||||
export function withFormErrorHandlers(target, name, descriptor) {
|
||||
|
@ -345,9 +348,6 @@ class InputField extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
@withComponentMixins([
|
||||
withFormStateOwner
|
||||
])
|
||||
class CheckBox extends Component {
|
||||
static propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
|
@ -359,8 +359,11 @@ class CheckBox extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<FormStateOwnerContext.Consumer>
|
||||
{
|
||||
owner => {
|
||||
const props = this.props;
|
||||
const owner = this.getFormStateOwner();
|
||||
const id = this.props.id;
|
||||
const htmlId = 'form_' + id;
|
||||
|
||||
|
@ -373,6 +376,12 @@ class CheckBox extends Component {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
</FormStateOwnerContext.Consumer>
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@withComponentMixins([
|
||||
|
@ -489,6 +498,15 @@ class RadioGroup extends Component {
|
|||
withFormStateOwner
|
||||
])
|
||||
class TextArea extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.onChange = evt => {
|
||||
const id = this.props.id;
|
||||
const owner = this.getFormStateOwner();
|
||||
owner.updateFormValue(id, evt.target.value);
|
||||
}
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
|
@ -506,7 +524,7 @@ class TextArea extends Component {
|
|||
const className = owner.addFormValidationClass('form-control ' + (props.className || '') , id);
|
||||
|
||||
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={evt => owner.updateFormValue(id, evt.target.value)}></textarea>
|
||||
<textarea id={htmlId} placeholder={props.placeholder} value={owner.getFormValue(id) || ''} className={className} aria-describedby={htmlId + '_help'} onChange={this.onChange}></textarea>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -977,7 +995,8 @@ class ACEEditor extends Component {
|
|||
}
|
||||
|
||||
|
||||
const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
||||
const withForm = createComponentMixin({
|
||||
decoratorFn: (TargetClass, InnerClass) => {
|
||||
const proto = InnerClass.prototype;
|
||||
|
||||
const cleanFormState = Immutable.Map({
|
||||
|
@ -1101,7 +1120,7 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
|||
}
|
||||
|
||||
const previousComponentDidMount = proto.componentDidMount;
|
||||
proto.componentDidMount = function() {
|
||||
proto.componentDidMount = function () {
|
||||
this._isComponentMounted = true;
|
||||
if (previousComponentDidMount) {
|
||||
previousComponentDidMount.apply(this);
|
||||
|
@ -1109,18 +1128,18 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
|||
};
|
||||
|
||||
const previousComponentWillUnmount = proto.componentWillUnmount;
|
||||
proto.componentWillUnmount = function() {
|
||||
proto.componentWillUnmount = function () {
|
||||
this._isComponentMounted = false;
|
||||
if (previousComponentWillUnmount) {
|
||||
previousComponentDidMount.apply(this);
|
||||
}
|
||||
};
|
||||
|
||||
proto.isComponentMounted = function() {
|
||||
proto.isComponentMounted = function () {
|
||||
return !!this._isComponentMounted;
|
||||
}
|
||||
|
||||
proto.initForm = function(settings) {
|
||||
proto.initForm = function (settings) {
|
||||
const state = this.state || {};
|
||||
state.formState = cleanFormState;
|
||||
state.formSettings = {
|
||||
|
@ -1130,13 +1149,13 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
|||
this.state = state;
|
||||
};
|
||||
|
||||
proto.resetFormState = function() {
|
||||
proto.resetFormState = function () {
|
||||
this.setState({
|
||||
formState: cleanFormState
|
||||
});
|
||||
};
|
||||
|
||||
proto.getFormValuesFromEntity = function(entity) {
|
||||
proto.getFormValuesFromEntity = function (entity) {
|
||||
const settings = this.state.formSettings;
|
||||
const data = Object.assign({}, entity);
|
||||
|
||||
|
@ -1150,7 +1169,7 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
|||
this.populateFormValues(data);
|
||||
};
|
||||
|
||||
proto.getFormValuesFromURL = async function(url) {
|
||||
proto.getFormValuesFromURL = async function (url) {
|
||||
const settings = this.state.formSettings;
|
||||
setTimeout(() => {
|
||||
this.setState(previousState => {
|
||||
|
@ -1180,7 +1199,7 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
|||
this.populateFormValues(data);
|
||||
};
|
||||
|
||||
proto.validateAndSendFormValuesToURL = async function(method, url) {
|
||||
proto.validateAndSendFormValuesToURL = async function (method, url) {
|
||||
const settings = this.state.formSettings;
|
||||
await this.waitForFormServerValidated();
|
||||
|
||||
|
@ -1225,7 +1244,7 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
|||
};
|
||||
|
||||
|
||||
proto.populateFormValues = function(data) {
|
||||
proto.populateFormValues = function (data) {
|
||||
const settings = this.state.formSettings;
|
||||
|
||||
this.setState(previousState => ({
|
||||
|
@ -1249,17 +1268,19 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
|||
}));
|
||||
};
|
||||
|
||||
proto.waitForFormServerValidated = async function() {
|
||||
proto.waitForFormServerValidated = async function () {
|
||||
if (!this.isFormServerValidated()) {
|
||||
await new Promise(resolve => { formValidateResolve = resolve; });
|
||||
await new Promise(resolve => {
|
||||
formValidateResolve = resolve;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
proto.scheduleFormRevalidate = function() {
|
||||
proto.scheduleFormRevalidate = function () {
|
||||
scheduleValidateForm(this);
|
||||
};
|
||||
|
||||
proto.updateForm = function(mutator) {
|
||||
proto.updateForm = function (mutator) {
|
||||
this.setState(previousState => {
|
||||
const onChangeBeforeValidationCallback = this.state.formSettings.onChangeBeforeValidation || {};
|
||||
|
||||
|
@ -1302,7 +1323,7 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
|||
});
|
||||
};
|
||||
|
||||
proto.updateFormValue = function(key, value) {
|
||||
proto.updateFormValue = function (key, value) {
|
||||
this.setState(previousState => {
|
||||
const oldValue = previousState.formState.getIn(['data', key, 'value']);
|
||||
|
||||
|
@ -1343,28 +1364,28 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
|||
});
|
||||
};
|
||||
|
||||
proto.getFormValue = function(name) {
|
||||
proto.getFormValue = function (name) {
|
||||
return this.state.formState.getIn(['data', name, 'value']);
|
||||
};
|
||||
|
||||
proto.getFormValues = function(name) {
|
||||
proto.getFormValues = function (name) {
|
||||
if (!this.state || !this.state.formState) return undefined;
|
||||
return this.state.formState.get('data').map(attr => attr.get('value')).toJS();
|
||||
};
|
||||
|
||||
proto.getFormError = function(name) {
|
||||
proto.getFormError = function (name) {
|
||||
return this.state.formState.getIn(['data', name, 'error']);
|
||||
};
|
||||
|
||||
proto.isFormWithLoadingNotice = function() {
|
||||
proto.isFormWithLoadingNotice = function () {
|
||||
return this.state.formState.get('state') === FormState.LoadingWithNotice;
|
||||
};
|
||||
|
||||
proto.isFormLoading = function() {
|
||||
proto.isFormLoading = function () {
|
||||
return this.state.formState.get('state') === FormState.Loading || this.state.formState.get('state') === FormState.LoadingWithNotice;
|
||||
};
|
||||
|
||||
proto.isFormReady = function() {
|
||||
proto.isFormReady = function () {
|
||||
return this.state.formState.get('state') === FormState.Ready;
|
||||
};
|
||||
|
||||
|
@ -1392,7 +1413,7 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
|||
return result;
|
||||
};
|
||||
|
||||
proto.isFormChanged = function() {
|
||||
proto.isFormChanged = function () {
|
||||
const settings = this.state.formSettings;
|
||||
|
||||
if (!settings.leaveConfirmation) return false;
|
||||
|
@ -1406,7 +1427,7 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
|||
return _isFormChanged(this);
|
||||
};
|
||||
|
||||
proto.isFormChangedAsync = async function() {
|
||||
proto.isFormChangedAsync = async function () {
|
||||
const settings = this.state.formSettings;
|
||||
|
||||
if (!settings.leaveConfirmation) return false;
|
||||
|
@ -1427,11 +1448,11 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
|||
|
||||
};
|
||||
|
||||
proto.isFormValidationShown = function() {
|
||||
proto.isFormValidationShown = function () {
|
||||
return this.state.formState.get('isValidationShown');
|
||||
};
|
||||
|
||||
proto.addFormValidationClass = function(className, name) {
|
||||
proto.addFormValidationClass = function (className, name) {
|
||||
if (this.isFormValidationShown()) {
|
||||
const error = this.getFormError(name);
|
||||
if (error) {
|
||||
|
@ -1444,7 +1465,7 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
|||
}
|
||||
};
|
||||
|
||||
proto.getFormValidationMessage = function(name) {
|
||||
proto.getFormValidationMessage = function (name) {
|
||||
if (this.isFormValidationShown()) {
|
||||
return this.getFormError(name);
|
||||
} else {
|
||||
|
@ -1452,31 +1473,31 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
|||
}
|
||||
};
|
||||
|
||||
proto.showFormValidation = function() {
|
||||
proto.showFormValidation = function () {
|
||||
this.setState(previousState => ({formState: previousState.formState.set('isValidationShown', true)}));
|
||||
};
|
||||
|
||||
proto.hideFormValidation = function() {
|
||||
proto.hideFormValidation = function () {
|
||||
this.setState(previousState => ({formState: previousState.formState.set('isValidationShown', false)}));
|
||||
};
|
||||
|
||||
proto.isFormWithoutErrors = function() {
|
||||
proto.isFormWithoutErrors = function () {
|
||||
return !this.state.formState.get('data').find(attr => attr.get('error'));
|
||||
};
|
||||
|
||||
proto.isFormServerValidated = function() {
|
||||
proto.isFormServerValidated = function () {
|
||||
return !this.state.formSettings.serverValidation || this.state.formSettings.serverValidation.changed.every(attr => this.state.formState.getIn(['data', attr, 'serverValidated']));
|
||||
};
|
||||
|
||||
proto.getFormStatusMessageText = function() {
|
||||
proto.getFormStatusMessageText = function () {
|
||||
return this.state.formState.get('statusMessageText');
|
||||
};
|
||||
|
||||
proto.getFormStatusMessageSeverity = function() {
|
||||
proto.getFormStatusMessageSeverity = function () {
|
||||
return this.state.formState.get('statusMessageSeverity');
|
||||
};
|
||||
|
||||
proto.setFormStatusMessage = function(severity, text) {
|
||||
proto.setFormStatusMessage = function (severity, text) {
|
||||
this.setState(previousState => ({
|
||||
formState: previousState.formState.withMutations(map => {
|
||||
map.set('statusMessageText', text);
|
||||
|
@ -1485,7 +1506,7 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
|||
}));
|
||||
};
|
||||
|
||||
proto.clearFormStatusMessage = function() {
|
||||
proto.clearFormStatusMessage = function () {
|
||||
this.setState(previousState => ({
|
||||
formState: previousState.formState.withMutations(map => {
|
||||
map.set('statusMessageText', '');
|
||||
|
@ -1493,19 +1514,19 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
|||
}));
|
||||
};
|
||||
|
||||
proto.enableForm = function() {
|
||||
proto.enableForm = function () {
|
||||
this.setState(previousState => ({formState: previousState.formState.set('isDisabled', false)}));
|
||||
};
|
||||
|
||||
proto.disableForm = function() {
|
||||
proto.disableForm = function () {
|
||||
this.setState(previousState => ({formState: previousState.formState.set('isDisabled', true)}));
|
||||
};
|
||||
|
||||
proto.isFormDisabled = function() {
|
||||
proto.isFormDisabled = function () {
|
||||
return this.state.formState.get('isDisabled');
|
||||
};
|
||||
|
||||
proto.formHandleErrors = async function(fn) {
|
||||
proto.formHandleErrors = async function (fn) {
|
||||
const t = this.props.t;
|
||||
try {
|
||||
await fn();
|
||||
|
@ -1548,6 +1569,7 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
|||
};
|
||||
|
||||
return {};
|
||||
}
|
||||
});
|
||||
|
||||
function filterData(obj, allowedKeys) {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import {I18nextProvider, withNamespaces} from 'react-i18next';
|
||||
import i18n from 'i18next';
|
||||
import {withNamespaces} from "react-i18next";
|
||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||
import mailtrainConfig from 'mailtrainConfig';
|
||||
|
||||
|
@ -63,12 +63,30 @@ i18n
|
|||
export default i18n;
|
||||
|
||||
|
||||
export const withTranslation = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
||||
return {
|
||||
cls: withNamespaces()(TargetClass)
|
||||
};
|
||||
export const TranslationContext = React.createContext(null);
|
||||
|
||||
export const withTranslation = createComponentMixin({
|
||||
contexts: [{context: TranslationContext, propName: 't'}]
|
||||
});
|
||||
|
||||
const TranslationContextProvider = withNamespaces()(props => {
|
||||
return (
|
||||
<TranslationContext.Provider value={props.t}>
|
||||
{props.children}
|
||||
</TranslationContext.Provider>
|
||||
);
|
||||
});
|
||||
|
||||
export function TranslationRoot(props) {
|
||||
return (
|
||||
<I18nextProvider i18n={ i18n }>
|
||||
<TranslationContextProvider>
|
||||
{props.children}
|
||||
</TranslationContextProvider>
|
||||
</I18nextProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export function tMark(key) {
|
||||
return key;
|
||||
}
|
||||
|
|
|
@ -354,30 +354,34 @@ export function renderRoute(route, panelRouteCtor, loadingMessageFn, flashMessag
|
|||
}
|
||||
|
||||
export const SectionContentContext = React.createContext(null);
|
||||
export const withPageHelpers = createComponentMixin([{context: SectionContentContext, propName: 'sectionContent'}], [withErrorHandling], (TargetClass, InnerClass) => {
|
||||
InnerClass.prototype.setFlashMessage = function(severity, text) {
|
||||
export const withPageHelpers = createComponentMixin({
|
||||
contexts: [{context: SectionContentContext, propName: 'sectionContent'}],
|
||||
deps: [withErrorHandling],
|
||||
decoratorFn: (TargetClass, InnerClass) => {
|
||||
InnerClass.prototype.setFlashMessage = function (severity, text) {
|
||||
return this.props.sectionContent.setFlashMessage(severity, text);
|
||||
};
|
||||
|
||||
InnerClass.prototype.navigateTo = function(path) {
|
||||
InnerClass.prototype.navigateTo = function (path) {
|
||||
return this.props.sectionContent.navigateTo(path);
|
||||
};
|
||||
|
||||
InnerClass.prototype.navigateBack = function() {
|
||||
InnerClass.prototype.navigateBack = function () {
|
||||
return this.props.sectionContent.navigateBack();
|
||||
};
|
||||
|
||||
InnerClass.prototype.navigateToWithFlashMessage = function(path, severity, text) {
|
||||
InnerClass.prototype.navigateToWithFlashMessage = function (path, severity, text) {
|
||||
return this.props.sectionContent.navigateToWithFlashMessage(path, severity, text);
|
||||
};
|
||||
|
||||
InnerClass.prototype.registerBeforeUnloadHandlers = function(handlers) {
|
||||
InnerClass.prototype.registerBeforeUnloadHandlers = function (handlers) {
|
||||
return this.props.sectionContent.registerBeforeUnloadHandlers(handlers);
|
||||
};
|
||||
|
||||
InnerClass.prototype.deregisterBeforeUnloadHandlers = function(handlers) {
|
||||
InnerClass.prototype.deregisterBeforeUnloadHandlers = function (handlers) {
|
||||
return this.props.sectionContent.deregisterBeforeUnloadHandlers(handlers);
|
||||
};
|
||||
|
||||
return {};
|
||||
}
|
||||
});
|
||||
|
|
|
@ -683,7 +683,9 @@ export class NavDropdown extends Component {
|
|||
}
|
||||
|
||||
|
||||
export const requiresAuthenticatedUser = createComponentMixin([], [withPageHelpers], (TargetClass, InnerClass) => {
|
||||
export const requiresAuthenticatedUser = createComponentMixin({
|
||||
deps: [withPageHelpers],
|
||||
decoratorFn: (TargetClass, InnerClass) => {
|
||||
class RequiresAuthenticatedUser extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
@ -698,6 +700,7 @@ export const requiresAuthenticatedUser = createComponentMixin([], [withPageHelpe
|
|||
return {
|
||||
cls: RequiresAuthenticatedUser
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
export function getLanguageChooser(t) {
|
||||
|
|
|
@ -4,8 +4,7 @@ import './public-path';
|
|||
|
||||
import React, {Component} from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import {I18nextProvider} from 'react-i18next';
|
||||
import i18n, {withTranslation} from './i18n';
|
||||
import {TranslationRoot, withTranslation} from './i18n';
|
||||
import {parentRPC, UntrustedContentRoot} from './untrusted';
|
||||
import PropTypes from "prop-types";
|
||||
import styles from "./sandboxed-ckeditor.scss";
|
||||
|
@ -126,9 +125,9 @@ export default function() {
|
|||
parentRPC.init();
|
||||
|
||||
ReactDOM.render(
|
||||
<I18nextProvider i18n={ i18n }>
|
||||
<TranslationRoot>
|
||||
<UntrustedContentRoot render={props => <CKEditorSandbox {...props} />} />
|
||||
</I18nextProvider>,
|
||||
</TranslationRoot>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
};
|
||||
|
|
|
@ -4,8 +4,7 @@ import './public-path';
|
|||
|
||||
import React, {Component} from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import {I18nextProvider} from 'react-i18next';
|
||||
import i18n, {withTranslation} from './i18n';
|
||||
import {TranslationRoot, withTranslation} from './i18n';
|
||||
import {parentRPC, UntrustedContentRoot} from './untrusted';
|
||||
import PropTypes from "prop-types";
|
||||
import styles from "./sandboxed-codeeditor.scss";
|
||||
|
@ -211,9 +210,9 @@ export default function() {
|
|||
parentRPC.init();
|
||||
|
||||
ReactDOM.render(
|
||||
<I18nextProvider i18n={ i18n }>
|
||||
<TranslationRoot>
|
||||
<UntrustedContentRoot render={props => <CodeEditorSandbox {...props} />} />
|
||||
</I18nextProvider>,
|
||||
</TranslationRoot>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
};
|
||||
|
|
|
@ -4,8 +4,7 @@ import './public-path';
|
|||
|
||||
import React, {Component} from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import {I18nextProvider} from 'react-i18next';
|
||||
import i18n, {withTranslation} from './i18n';
|
||||
import {TranslationRoot, withTranslation} from './i18n';
|
||||
import {parentRPC, UntrustedContentRoot} from './untrusted';
|
||||
import PropTypes from "prop-types";
|
||||
import {getPublicUrl, getSandboxUrl, getTrustedUrl} from "./urls";
|
||||
|
@ -626,9 +625,9 @@ export default function() {
|
|||
parentRPC.init();
|
||||
|
||||
ReactDOM.render(
|
||||
<I18nextProvider i18n={ i18n }>
|
||||
<TranslationRoot>
|
||||
<UntrustedContentRoot render={props => <GrapesJSSandbox {...props} />} />
|
||||
</I18nextProvider>,
|
||||
</TranslationRoot>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
};
|
||||
|
|
|
@ -4,8 +4,7 @@ import './public-path';
|
|||
|
||||
import React, {Component} from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import {I18nextProvider} from 'react-i18next';
|
||||
import i18n, {withTranslation} from './i18n';
|
||||
import {TranslationRoot, withTranslation} from './i18n';
|
||||
import {parentRPC, UntrustedContentRoot} from './untrusted';
|
||||
import PropTypes from "prop-types";
|
||||
import {getPublicUrl, getSandboxUrl, getTrustedUrl} from "./urls";
|
||||
|
@ -149,9 +148,9 @@ export default function() {
|
|||
parentRPC.init();
|
||||
|
||||
ReactDOM.render(
|
||||
<I18nextProvider i18n={ i18n }>
|
||||
<TranslationRoot>
|
||||
<UntrustedContentRoot render={props => <MosaicoSandbox {...props} />} />
|
||||
</I18nextProvider>,
|
||||
</TranslationRoot>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
};
|
||||
|
|
|
@ -82,11 +82,13 @@ export default class CUD extends Component {
|
|||
this.removeNsIdSubtree(data);
|
||||
}
|
||||
|
||||
if (this.isComponentMounted()) {
|
||||
this.setState({
|
||||
treeData: data
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.entity) {
|
||||
|
@ -191,7 +193,7 @@ export default class CUD extends Component {
|
|||
render() {
|
||||
const t = this.props.t;
|
||||
const isEdit = !!this.props.entity;
|
||||
const canDelete = isEdit && !this.isEditGlobal() && this.props.entity.permissions.includes('delete');
|
||||
const canDelete = isEdit && !this.isEditGlobal() && mailtrainConfig.user.namespace !== this.props.entity.id && this.props.entity.permissions.includes('delete');
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
|
|
@ -10,6 +10,7 @@ import {checkPermissions} from "../lib/permissions";
|
|||
import {tableAddDeleteButton, tableRestActionDialogInit, tableRestActionDialogRender} from "../lib/modals";
|
||||
import {getGlobalNamespaceId} from "../../../shared/namespaces";
|
||||
import {withComponentMixins} from "../lib/decorator-helpers";
|
||||
import mailtrainConfig from 'mailtrainConfig';
|
||||
|
||||
@withComponentMixins([
|
||||
withTranslation,
|
||||
|
@ -64,7 +65,8 @@ export default class List extends Component {
|
|||
});
|
||||
}
|
||||
|
||||
if (Number.parseInt(node.key) !== getGlobalNamespaceId()) {
|
||||
const namespaceId = Number.parseInt(node.key);
|
||||
if (namespaceId !== getGlobalNamespaceId() && mailtrainConfig.user.namespace !== namespaceId) {
|
||||
tableAddDeleteButton(actions, this, node.data.permissions, `rest/namespaces/${node.key}`, node.data.unsanitizedTitle, t('deletingNamespace'), t('namespaceDeleted'));
|
||||
}
|
||||
|
||||
|
|
|
@ -4,8 +4,7 @@ import './lib/public-path';
|
|||
|
||||
import React, {Component} from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import {I18nextProvider} from 'react-i18next';
|
||||
import i18n, {withTranslation} from './lib/i18n';
|
||||
import {TranslationRoot, withTranslation} from './lib/i18n';
|
||||
import account from './account/root';
|
||||
import login from './login/root';
|
||||
import blacklist from './blacklist/root';
|
||||
|
@ -139,7 +138,7 @@ class Root extends Component {
|
|||
}
|
||||
|
||||
export default function() {
|
||||
ReactDOM.render(<I18nextProvider i18n={ i18n }><Root/></I18nextProvider>,document.getElementById('root'));
|
||||
ReactDOM.render(<TranslationRoot><Root/></TranslationRoot>,document.getElementById('root'));
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -37,17 +37,12 @@ async function ensureNoDependencies(tx, context, id, depSpecs) {
|
|||
name: row.name,
|
||||
link: entityType.clientLink(row.id)
|
||||
});
|
||||
} else if (await shares.checkEntityPermissionTx(tx, context, depSpec.entityTypeId, row.id, 'view')) {
|
||||
} else if (!depSpec.viewPermission && await shares.checkEntityPermissionTx(tx, context, depSpec.entityTypeId, row.id, 'view')) {
|
||||
deps.push({
|
||||
entityTypeId: depSpec.entityTypeId,
|
||||
name: row.name,
|
||||
link: entityType.clientLink(row.id)
|
||||
});
|
||||
} else {
|
||||
deps.push({
|
||||
entityTypeId: depSpec.entityTypeId,
|
||||
id: row.id
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue