diff --git a/README.md b/README.md index 49646a5c..820739b1 100644 --- a/README.md +++ b/README.md @@ -258,9 +258,6 @@ There are some rules when it comes to the folder structure of the frontend. ## GraphQL -When you change something on the server side run the following command to update the -graphql schema: - ```bash python manage.py graphql_schema ``` @@ -270,13 +267,25 @@ generated code ```bash npm run codegen + +# `npm run dev` includes `npm run codegen` as step... +npm run dev ``` -💡 If you run `npm run dev`, the codegen command will be run automatically in watch mode." +If you run `npm run dev`, the codegen command will be run automatically in watch mode. + + +For the `ObjectTypes` on the server, please use the postfix `ObjectType` for types, +like `LearningContentAttendanceCourseObjectType`. + +This will prevent problems with the hand written types on the client side, +when `npm run codegen` will create the types automatically. + +When you change something on the server side run the following command to update the +graphql schema. ### Open Questions - The `id` field has to be a string? -- Is running `codegen` a prerequisite so that it even works? - What about the generated types from `codegen`? Hand written types seem to be better. -- The functions is `cacheExchange` should be nearer the concrete implementation +- The functions in `cacheExchange` should be nearer the concrete implementation... diff --git a/client/src/gql/graphql.ts b/client/src/gql/graphql.ts index f0e7a382..696d5bfa 100644 --- a/client/src/gql/graphql.ts +++ b/client/src/gql/graphql.ts @@ -138,6 +138,20 @@ export type AttendanceUserType = { user_id: Scalars['UUID']['output']; }; +export type CircleObjectType = CoursePageInterface & { + __typename?: 'CircleObjectType'; + content_type?: Maybe; + description: Scalars['String']['output']; + frontend_url?: Maybe; + goals: Scalars['String']['output']; + id?: Maybe; + learning_sequences?: Maybe>>; + live?: Maybe; + slug?: Maybe; + title?: Maybe; + translation_key?: Maybe; +}; + /** An enumeration. */ export type CoreUserLanguageChoices = /** Deutsch */ @@ -147,6 +161,15 @@ export type CoreUserLanguageChoices = /** Italiano */ | 'IT'; +export type CourseObjectType = { + __typename?: 'CourseObjectType'; + category_name: Scalars['String']['output']; + id: Scalars['ID']['output']; + learning_path?: Maybe; + slug: Scalars['String']['output']; + title: Scalars['String']['output']; +}; + export type CoursePageInterface = { content_type?: Maybe; frontend_url?: Maybe; @@ -170,15 +193,6 @@ export type CourseSessionAttendanceCourseType = { trainer: Scalars['String']['output']; }; -export type CourseType = { - __typename?: 'CourseType'; - category_name: Scalars['String']['output']; - id: Scalars['ID']['output']; - learning_path?: Maybe; - slug: Scalars['String']['output']; - title: Scalars['String']['output']; -}; - export type ErrorType = { __typename?: 'ErrorType'; field: Scalars['String']['output']; @@ -187,14 +201,170 @@ export type ErrorType = { export type FeedbackResponse = Node & { __typename?: 'FeedbackResponse'; + circle: CircleObjectType; created_at: Scalars['DateTime']['output']; data?: Maybe; /** The ID of the object */ id: Scalars['ID']['output']; }; -export type LearningPathType = CoursePageInterface & { - __typename?: 'LearningPathType'; +export type LearningContentAssignmentObjectType = LearningContentInterface & { + __typename?: 'LearningContentAssignmentObjectType'; + assignment_type: LearnpathLearningContentAssignmentAssignmentTypeChoices; + content?: Maybe; + content_assignment: AssignmentObjectType; + content_type?: Maybe; + description?: Maybe; + frontend_url?: Maybe; + id?: Maybe; + live?: Maybe; + minutes?: Maybe; + slug?: Maybe; + title?: Maybe; + translation_key?: Maybe; +}; + +export type LearningContentAttendanceCourseObjectType = LearningContentInterface & { + __typename?: 'LearningContentAttendanceCourseObjectType'; + content?: Maybe; + content_type?: Maybe; + description?: Maybe; + frontend_url?: Maybe; + id?: Maybe; + live?: Maybe; + minutes?: Maybe; + slug?: Maybe; + title?: Maybe; + translation_key?: Maybe; +}; + +export type LearningContentDocumentListObjectType = LearningContentInterface & { + __typename?: 'LearningContentDocumentListObjectType'; + content?: Maybe; + content_type?: Maybe; + description?: Maybe; + frontend_url?: Maybe; + id?: Maybe; + live?: Maybe; + minutes?: Maybe; + slug?: Maybe; + title?: Maybe; + translation_key?: Maybe; +}; + +export type LearningContentFeedbackObjectType = LearningContentInterface & { + __typename?: 'LearningContentFeedbackObjectType'; + content?: Maybe; + content_type?: Maybe; + description?: Maybe; + frontend_url?: Maybe; + id?: Maybe; + live?: Maybe; + minutes?: Maybe; + slug?: Maybe; + title?: Maybe; + translation_key?: Maybe; +}; + +export type LearningContentInterface = { + content?: Maybe; + content_type?: Maybe; + description?: Maybe; + frontend_url?: Maybe; + id?: Maybe; + live?: Maybe; + minutes?: Maybe; + slug?: Maybe; + title?: Maybe; + translation_key?: Maybe; +}; + +export type LearningContentLearningModuleObjectType = LearningContentInterface & { + __typename?: 'LearningContentLearningModuleObjectType'; + content?: Maybe; + content_type?: Maybe; + description?: Maybe; + frontend_url?: Maybe; + id?: Maybe; + live?: Maybe; + minutes?: Maybe; + slug?: Maybe; + title?: Maybe; + translation_key?: Maybe; +}; + +export type LearningContentMediaLibraryObjectType = LearningContentInterface & { + __typename?: 'LearningContentMediaLibraryObjectType'; + content?: Maybe; + content_type?: Maybe; + description?: Maybe; + frontend_url?: Maybe; + id?: Maybe; + live?: Maybe; + minutes?: Maybe; + slug?: Maybe; + title?: Maybe; + translation_key?: Maybe; +}; + +export type LearningContentPlaceholderObjectType = LearningContentInterface & { + __typename?: 'LearningContentPlaceholderObjectType'; + content?: Maybe; + content_type?: Maybe; + description?: Maybe; + frontend_url?: Maybe; + id?: Maybe; + live?: Maybe; + minutes?: Maybe; + slug?: Maybe; + title?: Maybe; + translation_key?: Maybe; +}; + +export type LearningContentRichTextObjectType = LearningContentInterface & { + __typename?: 'LearningContentRichTextObjectType'; + content?: Maybe; + content_type?: Maybe; + description?: Maybe; + frontend_url?: Maybe; + id?: Maybe; + live?: Maybe; + minutes?: Maybe; + slug?: Maybe; + title?: Maybe; + translation_key?: Maybe; +}; + +export type LearningContentTestObjectType = LearningContentInterface & { + __typename?: 'LearningContentTestObjectType'; + content?: Maybe; + content_type?: Maybe; + description?: Maybe; + frontend_url?: Maybe; + id?: Maybe; + live?: Maybe; + minutes?: Maybe; + slug?: Maybe; + title?: Maybe; + translation_key?: Maybe; +}; + +export type LearningContentVideoObjectType = LearningContentInterface & { + __typename?: 'LearningContentVideoObjectType'; + content?: Maybe; + content_type?: Maybe; + description?: Maybe; + frontend_url?: Maybe; + id?: Maybe; + live?: Maybe; + minutes?: Maybe; + slug?: Maybe; + title?: Maybe; + translation_key?: Maybe; +}; + +export type LearningPathObjectType = CoursePageInterface & { + __typename?: 'LearningPathObjectType'; content_type?: Maybe; depth: Scalars['Int']['output']; draft_title: Scalars['String']['output']; @@ -222,10 +392,45 @@ export type LearningPathType = CoursePageInterface & { show_in_menus: Scalars['Boolean']['output']; slug?: Maybe; title?: Maybe; + topics?: Maybe>>; translation_key?: Maybe; url_path: Scalars['String']['output']; }; +export type LearningSequenceObjectType = CoursePageInterface & { + __typename?: 'LearningSequenceObjectType'; + content_type?: Maybe; + frontend_url?: Maybe; + icon: Scalars['String']['output']; + id?: Maybe; + learning_units?: Maybe>>; + live?: Maybe; + slug?: Maybe; + title?: Maybe; + translation_key?: Maybe; +}; + +export type LearningUnitObjectType = CoursePageInterface & { + __typename?: 'LearningUnitObjectType'; + content_type?: Maybe; + frontend_url?: Maybe; + id?: Maybe; + learning_contents?: Maybe>>; + live?: Maybe; + slug?: Maybe; + title?: Maybe; + translation_key?: Maybe; +}; + +/** An enumeration. */ +export type LearnpathLearningContentAssignmentAssignmentTypeChoices = + /** CASEWORK */ + | 'CASEWORK' + /** PREP_ASSIGNMENT */ + | 'PREP_ASSIGNMENT' + /** REFLECTION */ + | 'REFLECTION'; + export type Mutation = { __typename?: 'Mutation'; send_feedback?: Maybe; @@ -266,8 +471,20 @@ export type Query = { __typename?: 'Query'; assignment?: Maybe; assignment_completion?: Maybe; - course?: Maybe; + circle?: Maybe; + course?: Maybe; course_session_attendance_course?: Maybe; + learning_content_assignment?: Maybe; + learning_content_attendance_course?: Maybe; + learning_content_document_list?: Maybe; + learning_content_feedback?: Maybe; + learning_content_learning_module?: Maybe; + learning_content_media_library?: Maybe; + learning_content_placeholder?: Maybe; + learning_content_rich_text?: Maybe; + learning_content_test?: Maybe; + learning_content_video?: Maybe; + learning_path?: Maybe; }; @@ -285,6 +502,12 @@ export type QueryAssignmentCompletionArgs = { }; +export type QueryCircleArgs = { + id?: InputMaybe; + slug?: InputMaybe; +}; + + export type QueryCourseArgs = { id?: InputMaybe; }; @@ -295,6 +518,12 @@ export type QueryCourseSessionAttendanceCourseArgs = { id: Scalars['ID']['input']; }; + +export type QueryLearningPathArgs = { + id?: InputMaybe; + slug?: InputMaybe; +}; + export type SendFeedbackInput = { clientMutationId?: InputMaybe; course_session: Scalars['Int']['input']; @@ -310,6 +539,19 @@ export type SendFeedbackPayload = { feedback_response?: Maybe; }; +export type TopicObjectType = CoursePageInterface & { + __typename?: 'TopicObjectType'; + circles?: Maybe>>; + content_type?: Maybe; + frontend_url?: Maybe; + id?: Maybe; + is_visible: Scalars['Boolean']['output']; + live?: Maybe; + slug?: Maybe; + title?: Maybe; + translation_key?: Maybe; +}; + export type UserType = { __typename?: 'UserType'; avatar_url: Scalars['String']['output']; @@ -358,7 +600,7 @@ export type CourseQueryQueryVariables = Exact<{ }>; -export type CourseQueryQuery = { __typename?: 'Query', course?: { __typename?: 'CourseType', id: string, slug: string, title: string, category_name: string, learning_path?: { __typename?: 'LearningPathType', id?: string | null } | null } | null }; +export type CourseQueryQuery = { __typename?: 'Query', course?: { __typename?: 'CourseObjectType', id: string, slug: string, title: string, category_name: string, learning_path?: { __typename?: 'LearningPathObjectType', id?: string | null } | null } | null }; export const SendFeedbackMutationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SendFeedbackMutation"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SendFeedbackInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"send_feedback"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"feedback_response"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"errors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field"}},{"kind":"Field","name":{"kind":"Name","value":"messages"}}]}}]}}]}}]} as unknown as DocumentNode; diff --git a/client/src/gql/schema.graphql b/client/src/gql/schema.graphql index 15cea857..d96790bf 100644 --- a/client/src/gql/schema.graphql +++ b/client/src/gql/schema.graphql @@ -1,58 +1,82 @@ type Query { + circle(id: Int, slug: String): CircleObjectType + learning_path(id: Int, slug: String): LearningPathObjectType + learning_content_media_library: LearningContentMediaLibraryObjectType + learning_content_assignment: LearningContentAssignmentObjectType + learning_content_attendance_course: LearningContentAttendanceCourseObjectType + learning_content_feedback: LearningContentFeedbackObjectType + learning_content_learning_module: LearningContentLearningModuleObjectType + learning_content_placeholder: LearningContentPlaceholderObjectType + learning_content_rich_text: LearningContentRichTextObjectType + learning_content_test: LearningContentTestObjectType + learning_content_video: LearningContentVideoObjectType + learning_content_document_list: LearningContentDocumentListObjectType course_session_attendance_course(id: ID!, assignment_user_id: ID): CourseSessionAttendanceCourseType - course(id: Int): CourseType + course(id: Int): CourseObjectType assignment(id: ID, slug: String): AssignmentObjectType assignment_completion(assignment_id: ID!, course_session_id: ID!, learning_content_page_id: ID, assignment_user_id: UUID): AssignmentCompletionObjectType } -type CourseSessionAttendanceCourseType { - id: ID! - location: String! - trainer: String! - course_session_id: ID - learning_content_id: ID - due_date_id: ID - end: DateTime - start: DateTime - attendance_user_list: [AttendanceUserType] +type CircleObjectType implements CoursePageInterface { + description: String! + goals: String! + id: ID + title: String + slug: String + content_type: String + live: Boolean + translation_key: String + frontend_url: String + learning_sequences: [LearningSequenceObjectType] } -""" -The `DateTime` scalar type represents a DateTime -value as specified by -[iso8601](https://en.wikipedia.org/wiki/ISO_8601). -""" -scalar DateTime - -type AttendanceUserType { - user_id: UUID! - status: AttendanceUserStatus! - first_name: String - last_name: String - email: String +interface CoursePageInterface { + id: ID + title: String + slug: String + content_type: String + live: Boolean + translation_key: String + frontend_url: String } -""" -Leverages the internal Python implementation of UUID (uuid.UUID) to provide native UUID objects -in fields, resolvers and input. -""" -scalar UUID - -"""An enumeration.""" -enum AttendanceUserStatus { - PRESENT - ABSENT +type LearningSequenceObjectType implements CoursePageInterface { + icon: String! + id: ID + title: String + slug: String + content_type: String + live: Boolean + translation_key: String + frontend_url: String + learning_units: [LearningUnitObjectType] } -type CourseType { - id: ID! - title: String! - category_name: String! - slug: String! - learning_path: LearningPathType +type LearningUnitObjectType implements CoursePageInterface { + id: ID + title: String + slug: String + content_type: String + live: Boolean + translation_key: String + frontend_url: String + learning_contents: [LearningContentInterface] } -type LearningPathType implements CoursePageInterface { +interface LearningContentInterface { + id: ID + title: String + slug: String + content_type: String + live: Boolean + translation_key: String + frontend_url: String + minutes: Int + description: String + content: String +} + +type LearningPathObjectType implements CoursePageInterface { id: ID path: String! depth: Int! @@ -91,17 +115,15 @@ type LearningPathType implements CoursePageInterface { search_description: String! latest_revision_created_at: DateTime frontend_url: String + topics: [TopicObjectType] } -interface CoursePageInterface { - id: ID - title: String - slug: String - content_type: String - live: Boolean - translation_key: String - frontend_url: String -} +""" +The `DateTime` scalar type represents a DateTime +value as specified by +[iso8601](https://en.wikipedia.org/wiki/ISO_8601). +""" +scalar DateTime type UserType { """ @@ -116,6 +138,12 @@ type UserType { language: CoreUserLanguageChoices! } +""" +Leverages the internal Python implementation of UUID (uuid.UUID) to provide native UUID objects +in fields, resolvers and input. +""" +scalar UUID + """An enumeration.""" enum CoreUserLanguageChoices { """Deutsch""" @@ -128,6 +156,46 @@ enum CoreUserLanguageChoices { IT } +type TopicObjectType implements CoursePageInterface { + is_visible: Boolean! + id: ID + title: String + slug: String + content_type: String + live: Boolean + translation_key: String + frontend_url: String + circles: [CircleObjectType] +} + +type LearningContentMediaLibraryObjectType implements LearningContentInterface { + id: ID + title: String + slug: String + content_type: String + live: Boolean + translation_key: String + frontend_url: String + minutes: Int + description: String + content: String +} + +type LearningContentAssignmentObjectType implements LearningContentInterface { + content_assignment: AssignmentObjectType! + assignment_type: LearnpathLearningContentAssignmentAssignmentTypeChoices! + id: ID + title: String + slug: String + content_type: String + live: Boolean + translation_key: String + frontend_url: String + minutes: Int + description: String + content: String +} + type AssignmentObjectType implements CoursePageInterface { assignment_type: AssignmentAssignmentAssignmentTypeChoices! @@ -168,6 +236,156 @@ enum AssignmentAssignmentAssignmentTypeChoices { scalar JSONStreamField +"""An enumeration.""" +enum LearnpathLearningContentAssignmentAssignmentTypeChoices { + """CASEWORK""" + CASEWORK + + """PREP_ASSIGNMENT""" + PREP_ASSIGNMENT + + """REFLECTION""" + REFLECTION +} + +type LearningContentAttendanceCourseObjectType implements LearningContentInterface { + id: ID + title: String + slug: String + content_type: String + live: Boolean + translation_key: String + frontend_url: String + minutes: Int + description: String + content: String +} + +type LearningContentFeedbackObjectType implements LearningContentInterface { + id: ID + title: String + slug: String + content_type: String + live: Boolean + translation_key: String + frontend_url: String + minutes: Int + description: String + content: String +} + +type LearningContentLearningModuleObjectType implements LearningContentInterface { + id: ID + title: String + slug: String + content_type: String + live: Boolean + translation_key: String + frontend_url: String + minutes: Int + description: String + content: String +} + +type LearningContentPlaceholderObjectType implements LearningContentInterface { + id: ID + title: String + slug: String + content_type: String + live: Boolean + translation_key: String + frontend_url: String + minutes: Int + description: String + content: String +} + +type LearningContentRichTextObjectType implements LearningContentInterface { + id: ID + title: String + slug: String + content_type: String + live: Boolean + translation_key: String + frontend_url: String + minutes: Int + description: String + content: String +} + +type LearningContentTestObjectType implements LearningContentInterface { + id: ID + title: String + slug: String + content_type: String + live: Boolean + translation_key: String + frontend_url: String + minutes: Int + description: String + content: String +} + +type LearningContentVideoObjectType implements LearningContentInterface { + id: ID + title: String + slug: String + content_type: String + live: Boolean + translation_key: String + frontend_url: String + minutes: Int + description: String + content: String +} + +type LearningContentDocumentListObjectType implements LearningContentInterface { + id: ID + title: String + slug: String + content_type: String + live: Boolean + translation_key: String + frontend_url: String + minutes: Int + description: String + content: String +} + +type CourseSessionAttendanceCourseType { + id: ID! + location: String! + trainer: String! + course_session_id: ID + learning_content_id: ID + due_date_id: ID + end: DateTime + start: DateTime + attendance_user_list: [AttendanceUserType] +} + +type AttendanceUserType { + user_id: UUID! + status: AttendanceUserStatus! + first_name: String + last_name: String + email: String +} + +"""An enumeration.""" +enum AttendanceUserStatus { + PRESENT + ABSENT +} + +type CourseObjectType { + id: ID! + title: String! + category_name: String! + slug: String! + learning_path: LearningPathObjectType +} + type AssignmentCompletionObjectType { id: UUID! created_at: DateTime! @@ -234,6 +452,7 @@ type FeedbackResponse implements Node { id: ID! data: GenericScalar created_at: DateTime! + circle: CircleObjectType! } """An object with an ID""" diff --git a/client/src/gql/typenames.ts b/client/src/gql/typenames.ts index e4fd7627..fb87f08b 100644 --- a/client/src/gql/typenames.ts +++ b/client/src/gql/typenames.ts @@ -9,10 +9,11 @@ export const AttendanceUserInputType = "AttendanceUserInputType"; export const AttendanceUserStatus = "AttendanceUserStatus"; export const AttendanceUserType = "AttendanceUserType"; export const Boolean = "Boolean"; +export const CircleObjectType = "CircleObjectType"; export const CoreUserLanguageChoices = "CoreUserLanguageChoices"; +export const CourseObjectType = "CourseObjectType"; export const CoursePageInterface = "CoursePageInterface"; export const CourseSessionAttendanceCourseType = "CourseSessionAttendanceCourseType"; -export const CourseType = "CourseType"; export const DateTime = "DateTime"; export const ErrorType = "ErrorType"; export const FeedbackResponse = "FeedbackResponse"; @@ -22,12 +23,27 @@ export const ID = "ID"; export const Int = "Int"; export const JSONStreamField = "JSONStreamField"; export const JSONString = "JSONString"; -export const LearningPathType = "LearningPathType"; +export const LearningContentAssignmentObjectType = "LearningContentAssignmentObjectType"; +export const LearningContentAttendanceCourseObjectType = "LearningContentAttendanceCourseObjectType"; +export const LearningContentDocumentListObjectType = "LearningContentDocumentListObjectType"; +export const LearningContentFeedbackObjectType = "LearningContentFeedbackObjectType"; +export const LearningContentInterface = "LearningContentInterface"; +export const LearningContentLearningModuleObjectType = "LearningContentLearningModuleObjectType"; +export const LearningContentMediaLibraryObjectType = "LearningContentMediaLibraryObjectType"; +export const LearningContentPlaceholderObjectType = "LearningContentPlaceholderObjectType"; +export const LearningContentRichTextObjectType = "LearningContentRichTextObjectType"; +export const LearningContentTestObjectType = "LearningContentTestObjectType"; +export const LearningContentVideoObjectType = "LearningContentVideoObjectType"; +export const LearningPathObjectType = "LearningPathObjectType"; +export const LearningSequenceObjectType = "LearningSequenceObjectType"; +export const LearningUnitObjectType = "LearningUnitObjectType"; +export const LearnpathLearningContentAssignmentAssignmentTypeChoices = "LearnpathLearningContentAssignmentAssignmentTypeChoices"; export const Mutation = "Mutation"; export const Node = "Node"; export const Query = "Query"; export const SendFeedbackInput = "SendFeedbackInput"; export const SendFeedbackPayload = "SendFeedbackPayload"; export const String = "String"; +export const TopicObjectType = "TopicObjectType"; export const UUID = "UUID"; export const UserType = "UserType";