+ {label && (
+
)
+ }
+ {required && !hideRequiredStar && (
+
+ {'*'}
+
+ )
+ }
+
+ {children}
+
+ {helpText}
+
+
+
+ );
+ }
+}
diff --git a/webapp/src/constants/action_types.js b/webapp/src/constants/action_types.js
index 18b00b59..a6303a3c 100644
--- a/webapp/src/constants/action_types.js
+++ b/webapp/src/constants/action_types.js
@@ -3,7 +3,10 @@ import {id} from '../manifest';
export const ACTION_TYPES = {
OPEN_SUBSCRIPTION_MODAL: id + '_open_subscription_modal',
CLOSE_SUBSCRIPTION_MODAL: id + '_close_subscription_modal',
+ OPEN_CREATE_CONFLUENCE_PAGE_MODAL: id + '_open_create_confluence_page_modal',
+ CLOSE_CREATE_CONFLUENCE_PAGE_MODAL: id + '_close_create_confluence_page_modal',
RECEIVED_SUBSCRIPTION: id + '_received_subscription',
RECEIVED_CONNECTED: id + '_connected',
RECEIVED_INSTANCE_STATUS: id + '_instance_status',
+ RECEIVED_CONFLUENCE_INSTANCE: id + '_received_confluence_instance',
};
diff --git a/webapp/src/hooks/index.js b/webapp/src/hooks/index.js
index 78e8004b..93ed0f83 100644
--- a/webapp/src/hooks/index.js
+++ b/webapp/src/hooks/index.js
@@ -1,6 +1,6 @@
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
-import {openSubscriptionModal, getChannelSubscription, getConnected} from '../actions';
+import {openSubscriptionModal, getChannelSubscription, getConnected, openCreateConfluencePageModal} from '../actions';
import {splitArgs} from '../utils';
import {sendEphemeralPost} from '../actions/subscription_modal';
@@ -45,4 +45,10 @@ export default class Hooks {
args: contextArgs,
});
}
+
+ createConfluencePage = (message) => {
+ this.store.dispatch(getConnected());
+ this.store.dispatch(openCreateConfluencePageModal(message));
+ return Promise.resolve({});
+ }
}
diff --git a/webapp/src/index.js b/webapp/src/index.js
index a0026348..c9f39aeb 100644
--- a/webapp/src/index.js
+++ b/webapp/src/index.js
@@ -4,6 +4,7 @@ import Hooks from './hooks';
import reducer from './reducers';
import SubscriptionModal from './components/subscription_modal';
+import CreateConfluencePage from './components/create_confluence_page_modal/create_confluence_page_modal';
//
// Define the plugin class that will register
@@ -12,9 +13,11 @@ import SubscriptionModal from './components/subscription_modal';
class PluginClass {
initialize(registry, store) {
registry.registerReducer(reducer);
+ registry.registerRootComponent(CreateConfluencePage);
registry.registerRootComponent(SubscriptionModal);
const hooks = new Hooks(store);
registry.registerSlashCommandWillBePostedHook(hooks.slashCommandWillBePostedHook);
+ registry.registerPostDropdownMenuAction('Create Confluence Page', hooks.createConfluencePage);
}
}
diff --git a/webapp/src/reducers/index.js b/webapp/src/reducers/index.js
index 3d523d39..060312cb 100644
--- a/webapp/src/reducers/index.js
+++ b/webapp/src/reducers/index.js
@@ -1,10 +1,12 @@
import {combineReducers} from 'redux';
-import {subscriptionModal, subscriptionEditModal, installedInstances, userConnected} from './subscription_modal';
+import {subscriptionModal, subscriptionEditModal, installedInstances, userConnected, createConfluencePageModal, spacesForConfluenceURL} from './subscription_modal';
export default combineReducers({
subscriptionModal,
subscriptionEditModal,
installedInstances,
userConnected,
+ createConfluencePageModal,
+ spacesForConfluenceURL,
});
diff --git a/webapp/src/reducers/subscription_modal.js b/webapp/src/reducers/subscription_modal.js
index 9d34a202..25f6c36f 100644
--- a/webapp/src/reducers/subscription_modal.js
+++ b/webapp/src/reducers/subscription_modal.js
@@ -29,6 +29,30 @@ export const subscriptionEditModal = (state = {}, action) => {
}
};
+export const spacesForConfluenceURL = (state = {}, action) => {
+ switch (action.type) {
+ case Constants.ACTION_TYPES.RECEIVED_CONFLUENCE_INSTANCE:
+ return {
+ spaces: action.data ? action.data : [],
+ };
+ default:
+ return state;
+ }
+};
+
+export const createConfluencePageModal = (state = {}, action) => {
+ switch (action.type) {
+ case Constants.ACTION_TYPES.OPEN_CREATE_CONFLUENCE_PAGE_MODAL:
+ return {
+ message: action.data.message,
+ };
+ case Constants.ACTION_TYPES.CLOSE_CREATE_CONFLUENCE_PAGE_MODAL:
+ return {};
+ default:
+ return state;
+ }
+};
+
export function installedInstances(state = [], action) {
// We're notified of the instance status at startup (through getConnected)
// and when we get a websocket instance_status event
diff --git a/webapp/src/selectors/index.js b/webapp/src/selectors/index.js
index b4e4681c..c9876e04 100644
--- a/webapp/src/selectors/index.js
+++ b/webapp/src/selectors/index.js
@@ -6,7 +6,19 @@ const isSubscriptionModalVisible = (state) => getPluginState(state).subscription
const isSubscriptionEditModalVisible = (state) => getPluginState(state).subscriptionEditModal;
+const isCreateConfluencePageModalVisible = (state) => getPluginState(state).createConfluencePageModal;
+
+const isInstalledInstances = (state) => getPluginState(state).installedInstances;
+
+const spacesForConfluenceURL = (state) => getPluginState(state).spacesForConfluenceURL;
+
+const isUserConnected = (state) => getPluginState(state).userConnected;
+
export default {
isSubscriptionModalVisible,
isSubscriptionEditModalVisible,
+ isCreateConfluencePageModalVisible,
+ isUserConnected,
+ isInstalledInstances,
+ spacesForConfluenceURL,
};
diff --git a/webapp/src/utils/styles.js b/webapp/src/utils/styles.js
new file mode 100644
index 00000000..3755423a
--- /dev/null
+++ b/webapp/src/utils/styles.js
@@ -0,0 +1,119 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import {changeOpacity} from 'mattermost-redux/utils/theme_utils';
+
+export const getStyleForReactSelect = (theme) => {
+ if (!theme) {
+ return null;
+ }
+
+ return {
+ menuPortal: (provided) => ({
+ ...provided,
+ zIndex: 9999,
+ }),
+ control: (provided, state) => ({
+ ...provided,
+ color: theme.theme.centerChannelColor,
+ background: theme.theme.centerChannelBg,
+
+ // Overwrittes the different states of border
+ borderColor: state.isFocused ? changeOpacity(theme.theme.centerChannelColor, 0.25) : changeOpacity(theme.theme.centerChannelColor, 0.12),
+
+ // Removes weird border around container
+ boxShadow: 'inset 0 1px 1px ' + changeOpacity(theme.theme.centerChannelColor, 0.075),
+ borderRadius: '2px',
+
+ '&:hover': {
+ borderColor: changeOpacity(theme.theme.centerChannelColor, 0.25),
+ },
+ }),
+ option: (provided, state) => ({
+ ...provided,
+ background: state.isFocused ? changeOpacity(theme.theme.centerChannelColor, 0.12) : theme.theme.centerChannelBg,
+ cursor: state.isDisabled ? 'not-allowed' : 'pointer',
+ color: theme.theme.centerChannelColor,
+ '&:hover': state.isDisabled ? {} : {
+ background: changeOpacity(theme.theme.centerChannelColor, 0.12),
+ },
+ }),
+ clearIndicator: (provided) => ({
+ ...provided,
+ width: '34px',
+ color: changeOpacity(theme.theme.centerChannelColor, 0.4),
+ transform: 'scaleX(1.15)',
+ marginRight: '-10px',
+ '&:hover': {
+ color: theme.theme.centerChannelColor,
+ },
+ }),
+ multiValue: (provided) => ({
+ ...provided,
+ background: changeOpacity(theme.theme.centerChannelColor, 0.15),
+ }),
+ multiValueLabel: (provided) => ({
+ ...provided,
+ color: theme.theme.centerChannelColor,
+ paddingBottom: '4px',
+ paddingLeft: '8px',
+ fontSize: '90%',
+ }),
+ multiValueRemove: (provided) => ({
+ ...provided,
+ transform: 'translateX(-2px) scaleX(1.15)',
+ color: changeOpacity(theme.theme.centerChannelColor, 0.4),
+ '&:hover': {
+ background: 'transparent',
+ },
+ }),
+ menu: (provided) => ({
+ ...provided,
+ color: theme.theme.centerChannelColor,
+ background: theme.theme.centerChannelBg,
+ border: '1px solid ' + changeOpacity(theme.theme.centerChannelColor, 0.2),
+ borderRadius: '0 0 2px 2px',
+ boxShadow: changeOpacity(theme.theme.centerChannelColor, 0.2) + ' 1px 3px 12px',
+ marginTop: '4px',
+ }),
+ input: (provided) => ({
+ ...provided,
+ color: theme.theme.centerChannelColor,
+ }),
+ placeholder: (provided) => ({
+ ...provided,
+ color: theme.theme.centerChannelColor,
+ }),
+ dropdownIndicator: (provided) => ({
+ ...provided,
+
+ '&:hover': {
+ color: theme.theme.centerChannelColor,
+ },
+ }),
+ singleValue: (provided) => ({
+ ...provided,
+ color: theme.theme.centerChannelColor,
+ }),
+ indicatorSeparator: (provided) => ({
+ ...provided,
+ display: 'none',
+ }),
+ };
+};
+
+export const getModalStyles = (theme) => ({
+ modalBody: {
+ padding: '2em 2em 3em',
+ color: theme.centerChannelColor,
+ backgroundColor: theme.centerChannelBg,
+ },
+ modalFooter: {
+ padding: '2rem 15px',
+ },
+ descriptionArea: {
+ height: 'auto',
+ width: '100%',
+ color: '#000',
+ },
+});