diff --git a/packages/vulcan-forms-upload/lib/Upload.jsx b/packages/vulcan-forms-upload/lib/Upload.jsx
index 31fec2bbe3..77dd5272e3 100755
--- a/packages/vulcan-forms-upload/lib/Upload.jsx
+++ b/packages/vulcan-forms-upload/lib/Upload.jsx
@@ -16,7 +16,6 @@ import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import Dropzone from 'react-dropzone';
import 'cross-fetch/polyfill'; // patch for browser which don't have fetch implemented
-import { FormattedMessage } from 'meteor/vulcan:i18n';
import set from 'lodash/set';
registerSetting('cloudinary.cloudName', null, 'Cloudinary cloud name (for image uploads)');
@@ -302,12 +301,12 @@ class Upload extends PureComponent {
-
+
{uploading && (
-
+
)}
diff --git a/packages/vulcan-forms/lib/components/FormComponent.jsx b/packages/vulcan-forms/lib/components/FormComponent.jsx
index c97202ce43..c1fb222bd6 100644
--- a/packages/vulcan-forms/lib/components/FormComponent.jsx
+++ b/packages/vulcan-forms/lib/components/FormComponent.jsx
@@ -31,8 +31,8 @@ class FormComponent extends Component {
return null;
}
const path = getPath(props);
- const value = get(document, path);
-
+ const intlOrRegularValue = get(document, path);
+ const value = typeof intlOrRegularValue === 'object' ? intlOrRegularValue.value : intlOrRegularValue;
return getCharacterCounts(value, max);
}
diff --git a/packages/vulcan-forms/lib/components/FormComponentLoader.jsx b/packages/vulcan-forms/lib/components/FormComponentLoader.jsx
index a40642a2e5..f0a4d77b2d 100644
--- a/packages/vulcan-forms/lib/components/FormComponentLoader.jsx
+++ b/packages/vulcan-forms/lib/components/FormComponentLoader.jsx
@@ -29,12 +29,13 @@ const FormComponentLoader = props => {
throw new Error(error);
}
- if (loading)
+ if (loading){
return (
);
+ }
// pass newly loaded data (and options if needed) to child component
const extraProps = { data, queryData: data, queryError: error, loading };
diff --git a/packages/vulcan-forms/lib/components/FormDescription.jsx b/packages/vulcan-forms/lib/components/FormDescription.jsx
new file mode 100644
index 0000000000..85e0b5d794
--- /dev/null
+++ b/packages/vulcan-forms/lib/components/FormDescription.jsx
@@ -0,0 +1,13 @@
+import React from 'react';
+import { registerComponent } from 'meteor/vulcan:core';
+import Form from 'react-bootstrap/Form';
+
+const FormDescription = ({ description }) => {
+ return (
+
+
+
+ );
+};
+
+registerComponent('FormDescription', FormDescription);
diff --git a/packages/vulcan-forms/lib/components/FormError.jsx b/packages/vulcan-forms/lib/components/FormError.jsx
index d1449a0d06..588ecf4c57 100644
--- a/packages/vulcan-forms/lib/components/FormError.jsx
+++ b/packages/vulcan-forms/lib/components/FormError.jsx
@@ -1,8 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import getContext from 'recompose/getContext';
-import { registerComponent } from 'meteor/vulcan:core';
-import { FormattedMessage } from 'meteor/vulcan:i18n';
+import { Components, registerComponent } from 'meteor/vulcan:core';
import get from 'lodash/get';
const FormError = ({ error, errorContext, getLabel }) => {
@@ -48,7 +47,7 @@ const FormError = ({ error, errorContext, getLabel }) => {
values: exception.data,
};
}
- return
;
+ return
;
};
FormError.defaultProps = {
diff --git a/packages/vulcan-forms/lib/components/FormSubmit.jsx b/packages/vulcan-forms/lib/components/FormSubmit.jsx
index 49137019cf..066ce6b6e5 100644
--- a/packages/vulcan-forms/lib/components/FormSubmit.jsx
+++ b/packages/vulcan-forms/lib/components/FormSubmit.jsx
@@ -2,7 +2,6 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Components } from 'meteor/vulcan:core';
import { registerComponent } from 'meteor/vulcan:core';
-import { FormattedMessage } from 'meteor/vulcan:i18n';
const FormSubmit = ({
submitForm,
@@ -21,7 +20,7 @@ const FormSubmit = ({
}) => (
- {submitLabel ? submitLabel : }
+ {submitLabel ? submitLabel : }
{cancelCallback ? (
@@ -32,7 +31,7 @@ const FormSubmit = ({
cancelCallback(document);
}}
>
- {cancelLabel ? cancelLabel :
}
+ {cancelLabel ? cancelLabel :
}
) : null}
@@ -45,7 +44,7 @@ const FormSubmit = ({
revertCallback(document);
}}
>
- {revertLabel ? revertLabel :
}
+ {revertLabel ? revertLabel :
}
) : null}
@@ -53,7 +52,7 @@ const FormSubmit = ({
-
+
) : null}
diff --git a/packages/vulcan-forms/lib/modules/components.js b/packages/vulcan-forms/lib/modules/components.js
index 70bae3a573..bf9e342cb5 100644
--- a/packages/vulcan-forms/lib/modules/components.js
+++ b/packages/vulcan-forms/lib/modules/components.js
@@ -16,3 +16,4 @@ import '../components/Form.jsx';
import '../components/FormLayout.jsx';
import '../components/FormComponentLoader.jsx';
import '../components/FormOptionLabel.jsx';
+import '../components/FormDescription.jsx';
diff --git a/packages/vulcan-i18n/lib/modules/message.js b/packages/vulcan-i18n/lib/modules/message.js
index f6736bc2dc..ab4f446bf0 100644
--- a/packages/vulcan-i18n/lib/modules/message.js
+++ b/packages/vulcan-i18n/lib/modules/message.js
@@ -1,5 +1,6 @@
import React, { Component } from 'react';
import { intlShape } from './shape';
+import { registerComponent } from 'meteor/vulcan:lib';
const FormattedMessage = ({ id, values, defaultMessage = '', html = false, className = '' }, { intl }) => {
let message = intl.formatMessage({ id, defaultMessage }, values);
@@ -11,12 +12,14 @@ const FormattedMessage = ({ id, values, defaultMessage = '', html = false, class
}
return html ?
-
:
-
{message};
+
:
+
{message};
};
FormattedMessage.contextTypes = {
intl: intlShape
};
-export default FormattedMessage;
+registerComponent('FormattedMessage', FormattedMessage);
+
+export default FormattedMessage;
\ No newline at end of file
diff --git a/packages/vulcan-lib/lib/modules/collections.js b/packages/vulcan-lib/lib/modules/collections.js
index 30f5eb2d76..a79d6cd558 100644
--- a/packages/vulcan-lib/lib/modules/collections.js
+++ b/packages/vulcan-lib/lib/modules/collections.js
@@ -85,7 +85,7 @@ Mongo.Collection.prototype.addField = function (fieldOrFieldArray) {
});
// add field schema to collection schema
- collection.attachSchema(createSchema(merge(collection.simpleSchema()._schema, fieldSchema)));
+ collection.attachSchema(createSchema(merge(collection.options.schema, fieldSchema)));
};
/**
diff --git a/packages/vulcan-lib/lib/modules/routes.ts b/packages/vulcan-lib/lib/modules/routes.ts
new file mode 100644
index 0000000000..aeac7dc35d
--- /dev/null
+++ b/packages/vulcan-lib/lib/modules/routes.ts
@@ -0,0 +1,168 @@
+import { Components, getComponent } from './components';
+
+export type Route = {
+ name: string;
+ path: string;
+ componentName?: string,
+ layoutName?: string,
+}
+
+export const Routes = new Map(); // will be populated on startup
+export const RoutesTable = new Map(); // storage for infos about routes themselves
+
+/*
+ A route is defined in the list like:
+ RoutesTable.foobar = {
+ name: 'foobar',
+ path: '/xyz',
+ component: getComponent('FooBar')
+ componentName: 'FooBar' // optional
+ }
+
+ if there there is value for parentRouteName it will look for the route and add the new route as a child of it
+ */
+export const addRoute = (routeOrRouteArray: Route|Array
, parentRouteName?: string) => {
+
+ // be sure to have an array of routes to manipulate
+ const addedRoutes = Array.isArray(routeOrRouteArray) ? routeOrRouteArray : [routeOrRouteArray];
+
+ // if there is a value for parentRouteName you are adding this route as new child
+ if (parentRouteName) {
+
+ addAsChildRoute(parentRouteName, addedRoutes);
+
+ } else {
+
+ // modify the routes table with the new routes
+ addedRoutes.forEach(({ name, path, ...properties }) => {
+
+ // check if there is already a route registered to this path
+ const routeWithSamePath = Object.values(RoutesTable).find(route => route.path === path);
+
+ if (routeWithSamePath) {
+ // delete the route registered with same path
+ delete RoutesTable[routeWithSamePath.name];
+ }
+
+ // register the new route
+ RoutesTable[name] = {
+ name,
+ path,
+ ...properties
+ };
+
+ });
+ }
+};
+
+export const extendRoute = (routeName, routeProps) => {
+
+ const route = Object.values(RoutesTable).find(route => route.name === routeName);
+
+ if (route) {
+ RoutesTable[route.name] = {
+ ...route,
+ ...routeProps
+ };
+ }
+};
+
+
+/**
+ A route is defined in the list like: (same as above)
+ RoutesTable.foobar = {
+ name: 'foobar',
+ path: '/xyz',
+ component: getComponent('FooBar')
+ componentName: 'FooBar' // optional
+ }
+
+ NOTE: This is implemented on single level deep ONLY for now
+ **/
+
+
+export const addAsChildRoute = (parentRouteName, addedRoutes) => {
+
+ // if the parentRouteName does not exist, error
+ if (!RoutesTable[parentRouteName]) {
+ throw new Error(`Route ${parentRouteName} doesn't exist`);
+ }
+
+ // modify the routes table with the new routes
+ addedRoutes.map(({ name, path, ...properties }) => {
+
+ // get the current child routes for this Route
+ const childRoutes = RoutesTable[parentRouteName]['childRoutes'] || [];
+
+ // check if there is already a route registered to this path
+ const routeWithSamePath = childRoutes.find(route => route.path === path);
+
+ if (routeWithSamePath) {
+ // delete the route registered with same path
+ delete childRoutes[routeWithSamePath.name];
+ }
+
+ // append to the child routes the new route
+ childRoutes.push({
+ name,
+ path,
+ ...properties
+ });
+
+ // register the new child route (overwriting the current which is fine)
+ RoutesTable[parentRouteName]['childRoutes'] = childRoutes;
+
+ });
+};
+
+
+export const getRoute = name => {
+ const routeDef = RoutesTable[name];
+
+ // components should be loaded by now (populateComponentsApp function), we can grab the component in the lookup table and assign it to the route
+ if (!routeDef.component && routeDef.componentName) {
+ routeDef.component = getComponent(routeDef.componentName);
+ }
+
+ return routeDef;
+};
+
+export const getChildRoute = (name, index) => {
+ const routeDef = RoutesTable[name]['childRoutes'][index];
+
+ // components should be loaded by now (populateComponentsApp function), we can grab the component in the lookup table and assign it to the route
+ if (!routeDef.component && routeDef.componentName) {
+ routeDef.component = getComponent(routeDef.componentName);
+ }
+
+ return routeDef;
+};
+
+/**
+ * Populate the lookup table for routes to be callable
+ * ℹ️ Called once on app startup
+ **/
+export const populateRoutesApp = () => {
+ // loop over each component in the list
+ Object.keys(RoutesTable).map(name => {
+ // loop over child routes if available
+ if (typeof RoutesTable[name]['childRoutes'] !== typeof undefined) {
+ RoutesTable[name]['childRoutes'].map((item, index) => {
+ RoutesTable[name]['childRoutes'][index] = getChildRoute(name, index);
+ });
+ }
+
+ // populate an entry in the lookup table
+ Routes[name] = getRoute(name);
+
+ // uncomment for debug
+ // console.log('init route:', name);
+ });
+};
+
+// Should be used only in tests
+export const emptyRoutes = () => {
+ Object.keys(Routes).map((key) => {
+ delete Routes[key];
+ });
+};
diff --git a/packages/vulcan-lib/lib/server/debug.js b/packages/vulcan-lib/lib/server/debug.js
index 4f0ff89074..2d4916c103 100644
--- a/packages/vulcan-lib/lib/server/debug.js
+++ b/packages/vulcan-lib/lib/server/debug.js
@@ -1,7 +1,7 @@
import { GraphQLSchema } from './graphql/graphql.js';
import { generateTypeDefs } from './graphql/typedefs.js';
import Vulcan from '../modules/config.js';
-import fs from 'fs';
+import fs, { promises as fsAsync } from 'fs';
import { Collections } from '../modules/collections.js';
import { extractCollectionInfo, extractFragmentInfo } from '../modules/handleOptions';
@@ -35,7 +35,9 @@ export const getGraphQLSchema = fileName => {
Vulcan.getGraphQLSchema = getGraphQLSchema;
-export const logToFile = (fileName, object, options = {}) => {
+const logsDirectory = '.logs';
+
+export const logToFile = async (fileName, object, options = {}) => {
const { mode = 'append', timestamp = false } = options;
// the server path is of type "/Users/foo/bar/appName/.meteor/local/build/programs/server"
// we remove the last five segments to get the app directory
@@ -44,13 +46,17 @@ export const logToFile = (fileName, object, options = {}) => {
.split('/')
.slice(1, -5)
.join('/');
- const fullPath = `/${path}/${fileName}`;
+ const logsDirPath = `/${path}/${logsDirectory}`;
+ if (!fs.existsSync(logsDirPath)) {
+ fs.mkdirSync(logsDirPath, { recursive: true });
+ }
+ const fullPath = `${logsDirPath}/${fileName}`;
const contents = typeof object === 'string' ? object : JSON.stringify(object, null, 2);
const now = new Date();
const text = timestamp ? now.toString() + '\n---\n' + contents : contents;
if (mode === 'append') {
const stream = fs.createWriteStream(fullPath, { flags: 'a' });
- stream.write(text + '\n\n');
+ stream.write(text + '\n');
stream.end();
} else {
fs.writeFile(fullPath, text, error => {
@@ -84,11 +90,11 @@ export const generateGraphQLQueries = fileName => {
.slice(1, -5)
.join('/');
const fullPath = `/${path}/${name}`;
- fd = fs.openSync(fullPath, 'w');
+ fd = fsAsync.openSync(fullPath, 'w');
- Object.keys(Fragments).forEach(fragment => fs.appendFileSync(fd, Fragments[fragment].fragmentText + '\n'));
+ Object.keys(Fragments).forEach(fragment => fsAsync.appendFileSync(fd, Fragments[fragment].fragmentText + '\n'));
- fs.appendFileSync(fd, '\n');
+ fsAsync.appendFileSync(fd, '\n');
Collections.forEach(collection => {
const { collectionName } = extractCollectionInfo({ collection });
@@ -101,7 +107,7 @@ export const generateGraphQLQueries = fileName => {
typeName,
fragmentName,
});
- fs.appendFileSync(fd, singleQueryString + '\n');
+ fsAsync.appendFileSync(fd, singleQueryString + '\n');
}
if (get(GraphQLSchema.resolvers, `Query.${Utils.camelCaseify(Utils.pluralize(typeName))}`)) {
@@ -109,13 +115,13 @@ export const generateGraphQLQueries = fileName => {
typeName,
fragmentName,
});
- fs.appendFileSync(fd, multiQueryString + '\n');
+ fsAsync.appendFileSync(fd, multiQueryString + '\n');
}
});
} catch (err) {
console.log(err);
} finally {
- if (fd !== undefined) fs.closeSync(fd);
+ if (fd !== undefined) fsAsync.closeSync(fd);
}
};
diff --git a/packages/vulcan-newsletter/lib/components/NewsletterSubscribe.jsx b/packages/vulcan-newsletter/lib/components/NewsletterSubscribe.jsx
index 994a90e5ee..d0b5e133ce 100644
--- a/packages/vulcan-newsletter/lib/components/NewsletterSubscribe.jsx
+++ b/packages/vulcan-newsletter/lib/components/NewsletterSubscribe.jsx
@@ -1,7 +1,6 @@
import { Components, registerComponent, withMutation, withMessages } from 'meteor/vulcan:core';
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
-import { FormattedMessage } from 'meteor/vulcan:i18n';
// this component is used as a custom controller in user's account edit (cf. ./custom_fields.js)
class NewsletterSubscribe extends PureComponent {
@@ -44,7 +43,7 @@ class NewsletterSubscribe extends PureComponent {
onClick={this.subscribeUnsubscribe}
variant="primary"
>
-
+
diff --git a/packages/vulcan-subscribe/lib/components/SubscribeTo.jsx b/packages/vulcan-subscribe/lib/components/SubscribeTo.jsx
index 3f7654b1a0..5fc0b1b7bf 100644
--- a/packages/vulcan-subscribe/lib/components/SubscribeTo.jsx
+++ b/packages/vulcan-subscribe/lib/components/SubscribeTo.jsx
@@ -1,11 +1,11 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
-import { intlShape, FormattedMessage } from 'meteor/vulcan:i18n';
+import { intlShape } from 'meteor/vulcan:i18n';
import { graphql } from '@apollo/client/react/hoc';
import compose from 'recompose/compose';
import gql from 'graphql-tag';
import Users from 'meteor/vulcan:users';
-import { withCurrentUser, withMessages, registerComponent, Utils } from 'meteor/vulcan:core';
+import { Components, withCurrentUser, withMessages, registerComponent, Utils } from 'meteor/vulcan:core';
// boolean -> unsubscribe || subscribe
const getSubscribeAction = subscribed => subscribed ? 'unsubscribe' : 'subscribe';
@@ -61,7 +61,7 @@ class SubscribeToActionHandler extends PureComponent {
const className = this.props.className ? this.props.className : '';
- return Users.canDo(currentUser, action) ?
: null;
+ return Users.canDo(currentUser, action) ?
: null;
}
}
diff --git a/packages/vulcan-ui-bootstrap/lib/components/forms/Date2.jsx b/packages/vulcan-ui-bootstrap/lib/components/forms/Date2.jsx
index 6db0661d84..27b14f26a4 100644
--- a/packages/vulcan-ui-bootstrap/lib/components/forms/Date2.jsx
+++ b/packages/vulcan-ui-bootstrap/lib/components/forms/Date2.jsx
@@ -1,7 +1,6 @@
import React, { PureComponent } from 'react';
import { Components, registerComponent } from 'meteor/vulcan:core';
import moment from 'moment';
-import { FormattedMessage } from 'meteor/vulcan:i18n';
const isEmptyValue = value =>
typeof value === 'undefined' ||
@@ -129,7 +128,7 @@ class DateComponent2 extends PureComponent {
diff --git a/packages/vulcan-ui-bootstrap/lib/components/forms/FormComponentInner.jsx b/packages/vulcan-ui-bootstrap/lib/components/forms/FormComponentInner.jsx
index d649cf2333..4868c35984 100644
--- a/packages/vulcan-ui-bootstrap/lib/components/forms/FormComponentInner.jsx
+++ b/packages/vulcan-ui-bootstrap/lib/components/forms/FormComponentInner.jsx
@@ -1,6 +1,6 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
-import { FormattedMessage, intlShape } from 'meteor/vulcan:i18n';
+import { intlShape } from 'meteor/vulcan:i18n';
import { Components, registerComponent, instantiateComponent, whitelistInputProps } from 'meteor/vulcan:core';
import classNames from 'classnames';
@@ -17,7 +17,7 @@ class FormComponentInner extends PureComponent {
✕
}>
-
+
);
}
diff --git a/packages/vulcan-ui-bootstrap/lib/components/forms/FormItem.jsx b/packages/vulcan-ui-bootstrap/lib/components/forms/FormItem.jsx
index e528737fed..87d60ac624 100644
--- a/packages/vulcan-ui-bootstrap/lib/components/forms/FormItem.jsx
+++ b/packages/vulcan-ui-bootstrap/lib/components/forms/FormItem.jsx
@@ -34,11 +34,7 @@ const FormItem = props => {
{beforeInput}
{innerComponent}
{afterInput}
- {description && (
-
-
-
- )}
+ {description && }
);
} else if (layout === 'vertical') {
@@ -52,11 +48,7 @@ const FormItem = props => {
{innerComponent}
{afterInput}
- {description && (
-
-
-
- )}
+ {description &&
}
);
@@ -69,11 +61,7 @@ const FormItem = props => {
{beforeInput}
{innerComponent}
{afterInput}
- {description && (
-
-
-
- )}
+ {description &&
}
);
diff --git a/packages/vulcan-ui-bootstrap/lib/components/ui/Dropdown.jsx b/packages/vulcan-ui-bootstrap/lib/components/ui/Dropdown.jsx
index 2a9b37d7e6..360da95461 100644
--- a/packages/vulcan-ui-bootstrap/lib/components/ui/Dropdown.jsx
+++ b/packages/vulcan-ui-bootstrap/lib/components/ui/Dropdown.jsx
@@ -1,11 +1,10 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { registerComponent } from 'meteor/vulcan:lib';
+import { Components, registerComponent } from 'meteor/vulcan:lib';
import Dropdown from 'react-bootstrap/Dropdown';
import DropdownItem from 'react-bootstrap/DropdownItem';
import DropdownButton from 'react-bootstrap/DropdownButton';
import { LinkContainer } from 'react-router-bootstrap';
-import { FormattedMessage } from 'meteor/vulcan:i18n';
/*
@@ -40,7 +39,7 @@ const Item = ({ index, to, labelId, label, component, componentProps = {}, itemP
if (component) {
menuComponent = React.cloneElement(component, componentProps);
} else if (labelId) {
- menuComponent =
;
+ menuComponent =
;
} else {
menuComponent =
{label};
}
@@ -89,7 +88,7 @@ const BootstrapDropdown = ({ label, labelId, trigger, menuItems, menuContents, v
} else {
// else default to DropdownButton
return (
-
: label} {...dropdownProps}>
+
: label} {...dropdownProps}>
{menuBody}
);
diff --git a/packages/vulcan-ui-material/lib/components/bonus/LoadMore.jsx b/packages/vulcan-ui-material/lib/components/bonus/LoadMore.jsx
index 747c36c028..71dee2468f 100644
--- a/packages/vulcan-ui-material/lib/components/bonus/LoadMore.jsx
+++ b/packages/vulcan-ui-material/lib/components/bonus/LoadMore.jsx
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { FormattedMessage, intlShape } from 'meteor/vulcan:i18n';
+import { intlShape } from 'meteor/vulcan:i18n';
import { Components, registerComponent } from 'meteor/vulcan:core';
import withStyles from '@material-ui/core/styles/withStyles';
import Typography from '@material-ui/core/Typography';
@@ -72,7 +72,7 @@ const LoadMore = (
{showCount && (
-
+
)}
{isLoadingMore ? (
diff --git a/packages/vulcan-ui-material/lib/components/forms/FormErrors.jsx b/packages/vulcan-ui-material/lib/components/forms/FormErrors.jsx
index af03bb95d4..8bfb0f6c66 100644
--- a/packages/vulcan-ui-material/lib/components/forms/FormErrors.jsx
+++ b/packages/vulcan-ui-material/lib/components/forms/FormErrors.jsx
@@ -1,7 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { replaceComponent, Components } from 'meteor/vulcan:core';
-import { FormattedMessage } from 'meteor/vulcan:i18n';
import Snackbar from '@material-ui/core/Snackbar';
import withStyles from '@material-ui/core/styles/withStyles';
diff --git a/packages/vulcan-ui-material/lib/components/forms/FormSubmit.jsx b/packages/vulcan-ui-material/lib/components/forms/FormSubmit.jsx
index d4974e6ee3..067fb5d1b1 100644
--- a/packages/vulcan-ui-material/lib/components/forms/FormSubmit.jsx
+++ b/packages/vulcan-ui-material/lib/components/forms/FormSubmit.jsx
@@ -7,7 +7,6 @@ import Button from '@material-ui/core/Button';
import IconButton from '@material-ui/core/IconButton';
import DeleteIcon from 'mdi-material-ui/Delete';
import Tooltip from '@material-ui/core/Tooltip';
-import { FormattedMessage } from 'meteor/vulcan:i18n';
import classNames from 'classnames';
const styles = theme => ({
@@ -67,7 +66,7 @@ const FormSubmit = (
event.preventDefault();
cancelCallback(document);
}}>
- {cancelLabel ? cancelLabel : }
+ {cancelLabel ? cancelLabel : }
) : null}
@@ -81,7 +80,7 @@ const FormSubmit = (
clearForm({ clearErrors: true, clearCurrentValues: true, clearDeletedValues: true });
revertCallback(document);
}}>
- {revertLabel ? revertLabel : }
+ {revertLabel ? revertLabel : }
) : null}
@@ -91,7 +90,7 @@ const FormSubmit = (
color="secondary"
className={classNames('submit-button', classes.button)}
disabled={!isChanged()}>
- {submitLabel ? submitLabel : }
+ {submitLabel ? submitLabel : }
);
diff --git a/packages/vulcan-ui-material/lib/components/upload/UploadImage.jsx b/packages/vulcan-ui-material/lib/components/upload/UploadImage.jsx
index 529e3d2a8b..68a3a9f05b 100755
--- a/packages/vulcan-ui-material/lib/components/upload/UploadImage.jsx
+++ b/packages/vulcan-ui-material/lib/components/upload/UploadImage.jsx
@@ -1,7 +1,6 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { Components, registerComponent } from 'meteor/vulcan:lib';
-import { FormattedMessage } from 'meteor/vulcan:i18n';
import withStyles from '@material-ui/core/styles/withStyles';
import IconButton from '@material-ui/core/IconButton';
import DeleteIcon from 'mdi-material-ui/Delete';
diff --git a/packages/vulcan-ui-material/lib/components/upload/UploadInner.jsx b/packages/vulcan-ui-material/lib/components/upload/UploadInner.jsx
index 8f79e7235d..1ba4f3b681 100755
--- a/packages/vulcan-ui-material/lib/components/upload/UploadInner.jsx
+++ b/packages/vulcan-ui-material/lib/components/upload/UploadInner.jsx
@@ -3,7 +3,6 @@ import PropTypes from 'prop-types';
import { Components, registerComponent, getComponent } from 'meteor/vulcan:lib';
import Dropzone from 'react-dropzone';
import withStyles from '@material-ui/core/styles/withStyles';
-import { FormattedMessage } from 'meteor/vulcan:i18n';
import FormControl from '@material-ui/core/FormControl';
import FormLabel from '@material-ui/core/FormLabel';
import FormHelperText from '@material-ui/core/FormHelperText';
@@ -104,7 +103,7 @@ const UploadInner = props => {
rejectClassName={classes.dropzoneReject}
disabled={disabled}>
-
@@ -112,7 +111,7 @@ const UploadInner = props => {
{uploading && (
-
+
)}
From 51be9c2a9031a3cffb40bba2562fe7409b2dd662 Mon Sep 17 00:00:00 2001
From: SachaG <358832+SachaG@users.noreply.github.com>
Date: Mon, 14 Dec 2020 09:35:29 +0900
Subject: [PATCH 2/4] Improve User.owns
---
packages/vulcan-users/lib/modules/permissions.js | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/packages/vulcan-users/lib/modules/permissions.js b/packages/vulcan-users/lib/modules/permissions.js
index ade9cdeea7..f4a0b2874a 100644
--- a/packages/vulcan-users/lib/modules/permissions.js
+++ b/packages/vulcan-users/lib/modules/permissions.js
@@ -153,11 +153,14 @@ Users.canDo = (user, actionOrActions) => {
Users.owns = function(user, document) {
try {
if (!!document.userId) {
- // case 1: document is a post or a comment, use userId to check
+ // case 1: use userId to check
return user._id === document.userId;
- } else {
- // case 2: document is a user, use _id or slug to check
- return document.slug ? user.slug === document.slug : user._id === document._id;
+ } else if (document.user) {
+ // case 2: use user._id to check
+ return user._id === document.user._id;
+ }else {
+ // case 3: document is a user, use _id to check
+ return user._id === document._id;
}
} catch (e) {
return false; // user not logged in
From 3ac67764b024ea78e7a87d8abeed66d1145f215e Mon Sep 17 00:00:00 2001
From: SachaG <358832+SachaG@users.noreply.github.com>
Date: Mon, 14 Dec 2020 09:35:43 +0900
Subject: [PATCH 3/4] Escape _like regex
---
packages/vulcan-lib/lib/modules/mongoParams.js | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/packages/vulcan-lib/lib/modules/mongoParams.js b/packages/vulcan-lib/lib/modules/mongoParams.js
index 0309720ded..61d5a887db 100644
--- a/packages/vulcan-lib/lib/modules/mongoParams.js
+++ b/packages/vulcan-lib/lib/modules/mongoParams.js
@@ -22,6 +22,10 @@ export const convertUniqueSelector = selector => {
}
return selector;
};
+
+// see https://stackoverflow.com/a/3561711
+export const escapeRegex = s => s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
+
/*
Filtering
@@ -40,12 +44,12 @@ const conversionTable = {
_neq: '$ne',
_nin: '$nin',
_is_null: value => ({ $exists: !value }),
- _is: value => ({$elemMatch: {$eq: value }}),
- _contains: value => ({$elemMatch: {$eq: value }}),
+ _is: value => ({ $elemMatch: { $eq: value } }),
+ _contains: value => ({ $elemMatch: { $eq: value } }),
asc: 1,
desc: -1,
_like: value => ({
- $regex: value,
+ $regex: escapeRegex(value),
$options: 'i',
}),
};
@@ -59,7 +63,6 @@ const getFieldNames = expressionArray => {
};
export const filterFunction = async (collection, input = {}, context) => {
-
// eslint-disable-next-line no-unused-vars
const { filter, limit, sort, search, filterArguments, offset, id } = input;
let selector = {};
From 74fc9dc52c4d4d3f698599b0db508c465d4c49da Mon Sep 17 00:00:00 2001
From: SachaG <358832+SachaG@users.noreply.github.com>
Date: Mon, 14 Dec 2020 09:40:11 +0900
Subject: [PATCH 4/4] Better error handling
---
.../lib/components/ErrorCatcherContents.jsx | 4 ++--
packages/vulcan-errors/lib/components/ErrorCatcher.jsx | 10 ++++++----
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/packages/vulcan-debug/lib/components/ErrorCatcherContents.jsx b/packages/vulcan-debug/lib/components/ErrorCatcherContents.jsx
index 6a7075170a..1d6a2cf8d6 100644
--- a/packages/vulcan-debug/lib/components/ErrorCatcherContents.jsx
+++ b/packages/vulcan-debug/lib/components/ErrorCatcherContents.jsx
@@ -1,9 +1,9 @@
import React from 'react';
import { Components, replaceComponent } from 'meteor/vulcan:lib';
-const ErrorCatcherContents = ({ error }) => (
+const ErrorCatcherContents = ({ error, message }) => (
-
+
Here are some suggestions to help you fix this issue:
diff --git a/packages/vulcan-errors/lib/components/ErrorCatcher.jsx b/packages/vulcan-errors/lib/components/ErrorCatcher.jsx
index de14e6a62f..0974542777 100644
--- a/packages/vulcan-errors/lib/components/ErrorCatcher.jsx
+++ b/packages/vulcan-errors/lib/components/ErrorCatcher.jsx
@@ -15,6 +15,8 @@ import { withRouter } from 'react-router';
import React, { Component } from 'react';
import { Errors } from '../modules/errors.js';
+const getMessage = error => error.message || error.errorMessage;
+
class ErrorCatcher extends Component {
state = {
error: null,
@@ -25,7 +27,7 @@ class ErrorCatcher extends Component {
const { sourceVersion } = siteData;
this.setState({ error });
Errors.log({
- message: error.message,
+ message: getMessage(error),
error,
details: { ...errorInfo, sourceVersion },
currentUser,
@@ -47,15 +49,15 @@ class ErrorCatcher extends Component {
render() {
const { error } = this.state;
- return error ? : this.props.children;
+ return error ? : this.props.children;
}
}
registerComponent('ErrorCatcher', ErrorCatcher, withCurrentUser, withSiteData, withRouter);
-const ErrorCatcherContents = ({ error }) => (
+const ErrorCatcherContents = ({ error, message }) => (
-
+
);