diff --git a/webapp/src/actions/index.ts b/webapp/src/actions/index.ts index 9d2d780d..186b79fd 100644 --- a/webapp/src/actions/index.ts +++ b/webapp/src/actions/index.ts @@ -10,6 +10,7 @@ import {APIError, ConnectedData, GitlabUsersData, LHSData, ShowRhsPluginActionDa import {Item} from 'src/types/gitlab_items'; import {GlobalState} from 'src/types/store'; import {getPluginState} from 'src/selectors'; +import {CommentBody, IssueBody} from 'src/types/gitlab_types'; export function getConnected(reminder = false) { return async (dispatch: Dispatch) => { @@ -179,7 +180,7 @@ export function getGitlabUser(userID: string) { }; } -export function openCreateIssueModal(postId) { +export function openCreateIssueModal(postId: string) { return { type: ActionTypes.OPEN_CREATE_ISSUE_MODAL, data: { @@ -188,7 +189,7 @@ export function openCreateIssueModal(postId) { }; } -export function openCreateIssueModalWithoutPost(title, channelId) { +export function openCreateIssueModalWithoutPost(title: string, channelId: string) { return { type: ActionTypes.OPEN_CREATE_ISSUE_MODAL_WITHOUT_POST, data: { @@ -204,8 +205,8 @@ export function closeCreateIssueModal() { }; } -export function createIssue(payload) { - return async (dispatch) => { +export function createIssue(payload: IssueBody) { + return async (dispatch: Dispatch) => { let data; try { data = await Client.createIssue(payload); @@ -213,7 +214,7 @@ export function createIssue(payload) { return {error}; } - const connected = await dispatch(checkAndHandleNotConnected(data)); + const connected = await checkAndHandleNotConnected(data as APIError)(dispatch); if (!connected) { return {error: data}; } @@ -221,7 +222,7 @@ export function createIssue(payload) { }; } -export function openAttachCommentToIssueModal(postId) { +export function openAttachCommentToIssueModal(postId: string) { return { type: ActionTypes.OPEN_ATTACH_COMMENT_TO_ISSUE_MODAL, data: { @@ -236,8 +237,8 @@ export function closeAttachCommentToIssueModal() { }; } -export function attachCommentToIssue(payload) { - return async (dispatch) => { +export function attachCommentToIssue(payload: CommentBody) { + return async (dispatch: Dispatch) => { let data; try { data = await Client.attachCommentToIssue(payload); @@ -245,7 +246,7 @@ export function attachCommentToIssue(payload) { return {error}; } - const connected = await dispatch(checkAndHandleNotConnected(data)); + const connected = await checkAndHandleNotConnected(data as APIError)(dispatch); if (!connected) { return {error: data}; } @@ -254,7 +255,7 @@ export function attachCommentToIssue(payload) { } export function getProjects() { - return async (dispatch, getState) => { + return async (dispatch: Dispatch) => { let data; try { data = await Client.getProjects(); @@ -262,7 +263,7 @@ export function getProjects() { return {error}; } - const connected = await checkAndHandleNotConnected(data)(dispatch, getState); + const connected = await checkAndHandleNotConnected(data as APIError)(dispatch); if (!connected) { return {error: data}; } @@ -276,8 +277,8 @@ export function getProjects() { }; } -export function getLabelOptions(projectID) { - return async (dispatch, getState) => { +export function getLabelOptions(projectID: number) { + return async (dispatch: Dispatch) => { let data; try { data = await Client.getLabels(projectID); @@ -285,7 +286,7 @@ export function getLabelOptions(projectID) { return {error}; } - const connected = await checkAndHandleNotConnected(data)(dispatch, getState); + const connected = await checkAndHandleNotConnected(data as APIError)(dispatch); if (!connected) { return {error: data}; } @@ -294,8 +295,8 @@ export function getLabelOptions(projectID) { }; } -export function getMilestoneOptions(projectID) { - return async (dispatch, getState) => { +export function getMilestoneOptions(projectID: number) { + return async (dispatch: Dispatch) => { let data; try { data = await Client.getMilestones(projectID); @@ -303,7 +304,7 @@ export function getMilestoneOptions(projectID) { return {error}; } - const connected = await checkAndHandleNotConnected(data)(dispatch, getState); + const connected = await checkAndHandleNotConnected(data as APIError)(dispatch); if (!connected) { return {error: data}; } @@ -312,8 +313,8 @@ export function getMilestoneOptions(projectID) { }; } -export function getAssigneeOptions(projectID) { - return async (dispatch, getState) => { +export function getAssigneeOptions(projectID: number) { + return async (dispatch: Dispatch, getState: () => GlobalState) => { let data; try { data = await Client.getAssignees(projectID); @@ -321,7 +322,7 @@ export function getAssigneeOptions(projectID) { return {error}; } - const connected = await checkAndHandleNotConnected(data)(dispatch, getState); + const connected = await checkAndHandleNotConnected(data as APIError)(dispatch); if (!connected) { return {error: data}; } diff --git a/webapp/src/client/client.ts b/webapp/src/client/client.ts index 284e4ab0..ab7781cf 100644 --- a/webapp/src/client/client.ts +++ b/webapp/src/client/client.ts @@ -5,6 +5,7 @@ import {Options} from 'mattermost-redux/types/client4'; import {Item, TooltipData} from 'src/types/gitlab_items'; import {APIError, ConnectedData, GitlabUsersData, LHSData, SubscriptionData} from 'src/types'; +import {CommentBody, IssueBody} from 'src/types/gitlab_types'; export default class Client { private url = ''; @@ -41,16 +42,15 @@ export default class Client { return this.doGet(`${this.url}/channel/${channelID}/subscriptions`); }; - - createIssue = async (payload) => { + createIssue = async (payload: IssueBody) => { return this.doPost(`${this.url}/issue`, payload); } - attachCommentToIssue = async (payload) => { + attachCommentToIssue = async (payload: CommentBody) => { return this.doPost(`${this.url}/attachcommenttoissue`, payload); } - searchIssues = async (searchTerm) => { + searchIssues = async (searchTerm: string) => { return this.doGet(`${this.url}/searchissues?search=${searchTerm}`); } @@ -58,15 +58,15 @@ export default class Client { return this.doGet(`${this.url}/projects`); } - getLabels = async (projectID) => { + getLabels = async (projectID: number) => { return this.doGet(`${this.url}/labels?projectID=${projectID}`); } - getMilestones = async (projectID) => { + getMilestones = async (projectID: number) => { return this.doGet(`${this.url}/milestones?projectID=${projectID}`); } - getAssignees = async (projectID) => { + getAssignees = async (projectID: number) => { return this.doGet(`${this.url}/assignees?projectID=${projectID}`); } diff --git a/webapp/src/components/gitlab_project_selector/index.tsx b/webapp/src/components/gitlab_project_selector/index.tsx index 52ae01fb..6eeb58fc 100644 --- a/webapp/src/components/gitlab_project_selector/index.tsx +++ b/webapp/src/components/gitlab_project_selector/index.tsx @@ -7,8 +7,7 @@ import {Theme} from 'mattermost-redux/types/preferences'; import {getProjects} from 'src/actions'; import ReactSelectSetting from 'src/components/react_select_setting'; -import {GlobalState} from 'src/types/global_state'; -import {getPluginState} from 'src/selectors'; +import {getYourProjects} from 'src/selectors'; import {getErrorMessage} from 'src/utils/user_utils'; import {Project, ProjectSelection} from 'src/types/gitlab_types'; import {ErrorType, SelectionType} from 'src/types/common'; @@ -26,7 +25,7 @@ const GitlabProjectSelector = ({theme, required, onChange, value, addValidate, r const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(''); - const myProjects = useSelector((state: GlobalState) => getPluginState(state).yourProjects); + const myProjects = useSelector(getYourProjects); const dispatch = useDispatch(); diff --git a/webapp/src/components/modals/create_issue/create_issue_form.tsx b/webapp/src/components/modals/create_issue/create_issue_form.tsx index 7a437fd0..78a65a18 100644 --- a/webapp/src/components/modals/create_issue/create_issue_form.tsx +++ b/webapp/src/components/modals/create_issue/create_issue_form.tsx @@ -43,7 +43,7 @@ const CreateIssueForm = ({theme, handleClose, isSubmitting, setIsSubmitting}: Pr if (post) { setIssueDescription(post.message); } else if (channelId) { - setIssueTitle(title.substring(0, MAX_TITLE_LENGTH)); + setIssueTitle(title?.substring(0, MAX_TITLE_LENGTH) ?? ''); } }, []); @@ -68,7 +68,7 @@ const CreateIssueForm = ({theme, handleClose, isSubmitting, setIsSubmitting}: Pr assignees: assignees.map((assignee) => assignee.value), milestone: milestone?.value, post_id: postId, - channel_id: channelId, + channel_id: channelId as string, }; setIsSubmitting(true); @@ -186,7 +186,7 @@ const CreateIssueForm = ({theme, handleClose, isSubmitting, setIsSubmitting}: Pr required={true} disabled={false} maxLength={MAX_TITLE_LENGTH} - value={issueTitle} + value={issueTitle ?? ''} onChange={handleIssueTitleChange} /> {issueTitleValidationError} diff --git a/webapp/src/components/post_options/attach_comment_to_issue.tsx b/webapp/src/components/post_options/attach_comment_to_issue.tsx index 28798652..fff3cb0a 100644 --- a/webapp/src/components/post_options/attach_comment_to_issue.tsx +++ b/webapp/src/components/post_options/attach_comment_to_issue.tsx @@ -7,11 +7,10 @@ import {useDispatch, useSelector} from 'react-redux'; import {getPost} from 'mattermost-redux/selectors/entities/posts'; import {isSystemMessage} from 'mattermost-redux/utils/post_utils'; -import manifest from 'src/manifest'; import GitLabIcon from 'src/images/icons/gitlab'; import {openAttachCommentToIssueModal} from 'src/actions'; -import {GlobalState} from 'src/types/global_state'; -import {isUserConnectedToGitlab} from 'src/selectors'; +import {getConnected} from 'src/selectors'; +import {GlobalState} from 'src/types/store'; interface PropTypes { postId: string; @@ -23,7 +22,7 @@ const AttachCommentToIssuePostMenuAction = ({postId}: PropTypes) => { const isPostSystemMessage = Boolean(!post || isSystemMessage(post)); return { - show: isUserConnectedToGitlab(state) && !isPostSystemMessage, + show: getConnected(state) && !isPostSystemMessage, }; }); diff --git a/webapp/src/components/post_options/create_issue.tsx b/webapp/src/components/post_options/create_issue.tsx index 12370150..80639570 100644 --- a/webapp/src/components/post_options/create_issue.tsx +++ b/webapp/src/components/post_options/create_issue.tsx @@ -7,10 +7,9 @@ import {getPost} from 'mattermost-redux/selectors/entities/posts'; import {isSystemMessage} from 'mattermost-redux/utils/post_utils'; import GitLabIcon from 'src/images/icons/gitlab'; -import manifest from 'src/manifest'; import {openCreateIssueModal} from 'src/actions'; -import {GlobalState} from 'src/types/global_state'; -import {isUserConnectedToGitlab} from 'src/selectors'; +import {getConnected} from 'src/selectors'; +import {GlobalState} from 'src/types/store'; type PropTypes = { postId: string; @@ -22,7 +21,7 @@ const CreateIssuePostMenuAction = ({postId}: PropTypes) => { const isPostSystemMessage = Boolean(!post || isSystemMessage(post)); return { - show: isUserConnectedToGitlab(state) && !isPostSystemMessage, + show: getConnected(state) && !isPostSystemMessage, }; }); diff --git a/webapp/src/reducers/index.ts b/webapp/src/reducers/index.ts index 5f6d6530..28679693 100644 --- a/webapp/src/reducers/index.ts +++ b/webapp/src/reducers/index.ts @@ -3,7 +3,8 @@ import {combineReducers, Reducer} from 'redux'; import ActionTypes from '../action_types'; import Constants from '../constants'; import {Item} from 'src/types/gitlab_items'; -import {ConnectedData, GitlabUsersData, LHSData, ShowRhsPluginActionData, SubscriptionData} from 'src/types'; +import {ConnectedData, CreateIssueModalData, GitlabUsersData, LHSData, ShowRhsPluginActionData, SubscriptionData} from 'src/types'; +import {Project} from 'src/types/gitlab_types'; const connected: Reducer = (state = false, action) => { switch (action.type) { @@ -130,7 +131,7 @@ const gitlabUsers: Reducer, {type: string, data: } }; -const isCreateIssueModalVisible = (state = false, action) => { +const isCreateIssueModalVisible = (state = false, action: {type: string}) => { switch (action.type) { case ActionTypes.OPEN_CREATE_ISSUE_MODAL: case ActionTypes.OPEN_CREATE_ISSUE_MODAL_WITHOUT_POST: @@ -142,7 +143,7 @@ const isCreateIssueModalVisible = (state = false, action) => { } }; -const isAttachCommentToIssueModalVisible = (state = false, action) => { +const isAttachCommentToIssueModalVisible = (state = false, action: {type: string}) => { switch (action.type) { case ActionTypes.OPEN_ATTACH_COMMENT_TO_ISSUE_MODAL: return true; @@ -153,7 +154,7 @@ const isAttachCommentToIssueModalVisible = (state = false, action) => { } }; -const postIdForAttachCommentToIssueModal = (state = {}, action) => { +const postIdForAttachCommentToIssueModal = (state = '', action: {type: string, data: {postId: string}}) => { switch (action.type) { case ActionTypes.OPEN_ATTACH_COMMENT_TO_ISSUE_MODAL: return action.data.postId; @@ -164,12 +165,13 @@ const postIdForAttachCommentToIssueModal = (state = {}, action) => { } }; -const createIssueModal = (state = {}, action) => { +const createIssueModal: Reducer = (state = {}, action) => { switch (action.type) { case ActionTypes.OPEN_CREATE_ISSUE_MODAL: case ActionTypes.OPEN_CREATE_ISSUE_MODAL_WITHOUT_POST: return { ...state, + postId: action.data.postId, title: action.data.title, channelId: action.data.channelId, @@ -181,7 +183,7 @@ const createIssueModal = (state = {}, action) => { } }; -function yourProjects(state = [], action) { +function yourProjects(state = [] as Project[], action: {type: string, data: Project[]}) { switch (action.type) { case ActionTypes.RECEIVED_PROJECTS: return action.data; diff --git a/webapp/src/selectors/index.ts b/webapp/src/selectors/index.ts index 99df6b34..e09f80aa 100644 --- a/webapp/src/selectors/index.ts +++ b/webapp/src/selectors/index.ts @@ -46,8 +46,6 @@ function mapPrsToDetails(prs?: Item[], details?: Item[]): Item[] { export const getPluginState = (state: GlobalState) => state[pluginStateKey]; -export const isUserConnectedToGitlab = (state) => state[`plugins-${manifest.id}`].connected; - export const getSidebarData = createSelector( getPluginState, (pluginState: PluginState): SideBarData => { @@ -66,12 +64,12 @@ export const getSidebarData = createSelector( }, ); -export const isCreateIssueModalVisible = (state) => state[`plugins-${manifest.id}`].isCreateIssueModalVisible; +export const isCreateIssueModalVisible = (state: GlobalState) => getPluginState(state).isCreateIssueModalVisible; -export const isAttachCommentToIssueModalVisible = (state) => state[`plugins-${manifest.id}`].isAttachCommentToIssueModalVisible; +export const isAttachCommentToIssueModalVisible = (state: GlobalState) => getPluginState(state).isAttachCommentToIssueModalVisible; -export const getCreateIssueModalContents = (state) => { - const {postId, title, channelId} = state[`plugins-${manifest.id}`].createIssueModal; +export const getCreateIssueModalContents = (state: GlobalState) => { + const {postId, title, channelId} = getPluginState(state).createIssueModal; const post = postId ? getPost(state, postId) : null; return { @@ -81,13 +79,15 @@ export const getCreateIssueModalContents = (state) => { }; }; -export const getAttachCommentModalContents = (state) => { - const postId = state[`plugins-${manifest.id}`].postIdForAttachCommentToIssueModal; +export const getAttachCommentModalContents = (state: GlobalState) => { + const postId = getPluginState(state).postIdForAttachCommentToIssueModal; const post = getPost(state, postId); return post; }; +export const getYourProjects = (state: GlobalState) => getPluginState(state).yourProjects; + export const getConnected = (state: GlobalState) => getPluginState(state).connected; export const getConnectedGitlabUrl = (state: GlobalState) => getPluginState(state).gitlabURL; diff --git a/webapp/src/types/global_state.ts b/webapp/src/types/global_state.ts deleted file mode 100644 index 606f1f7d..00000000 --- a/webapp/src/types/global_state.ts +++ /dev/null @@ -1,18 +0,0 @@ -import {GlobalState as ReduxGlobalState} from 'mattermost-redux/types/store'; - -import {Project} from './gitlab_types'; - -export type GlobalState = ReduxGlobalState & { - 'plugins-com.github.manland.mattermost-plugin-gitlab': { - createIssueModal: { - postId: string; - title: string; - channelId: string; - }; - isCreateIssueModalVisible: boolean; - yourProjects: Project[]; - connected: boolean; - postIdForAttachCommentToIssueModal: string; - isAttachCommentToIssueModalVisible: boolean; - } -} diff --git a/webapp/src/types/index.ts b/webapp/src/types/index.ts index 204a7286..6ed5236e 100644 --- a/webapp/src/types/index.ts +++ b/webapp/src/types/index.ts @@ -58,3 +58,9 @@ export type SideBarData = { gitlabURL: string; rhsState: string; } + +export type CreateIssueModalData = { + postId?: string; + title?: string; + channelId?: string; +}