Convert `axios` usage to `fetch` in Pace Plans
closes LS-2624 flag=pace_plans test plan: - with pace plans enabled, navigate to the pace plans view - select the settings cog, and toggle the "Skip Weekends" option - verify that the network request succeeds Change-Id: I0fbbc4236167bbcc9d4d665b734736b88988ef1f Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/273658 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Nate Armstrong <narmstrong@instructure.com> QA-Review: Nate Armstrong <narmstrong@instructure.com> Product-Review: Isaac Moore <isaac.moore@instructure.com>
This commit is contained in:
parent
2bb8ad0d2d
commit
5acedfc484
|
@ -199,7 +199,9 @@
|
|||
"@testing-library/react": "^11",
|
||||
"@testing-library/react-hooks": "^5",
|
||||
"@testing-library/user-event": "^12",
|
||||
"@types/jquery": "^3.5.6",
|
||||
"@types/lodash": "^4.14.72",
|
||||
"@types/parse-link-header": "^1.0.0",
|
||||
"@types/react": "^17.0.19",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"@typescript-eslint/eslint-plugin": "^4.29.1",
|
||||
|
|
|
@ -53,9 +53,7 @@ const updatePacePlan = async (
|
|||
!persisted || shouldBlock || (plan.hard_end_dates && plan.context_type === 'Enrollment')
|
||||
|
||||
return method(plan, extraSaveParams) // Hit the API to update
|
||||
.then(response => {
|
||||
const updatedPlan: PacePlan = response.data
|
||||
|
||||
.then(updatedPlan => {
|
||||
if (updateAfterRequest) {
|
||||
dispatch(pacePlanActions.planCreated(updatedPlan))
|
||||
}
|
||||
|
|
|
@ -94,8 +94,7 @@ const thunkActions = {
|
|||
publishForEnrollmentIds
|
||||
)
|
||||
.then(response => {
|
||||
const newDraft: PacePlan = response.data.new_draft_plan
|
||||
dispatch(pacePlanActions.setPacePlan(newDraft))
|
||||
dispatch(pacePlanActions.setPacePlan(response.new_draft_plan))
|
||||
dispatch(uiActions.hideLoadingOverlay())
|
||||
dispatch(uiActions.publishPlanFinished())
|
||||
})
|
||||
|
@ -120,8 +119,7 @@ const thunkActions = {
|
|||
|
||||
return Api.resetToLastPublished(contextType, contextId)
|
||||
.then(response => {
|
||||
const plan: PacePlan = response.data.pace_plan
|
||||
dispatch(pacePlanActions.setPacePlan(plan))
|
||||
dispatch(pacePlanActions.setPacePlan(response.pace_plan))
|
||||
dispatch(uiActions.hideLoadingOverlay())
|
||||
})
|
||||
.catch(error => {
|
||||
|
@ -143,8 +141,7 @@ const thunkActions = {
|
|||
|
||||
return Api.getLatestDraftFor(contextType, contextId)
|
||||
.then(response => {
|
||||
const plan: PacePlan = response.data.pace_plan
|
||||
dispatch(afterAction(plan))
|
||||
dispatch(afterAction(response.pace_plan))
|
||||
dispatch(uiActions.hideLoadingOverlay())
|
||||
})
|
||||
.catch(error => {
|
||||
|
@ -162,8 +159,7 @@ const thunkActions = {
|
|||
|
||||
return Api.relinkToParentPlan(getState().pacePlan.id)
|
||||
.then(response => {
|
||||
const plan: PacePlan = response.data.pace_plan
|
||||
dispatch(pacePlanActions.setPacePlan(plan))
|
||||
dispatch(pacePlanActions.setPacePlan(response.pace_plan))
|
||||
dispatch(uiActions.hideLoadingOverlay())
|
||||
})
|
||||
.catch(error => {
|
||||
|
|
|
@ -16,22 +16,23 @@
|
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import axios, {AxiosPromise} from '@canvas/axios'
|
||||
|
||||
import {BlackoutDate} from '../shared/types'
|
||||
import * as DateHelpers from '../utils/date_stuff/date_helpers'
|
||||
import doFetchApi from '@canvas/do-fetch-api-effect'
|
||||
|
||||
/* API methods */
|
||||
|
||||
export const create = (blackoutDate: BlackoutDate): AxiosPromise => {
|
||||
return axios.post(`/api/v1/blackout_dates`, {
|
||||
blackout_date: transformBlackoutDateForApi(blackoutDate)
|
||||
})
|
||||
}
|
||||
export const create = async (blackoutDate: BlackoutDate) =>
|
||||
(
|
||||
await doFetchApi<{blackout_date: BlackoutDate}>({
|
||||
path: '/api/v1/blackout_dates',
|
||||
method: 'POST',
|
||||
body: transformBlackoutDateForApi(blackoutDate)
|
||||
})
|
||||
).json
|
||||
|
||||
export const deleteBlackoutDate = (id: number | string): AxiosPromise => {
|
||||
return axios.delete(`/api/v1/blackout_dates/${id}`)
|
||||
}
|
||||
export const deleteBlackoutDate = async (id: number | string) =>
|
||||
(await doFetchApi({path: `/api/v1/blackout_dates/${id}`, method: 'DELETE'})).json
|
||||
|
||||
/* API transformers */
|
||||
|
||||
|
|
|
@ -16,9 +16,8 @@
|
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import axios, {AxiosPromise} from '@canvas/axios'
|
||||
|
||||
import {PacePlan, PlanContextTypes, WorkflowStates, PublishOptions} from '../types'
|
||||
import doFetchApi from '@canvas/do-fetch-api-effect'
|
||||
|
||||
/* API helpers */
|
||||
|
||||
|
@ -51,66 +50,96 @@ export const waitForActionCompletion = (actionInProgress: () => boolean, waitTim
|
|||
|
||||
/* API methods */
|
||||
|
||||
export const update = (pacePlan: PacePlan, extraSaveParams = {}): AxiosPromise => {
|
||||
return axios.put(`/api/v1/courses/${pacePlan.course_id}/pace_plans/${pacePlan.id}`, {
|
||||
...extraSaveParams,
|
||||
pace_plan: transformPacePlanForApi(pacePlan)
|
||||
})
|
||||
}
|
||||
export const update = async (pacePlan: PacePlan, extraSaveParams = {}) =>
|
||||
(
|
||||
await doFetchApi<PacePlan>({
|
||||
path: `/api/v1/courses/${pacePlan.course_id}/pace_plans/${pacePlan.id}`,
|
||||
method: 'PUT',
|
||||
body: {
|
||||
...extraSaveParams,
|
||||
pace_plan: transformPacePlanForApi(pacePlan)
|
||||
}
|
||||
})
|
||||
).json
|
||||
|
||||
export const create = (pacePlan: PacePlan, extraSaveParams = {}): AxiosPromise => {
|
||||
return axios.post(`/api/v1/courses/${pacePlan.course_id}/pace_plans`, {
|
||||
...extraSaveParams,
|
||||
pace_plan: transformPacePlanForApi(pacePlan)
|
||||
})
|
||||
}
|
||||
export const create = async (pacePlan: PacePlan, extraSaveParams = {}) =>
|
||||
(
|
||||
await doFetchApi<PacePlan>({
|
||||
path: `/api/v1/courses/${pacePlan.course_id}/pace_plans`,
|
||||
method: 'POST',
|
||||
body: {
|
||||
...extraSaveParams,
|
||||
pace_plan: transformPacePlanForApi(pacePlan)
|
||||
}
|
||||
})
|
||||
).json
|
||||
|
||||
export const publish = (
|
||||
export const publish = async (
|
||||
plan: PacePlan,
|
||||
publishForOption: PublishOptions,
|
||||
publishForSectionIds: Array<string>,
|
||||
publishForEnrollmentIds: Array<string>
|
||||
): AxiosPromise => {
|
||||
return axios.post(`/api/v1/courses/${plan.course_id}/pace_plans/publish`, {
|
||||
context_type: plan.context_type,
|
||||
context_id: plan.context_id,
|
||||
publish_for_option: publishForOption,
|
||||
publish_for_section_ids: publishForSectionIds,
|
||||
publish_for_enrollment_ids: publishForEnrollmentIds
|
||||
})
|
||||
}
|
||||
) =>
|
||||
(
|
||||
await doFetchApi<{new_draft_plan: PacePlan}>({
|
||||
path: `/api/v1/courses/${plan.course_id}/pace_plans/publish`,
|
||||
method: 'POST',
|
||||
body: {
|
||||
context_type: plan.context_type,
|
||||
context_id: plan.context_id,
|
||||
publish_for_option: publishForOption,
|
||||
publish_for_section_ids: publishForSectionIds,
|
||||
publish_for_enrollment_ids: publishForEnrollmentIds
|
||||
}
|
||||
})
|
||||
).json
|
||||
|
||||
export const resetToLastPublished = (
|
||||
contextType: PlanContextTypes,
|
||||
contextId: string
|
||||
): AxiosPromise => {
|
||||
return axios.post(`/api/v1/pace_plans/reset_to_last_published`, {
|
||||
context_type: contextType,
|
||||
context_id: contextId
|
||||
})
|
||||
}
|
||||
export const resetToLastPublished = async (contextType: PlanContextTypes, contextId: string) =>
|
||||
(
|
||||
await doFetchApi<{pace_plan: PacePlan}>({
|
||||
path: `/api/v1/pace_plans/reset_to_last_published`,
|
||||
method: 'POST',
|
||||
body: {
|
||||
context_type: contextType,
|
||||
context_id: contextId
|
||||
}
|
||||
})
|
||||
).json
|
||||
|
||||
export const load = (pacePlanId: string) => {
|
||||
return axios.get(`/api/v1/pace_plans/${pacePlanId}`)
|
||||
}
|
||||
export const load = async (pacePlanId: string) =>
|
||||
(await doFetchApi({path: `/api/v1/pace_plans/${pacePlanId}`})).json
|
||||
|
||||
export const getLatestDraftFor = (context: PlanContextTypes, contextId: string) => {
|
||||
return axios.get(
|
||||
`/api/v1/pace_plans/latest_draft_for?context_type=${context}&context_id=${contextId}`
|
||||
)
|
||||
}
|
||||
export const getLatestDraftFor = async (context: PlanContextTypes, contextId: string) =>
|
||||
(
|
||||
await doFetchApi<{pace_plan: PacePlan}>({
|
||||
path: `/api/v1/pace_plans/latest_draft_for?context_type=${context}&context_id=${contextId}`
|
||||
})
|
||||
).json
|
||||
|
||||
export const republishAllPlansForCourse = (courseId: string) => {
|
||||
return axios.post(`/api/v1/pace_plans/republish_all_plans`, {course_id: courseId})
|
||||
}
|
||||
export const republishAllPlansForCourse = async (courseId: string) =>
|
||||
(
|
||||
await doFetchApi({
|
||||
path: `/api/v1/pace_plans/republish_all_plans`,
|
||||
method: 'POST',
|
||||
body: {course_id: courseId}
|
||||
})
|
||||
).json
|
||||
|
||||
export const republishAllPlans = () => {
|
||||
return axios.post(`/api/v1/pace_plans/republish_all_plans`)
|
||||
}
|
||||
export const republishAllPlans = async () =>
|
||||
(
|
||||
await doFetchApi({
|
||||
path: `/api/v1/pace_plans/republish_all_plans`,
|
||||
method: 'POST'
|
||||
})
|
||||
).json
|
||||
|
||||
export const relinkToParentPlan = (planId: string) => {
|
||||
return axios.post(`/api/v1/pace_plans/${planId}/relink_to_parent_plan`)
|
||||
}
|
||||
export const relinkToParentPlan = async (planId: string) =>
|
||||
(
|
||||
await doFetchApi<{pace_plan: PacePlan}>({
|
||||
path: `/api/v1/pace_plans/${planId}/relink_to_parent_plan`,
|
||||
method: 'POST'
|
||||
})
|
||||
).json
|
||||
|
||||
/* API transformers
|
||||
* functions and interfaces to transform the frontend formatted objects
|
||||
|
|
|
@ -57,8 +57,7 @@ const thunkActions = {
|
|||
|
||||
BlackoutDatesApi.create(blackoutDateWithTempId)
|
||||
.then(response => {
|
||||
const savedBlackoutDate: BlackoutDate = response.data.blackout_date
|
||||
dispatch(actions.addBackendId(tempId, savedBlackoutDate.id as number))
|
||||
dispatch(actions.addBackendId(tempId, response.blackout_date.id as number))
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error) // eslint-disable-line no-console
|
||||
|
|
|
@ -21,22 +21,31 @@ import getCookie from 'get-cookie'
|
|||
import parseLinkHeader from 'parse-link-header'
|
||||
import {defaultFetchOptions} from '@instructure/js-utils'
|
||||
|
||||
function constructRelativeUrl({path, params}) {
|
||||
function constructRelativeUrl({path, params}: {path: string; params: {[k: string]: any}}) {
|
||||
const queryString = $.param(params)
|
||||
if (!queryString.length) return path
|
||||
return `${path}?${queryString}`
|
||||
}
|
||||
|
||||
export type DoFetchApiOpts = {
|
||||
path: string
|
||||
method?: string
|
||||
headers?: {[k: string]: string}
|
||||
params?: {[k: string]: any}
|
||||
body?: any
|
||||
fetchOpts?: RequestInit
|
||||
}
|
||||
|
||||
// NOTE: we do NOT deep-merge customFetchOptions.headers, they should be passed
|
||||
// in the headers arg instead.
|
||||
export default async function doFetchApi({
|
||||
export default async function doFetchApi<T = any>({
|
||||
path,
|
||||
method = 'GET',
|
||||
headers = {},
|
||||
params = {},
|
||||
body,
|
||||
fetchOpts = {}
|
||||
}) {
|
||||
}: DoFetchApiOpts) {
|
||||
const finalFetchOptions = {...defaultFetchOptions}
|
||||
finalFetchOptions.headers['X-CSRF-Token'] = getCookie('_csrf_token')
|
||||
|
||||
|
@ -53,11 +62,12 @@ export default async function doFetchApi({
|
|||
const err = new Error(
|
||||
`doFetchApi received a bad response: ${response.status} ${response.statusText}`
|
||||
)
|
||||
err.response = response // in case anyone wants to check it for something
|
||||
Object.assign(err, {response}) // in case anyone wants to check it for something
|
||||
throw err
|
||||
}
|
||||
const link = parseLinkHeader(response.headers.get('Link'))
|
||||
const linkHeader = response.headers.get('Link')
|
||||
const link = linkHeader ? parseLinkHeader(linkHeader) : null
|
||||
const text = await response.text()
|
||||
const json = text.length > 0 ? JSON.parse(text) : null
|
||||
const json = text.length > 0 ? (JSON.parse(text) as T) : null
|
||||
return {json, response, link}
|
||||
}
|
|
@ -3,5 +3,5 @@
|
|||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"author": "neme",
|
||||
"main": "./index.js"
|
||||
"main": "index.ts"
|
||||
}
|
||||
|
|
17
yarn.lock
17
yarn.lock
|
@ -6043,6 +6043,13 @@
|
|||
jest-diff "^25.2.1"
|
||||
pretty-format "^25.2.1"
|
||||
|
||||
"@types/jquery@^3.5.6":
|
||||
version "3.5.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.5.6.tgz#97ac8e36dccd8ad8ed3f3f3b48933614d9fd8cf0"
|
||||
integrity sha512-SmgCQRzGPId4MZQKDj9Hqc6kSXFNWZFHpELkyK8AQhf8Zr6HKfCzFv9ZC1Fv3FyQttJZOlap3qYb12h61iZAIg==
|
||||
dependencies:
|
||||
"@types/sizzle" "*"
|
||||
|
||||
"@types/js-cookie@^2.2.6":
|
||||
version "2.2.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.7.tgz#226a9e31680835a6188e887f3988e60c04d3f6a3"
|
||||
|
@ -6149,6 +6156,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
|
||||
integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
|
||||
|
||||
"@types/parse-link-header@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/parse-link-header/-/parse-link-header-1.0.0.tgz#69f059e40a0fa93dc2e095d4142395ae6adc5d7a"
|
||||
integrity sha512-fCA3btjE7QFeRLfcD0Sjg+6/CnmC66HpMBoRfRzd2raTaWMJV21CCZ0LO8MOqf8onl5n0EPfjq4zDhbyX8SVwA==
|
||||
|
||||
"@types/parse5@^5.0.0":
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-5.0.3.tgz#e7b5aebbac150f8b5fdd4a46e7f0bd8e65e19109"
|
||||
|
@ -6233,6 +6245,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-7.5.2.tgz#5e2f1d120f07b9cda07e5dedd4f3bf8888fccdb9"
|
||||
integrity sha512-T+m89VdXj/eidZyejvmoP9jivXgBDdkOSBVQjU9kF349NEx10QdPNGxHeZUaj1IlJ32/ewdyXJjnJxyxJroYwg==
|
||||
|
||||
"@types/sizzle@*":
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.3.tgz#ff5e2f1902969d305225a047c8a0fd5c915cebef"
|
||||
integrity sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==
|
||||
|
||||
"@types/source-list-map@*":
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9"
|
||||
|
|
Loading…
Reference in New Issue