diff --git a/src/core/apollo/generated/apollo-helpers.ts b/src/core/apollo/generated/apollo-helpers.ts index a4ac6a0be9..d0e696f7ba 100644 --- a/src/core/apollo/generated/apollo-helpers.ts +++ b/src/core/apollo/generated/apollo-helpers.ts @@ -15,6 +15,7 @@ export type AccountKeySpecifier = ( | 'license' | 'spaceID' | 'subscriptions' + | 'virtualContributors' | AccountKeySpecifier )[]; export type AccountFieldPolicy = { @@ -28,6 +29,7 @@ export type AccountFieldPolicy = { license?: FieldPolicy | FieldReadFunction; spaceID?: FieldPolicy | FieldReadFunction; subscriptions?: FieldPolicy | FieldReadFunction; + virtualContributors?: FieldPolicy | FieldReadFunction; }; export type AccountSubscriptionKeySpecifier = ('expires' | 'name' | AccountSubscriptionKeySpecifier)[]; export type AccountSubscriptionFieldPolicy = { @@ -1597,6 +1599,7 @@ export type MutationKeySpecifier = ( | 'deleteCallout' | 'deleteCalloutTemplate' | 'deleteCollaboration' + | 'deleteCommunityGuidelinesTemplate' | 'deleteDiscussion' | 'deleteDocument' | 'deleteInnovationFlowTemplate' @@ -1658,6 +1661,7 @@ export type MutationKeySpecifier = ( | 'updateCalloutsSortOrder' | 'updateCommunityApplicationForm' | 'updateCommunityGuidelines' + | 'updateCommunityGuidelinesTemplate' | 'updateDiscussion' | 'updateDocument' | 'updateEcosystemModel' @@ -1687,6 +1691,7 @@ export type MutationKeySpecifier = ( | 'updateUserGroup' | 'updateUserPlatformSettings' | 'updateVirtualContributor' + | 'updateVirtualContributorPlatformSettings' | 'updateVirtualPersona' | 'updateVisual' | 'updateWhiteboard' @@ -1754,6 +1759,7 @@ export type MutationFieldPolicy = { deleteCallout?: FieldPolicy | FieldReadFunction; deleteCalloutTemplate?: FieldPolicy | FieldReadFunction; deleteCollaboration?: FieldPolicy | FieldReadFunction; + deleteCommunityGuidelinesTemplate?: FieldPolicy | FieldReadFunction; deleteDiscussion?: FieldPolicy | FieldReadFunction; deleteDocument?: FieldPolicy | FieldReadFunction; deleteInnovationFlowTemplate?: FieldPolicy | FieldReadFunction; @@ -1815,6 +1821,7 @@ export type MutationFieldPolicy = { updateCalloutsSortOrder?: FieldPolicy | FieldReadFunction; updateCommunityApplicationForm?: FieldPolicy | FieldReadFunction; updateCommunityGuidelines?: FieldPolicy | FieldReadFunction; + updateCommunityGuidelinesTemplate?: FieldPolicy | FieldReadFunction; updateDiscussion?: FieldPolicy | FieldReadFunction; updateDocument?: FieldPolicy | FieldReadFunction; updateEcosystemModel?: FieldPolicy | FieldReadFunction; @@ -1844,6 +1851,7 @@ export type MutationFieldPolicy = { updateUserGroup?: FieldPolicy | FieldReadFunction; updateUserPlatformSettings?: FieldPolicy | FieldReadFunction; updateVirtualContributor?: FieldPolicy | FieldReadFunction; + updateVirtualContributorPlatformSettings?: FieldPolicy | FieldReadFunction; updateVirtualPersona?: FieldPolicy | FieldReadFunction; updateVisual?: FieldPolicy | FieldReadFunction; updateWhiteboard?: FieldPolicy | FieldReadFunction; diff --git a/src/core/apollo/generated/apollo-hooks.ts b/src/core/apollo/generated/apollo-hooks.ts index de8ce948a7..271df98663 100644 --- a/src/core/apollo/generated/apollo-hooks.ts +++ b/src/core/apollo/generated/apollo-hooks.ts @@ -14128,6 +14128,183 @@ export function refetchUserOrganizationIdsQuery(variables: SchemaTypes.UserOrgan return { query: UserOrganizationIdsDocument, variables: variables }; } +export const VirtualContributorDocument = gql` + query VirtualContributor($id: UUID_NAMEID!) { + virtualContributor(ID: $id) { + id + nameID + bodyOfKnowledgeID + authorization { + id + myPrivileges + } + account { + id + spaceID + host { + id + profile { + id + displayName + tagline + avatar: visual(type: AVATAR) { + uri + } + location { + id + city + country + } + } + } + } + profile { + id + displayName + description + tagline + tagsets { + ...TagsetDetails + } + url + avatar: visual(type: AVATAR) { + ...VisualFull + } + } + } + } + ${TagsetDetailsFragmentDoc} + ${VisualFullFragmentDoc} +`; + +/** + * __useVirtualContributorQuery__ + * + * To run a query within a React component, call `useVirtualContributorQuery` and pass it any options that fit your needs. + * When your component renders, `useVirtualContributorQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useVirtualContributorQuery({ + * variables: { + * id: // value for 'id' + * }, + * }); + */ +export function useVirtualContributorQuery( + baseOptions: Apollo.QueryHookOptions< + SchemaTypes.VirtualContributorQuery, + SchemaTypes.VirtualContributorQueryVariables + > +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useQuery( + VirtualContributorDocument, + options + ); +} + +export function useVirtualContributorLazyQuery( + baseOptions?: Apollo.LazyQueryHookOptions< + SchemaTypes.VirtualContributorQuery, + SchemaTypes.VirtualContributorQueryVariables + > +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useLazyQuery( + VirtualContributorDocument, + options + ); +} + +export type VirtualContributorQueryHookResult = ReturnType; +export type VirtualContributorLazyQueryHookResult = ReturnType; +export type VirtualContributorQueryResult = Apollo.QueryResult< + SchemaTypes.VirtualContributorQuery, + SchemaTypes.VirtualContributorQueryVariables +>; +export function refetchVirtualContributorQuery(variables: SchemaTypes.VirtualContributorQueryVariables) { + return { query: VirtualContributorDocument, variables: variables }; +} + +export const BodyOfKnowledgeProfileDocument = gql` + query BodyOfKnowledgeProfile($spaceId: UUID!) { + lookup { + space(ID: $spaceId) { + id + profile { + id + displayName + tagline + url + avatar: visual(type: AVATAR) { + id + uri + } + cardBanner: visual(type: CARD) { + id + uri + } + } + } + } + } +`; + +/** + * __useBodyOfKnowledgeProfileQuery__ + * + * To run a query within a React component, call `useBodyOfKnowledgeProfileQuery` and pass it any options that fit your needs. + * When your component renders, `useBodyOfKnowledgeProfileQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useBodyOfKnowledgeProfileQuery({ + * variables: { + * spaceId: // value for 'spaceId' + * }, + * }); + */ +export function useBodyOfKnowledgeProfileQuery( + baseOptions: Apollo.QueryHookOptions< + SchemaTypes.BodyOfKnowledgeProfileQuery, + SchemaTypes.BodyOfKnowledgeProfileQueryVariables + > +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useQuery( + BodyOfKnowledgeProfileDocument, + options + ); +} + +export function useBodyOfKnowledgeProfileLazyQuery( + baseOptions?: Apollo.LazyQueryHookOptions< + SchemaTypes.BodyOfKnowledgeProfileQuery, + SchemaTypes.BodyOfKnowledgeProfileQueryVariables + > +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useLazyQuery( + BodyOfKnowledgeProfileDocument, + options + ); +} + +export type BodyOfKnowledgeProfileQueryHookResult = ReturnType; +export type BodyOfKnowledgeProfileLazyQueryHookResult = ReturnType; +export type BodyOfKnowledgeProfileQueryResult = Apollo.QueryResult< + SchemaTypes.BodyOfKnowledgeProfileQuery, + SchemaTypes.BodyOfKnowledgeProfileQueryVariables +>; +export function refetchBodyOfKnowledgeProfileQuery(variables: SchemaTypes.BodyOfKnowledgeProfileQueryVariables) { + return { query: BodyOfKnowledgeProfileDocument, variables: variables }; +} + export const InnovationHubAvailableSpacesDocument = gql` query InnovationHubAvailableSpaces { spaces(filter: { visibilities: [ACTIVE, DEMO] }) { @@ -17161,6 +17338,198 @@ export type UpdateSpaceSettingsMutationOptions = Apollo.BaseMutationOptions< SchemaTypes.UpdateSpaceSettingsMutation, SchemaTypes.UpdateSpaceSettingsMutationVariables >; +export const CreateVirtualContributorOnAccountDocument = gql` + mutation CreateVirtualContributorOnAccount($virtualContributorData: CreateVirtualContributorOnAccountInput!) { + createVirtualContributor(virtualContributorData: $virtualContributorData) { + id + profile { + id + url + } + } + } +`; +export type CreateVirtualContributorOnAccountMutationFn = Apollo.MutationFunction< + SchemaTypes.CreateVirtualContributorOnAccountMutation, + SchemaTypes.CreateVirtualContributorOnAccountMutationVariables +>; + +/** + * __useCreateVirtualContributorOnAccountMutation__ + * + * To run a mutation, you first call `useCreateVirtualContributorOnAccountMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useCreateVirtualContributorOnAccountMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [createVirtualContributorOnAccountMutation, { data, loading, error }] = useCreateVirtualContributorOnAccountMutation({ + * variables: { + * virtualContributorData: // value for 'virtualContributorData' + * }, + * }); + */ +export function useCreateVirtualContributorOnAccountMutation( + baseOptions?: Apollo.MutationHookOptions< + SchemaTypes.CreateVirtualContributorOnAccountMutation, + SchemaTypes.CreateVirtualContributorOnAccountMutationVariables + > +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useMutation< + SchemaTypes.CreateVirtualContributorOnAccountMutation, + SchemaTypes.CreateVirtualContributorOnAccountMutationVariables + >(CreateVirtualContributorOnAccountDocument, options); +} + +export type CreateVirtualContributorOnAccountMutationHookResult = ReturnType< + typeof useCreateVirtualContributorOnAccountMutation +>; +export type CreateVirtualContributorOnAccountMutationResult = + Apollo.MutationResult; +export type CreateVirtualContributorOnAccountMutationOptions = Apollo.BaseMutationOptions< + SchemaTypes.CreateVirtualContributorOnAccountMutation, + SchemaTypes.CreateVirtualContributorOnAccountMutationVariables +>; +export const DeleteVirtualContributorOnAccountDocument = gql` + mutation DeleteVirtualContributorOnAccount($virtualContributorData: DeleteVirtualContributorInput!) { + deleteVirtualContributor(deleteData: $virtualContributorData) { + id + } + } +`; +export type DeleteVirtualContributorOnAccountMutationFn = Apollo.MutationFunction< + SchemaTypes.DeleteVirtualContributorOnAccountMutation, + SchemaTypes.DeleteVirtualContributorOnAccountMutationVariables +>; + +/** + * __useDeleteVirtualContributorOnAccountMutation__ + * + * To run a mutation, you first call `useDeleteVirtualContributorOnAccountMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useDeleteVirtualContributorOnAccountMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [deleteVirtualContributorOnAccountMutation, { data, loading, error }] = useDeleteVirtualContributorOnAccountMutation({ + * variables: { + * virtualContributorData: // value for 'virtualContributorData' + * }, + * }); + */ +export function useDeleteVirtualContributorOnAccountMutation( + baseOptions?: Apollo.MutationHookOptions< + SchemaTypes.DeleteVirtualContributorOnAccountMutation, + SchemaTypes.DeleteVirtualContributorOnAccountMutationVariables + > +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useMutation< + SchemaTypes.DeleteVirtualContributorOnAccountMutation, + SchemaTypes.DeleteVirtualContributorOnAccountMutationVariables + >(DeleteVirtualContributorOnAccountDocument, options); +} + +export type DeleteVirtualContributorOnAccountMutationHookResult = ReturnType< + typeof useDeleteVirtualContributorOnAccountMutation +>; +export type DeleteVirtualContributorOnAccountMutationResult = + Apollo.MutationResult; +export type DeleteVirtualContributorOnAccountMutationOptions = Apollo.BaseMutationOptions< + SchemaTypes.DeleteVirtualContributorOnAccountMutation, + SchemaTypes.DeleteVirtualContributorOnAccountMutationVariables +>; +export const SpaceSubspacesDocument = gql` + query SpaceSubspaces($spaceId: UUID_NAMEID!) { + space(ID: $spaceId) { + id + profile { + id + displayName + } + account { + id + authorization { + myPrivileges + } + virtualContributors { + id + nameID + bodyOfKnowledgeID + profile { + displayName + url + avatar: visual(type: AVATAR) { + uri + } + } + } + } + subspaces { + id + profile { + id + displayName + avatar: visual(type: AVATAR) { + uri + } + } + } + } + } +`; + +/** + * __useSpaceSubspacesQuery__ + * + * To run a query within a React component, call `useSpaceSubspacesQuery` and pass it any options that fit your needs. + * When your component renders, `useSpaceSubspacesQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useSpaceSubspacesQuery({ + * variables: { + * spaceId: // value for 'spaceId' + * }, + * }); + */ +export function useSpaceSubspacesQuery( + baseOptions: Apollo.QueryHookOptions +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useQuery( + SpaceSubspacesDocument, + options + ); +} + +export function useSpaceSubspacesLazyQuery( + baseOptions?: Apollo.LazyQueryHookOptions +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useLazyQuery( + SpaceSubspacesDocument, + options + ); +} + +export type SpaceSubspacesQueryHookResult = ReturnType; +export type SpaceSubspacesLazyQueryHookResult = ReturnType; +export type SpaceSubspacesQueryResult = Apollo.QueryResult< + SchemaTypes.SpaceSubspacesQuery, + SchemaTypes.SpaceSubspacesQueryVariables +>; +export function refetchSpaceSubspacesQuery(variables: SchemaTypes.SpaceSubspacesQueryVariables) { + return { query: SpaceSubspacesDocument, variables: variables }; +} + export const SpaceDashboardNavigationChallengesDocument = gql` query SpaceDashboardNavigationChallenges($spaceId: UUID!) { lookup { diff --git a/src/core/apollo/generated/graphql-schema.ts b/src/core/apollo/generated/graphql-schema.ts index a77caf5ad7..8055867878 100644 --- a/src/core/apollo/generated/graphql-schema.ts +++ b/src/core/apollo/generated/graphql-schema.ts @@ -56,6 +56,8 @@ export type Account = { spaceID: Scalars['String']; /** The subscriptions active for this Account. */ subscriptions: Array; + /** The virtual contributors for this Account. */ + virtualContributors: Array; }; export type AccountAuthorizationResetInput = { @@ -760,6 +762,7 @@ export enum AuthorizationPrivilege { } export enum BodyOfKnowledgeType { + Other = 'OTHER', Space = 'SPACE', } @@ -1737,8 +1740,8 @@ export type CreateUserInput = { export type CreateVirtualContributorOnAccountInput = { accountID: Scalars['UUID']; - bodyOfKnowledgeID: Scalars['UUID']; - bodyOfKnowledgeType: BodyOfKnowledgeType; + bodyOfKnowledgeID?: InputMaybe; + bodyOfKnowledgeType?: InputMaybe; /** A readable identifier, unique within the containing scope. */ nameID: Scalars['NameID']; profileData: CreateProfileInput; @@ -1860,6 +1863,10 @@ export type DeleteCollaborationInput = { ID: Scalars['UUID']; }; +export type DeleteCommunityGuidelinesTemplateInput = { + ID: Scalars['UUID']; +}; + export type DeleteDiscussionInput = { ID: Scalars['UUID']; }; @@ -2791,6 +2798,8 @@ export type Mutation = { deleteCalloutTemplate: CalloutTemplate; /** Delete Collaboration. */ deleteCollaboration: Collaboration; + /** Deletes the specified CommunityGuidelines Template. */ + deleteCommunityGuidelinesTemplate: CommunityGuidelinesTemplate; /** Deletes the specified Discussion. */ deleteDiscussion: Discussion; /** Deletes the specified Document. */ @@ -2913,6 +2922,8 @@ export type Mutation = { updateCommunityApplicationForm: Community; /** Updates the CommunityGuidelines. */ updateCommunityGuidelines: CommunityGuidelines; + /** Updates the specified CommunityGuidelinesTemplate. */ + updateCommunityGuidelinesTemplate: CommunityGuidelinesTemplate; /** Updates the specified Discussion. */ updateDiscussion: Discussion; /** Updates the specified Document. */ @@ -2971,6 +2982,8 @@ export type Mutation = { updateUserPlatformSettings: User; /** Updates the specified VirtualContributor. */ updateVirtualContributor: VirtualContributor; + /** Update VirtualContributor Platform Settings. */ + updateVirtualContributorPlatformSettings: VirtualContributor; /** Updates the specified VirtualPersona. */ updateVirtualPersona: VirtualPersona; /** Updates the image URI for the specified Visual. */ @@ -3191,6 +3204,10 @@ export type MutationDeleteCollaborationArgs = { deleteData: DeleteCollaborationInput; }; +export type MutationDeleteCommunityGuidelinesTemplateArgs = { + deleteData: DeleteCommunityGuidelinesTemplateInput; +}; + export type MutationDeleteDiscussionArgs = { deleteData: DeleteDiscussionInput; }; @@ -3427,6 +3444,10 @@ export type MutationUpdateCommunityGuidelinesArgs = { communityGuidelinesData: UpdateCommunityGuidelinesInput; }; +export type MutationUpdateCommunityGuidelinesTemplateArgs = { + communityGuidelinesTemplateInput: UpdateCommunityGuidelinesTemplateInput; +}; + export type MutationUpdateDiscussionArgs = { updateData: UpdateDiscussionInput; }; @@ -3543,6 +3564,10 @@ export type MutationUpdateVirtualContributorArgs = { virtualContributorData: UpdateVirtualContributorInput; }; +export type MutationUpdateVirtualContributorPlatformSettingsArgs = { + updateData: UpdateVirtualContributorPlatformSettingsInput; +}; + export type MutationUpdateVirtualPersonaArgs = { virtualPersonaData: UpdateVirtualPersonaInput; }; @@ -5183,6 +5208,19 @@ export type UpdateCommunityGuidelinesInput = { profile: UpdateProfileInput; }; +export type UpdateCommunityGuidelinesOfTemplateInput = { + /** The Profile for this community guidelines. */ + profile: UpdateProfileInput; +}; + +export type UpdateCommunityGuidelinesTemplateInput = { + ID: Scalars['UUID']; + /** The Community guidelines to associate with this template. */ + communityGuidelines?: InputMaybe; + /** The Profile of the Template. */ + profile?: InputMaybe; +}; + export type UpdateContextInput = { impact?: InputMaybe; vision?: InputMaybe; @@ -5521,6 +5559,12 @@ export type UpdateVirtualContributorInput = { profileData?: InputMaybe; }; +export type UpdateVirtualContributorPlatformSettingsInput = { + ID: Scalars['UUID']; + /** An Account ID associated with the VirtualContributor */ + accountID: Scalars['UUID']; +}; + export type UpdateVirtualPersonaInput = { ID: Scalars['UUID']; engine: VirtualContributorEngine; @@ -5708,9 +5752,9 @@ export type VirtualContributor = Contributor & { /** The authorization rules for the Contributor */ authorization?: Maybe; /** The body of knowledge ID used for the Virtual Contributor */ - bodyOfKnowledgeID: Scalars['UUID']; + bodyOfKnowledgeID?: Maybe; /** The body of knowledge type used for the Virtual Contributor */ - bodyOfKnowledgeType: BodyOfKnowledgeType; + bodyOfKnowledgeType?: Maybe; /** The ID of the Contributor */ id: Scalars['UUID']; /** A name identifier of the Contributor, unique within a given scope. */ @@ -17352,6 +17396,127 @@ export type UserOrganizationIdsQuery = { }; }; +export type VirtualContributorQueryVariables = Exact<{ + id: Scalars['UUID_NAMEID']; +}>; + +export type VirtualContributorQuery = { + __typename?: 'Query'; + virtualContributor: { + __typename?: 'VirtualContributor'; + id: string; + nameID: string; + bodyOfKnowledgeID?: string | undefined; + authorization?: + | { __typename?: 'Authorization'; id: string; myPrivileges?: Array | undefined } + | undefined; + account?: + | { + __typename?: 'Account'; + id: string; + spaceID: string; + host?: + | { + __typename?: 'Organization'; + id: string; + profile: { + __typename?: 'Profile'; + id: string; + displayName: string; + tagline: string; + avatar?: { __typename?: 'Visual'; uri: string } | undefined; + location?: { __typename?: 'Location'; id: string; city: string; country: string } | undefined; + }; + } + | { + __typename?: 'User'; + id: string; + profile: { + __typename?: 'Profile'; + id: string; + displayName: string; + tagline: string; + avatar?: { __typename?: 'Visual'; uri: string } | undefined; + location?: { __typename?: 'Location'; id: string; city: string; country: string } | undefined; + }; + } + | { + __typename?: 'VirtualContributor'; + id: string; + profile: { + __typename?: 'Profile'; + id: string; + displayName: string; + tagline: string; + avatar?: { __typename?: 'Visual'; uri: string } | undefined; + location?: { __typename?: 'Location'; id: string; city: string; country: string } | undefined; + }; + } + | undefined; + } + | undefined; + profile: { + __typename?: 'Profile'; + id: string; + displayName: string; + description?: string | undefined; + tagline: string; + url: string; + tagsets?: + | Array<{ + __typename?: 'Tagset'; + id: string; + name: string; + tags: Array; + allowedValues: Array; + type: TagsetType; + }> + | undefined; + avatar?: + | { + __typename?: 'Visual'; + id: string; + uri: string; + name: string; + allowedTypes: Array; + aspectRatio: number; + maxHeight: number; + maxWidth: number; + minHeight: number; + minWidth: number; + alternativeText?: string | undefined; + } + | undefined; + }; + }; +}; + +export type BodyOfKnowledgeProfileQueryVariables = Exact<{ + spaceId: Scalars['UUID']; +}>; + +export type BodyOfKnowledgeProfileQuery = { + __typename?: 'Query'; + lookup: { + __typename?: 'LookupQueryResults'; + space?: + | { + __typename?: 'Space'; + id: string; + profile: { + __typename?: 'Profile'; + id: string; + displayName: string; + tagline: string; + url: string; + avatar?: { __typename?: 'Visual'; id: string; uri: string } | undefined; + cardBanner?: { __typename?: 'Visual'; id: string; uri: string } | undefined; + }; + } + | undefined; + }; +}; + export type ContextDetailsFragment = { __typename?: 'Context'; id: string; @@ -21325,6 +21490,70 @@ export type UpdateSpaceSettingsMutation = { }; }; +export type CreateVirtualContributorOnAccountMutationVariables = Exact<{ + virtualContributorData: CreateVirtualContributorOnAccountInput; +}>; + +export type CreateVirtualContributorOnAccountMutation = { + __typename?: 'Mutation'; + createVirtualContributor: { + __typename?: 'VirtualContributor'; + id: string; + profile: { __typename?: 'Profile'; id: string; url: string }; + }; +}; + +export type DeleteVirtualContributorOnAccountMutationVariables = Exact<{ + virtualContributorData: DeleteVirtualContributorInput; +}>; + +export type DeleteVirtualContributorOnAccountMutation = { + __typename?: 'Mutation'; + deleteVirtualContributor: { __typename?: 'VirtualContributor'; id: string }; +}; + +export type SpaceSubspacesQueryVariables = Exact<{ + spaceId: Scalars['UUID_NAMEID']; +}>; + +export type SpaceSubspacesQuery = { + __typename?: 'Query'; + space: { + __typename?: 'Space'; + id: string; + profile: { __typename?: 'Profile'; id: string; displayName: string }; + account: { + __typename?: 'Account'; + id: string; + authorization?: + | { __typename?: 'Authorization'; myPrivileges?: Array | undefined } + | undefined; + virtualContributors: Array<{ + __typename?: 'VirtualContributor'; + id: string; + nameID: string; + bodyOfKnowledgeID?: string | undefined; + profile: { + __typename?: 'Profile'; + displayName: string; + url: string; + avatar?: { __typename?: 'Visual'; uri: string } | undefined; + }; + }>; + }; + subspaces: Array<{ + __typename?: 'Space'; + id: string; + profile: { + __typename?: 'Profile'; + id: string; + displayName: string; + avatar?: { __typename?: 'Visual'; uri: string } | undefined; + }; + }>; + }; +}; + export type SpaceDashboardNavigationChallengesQueryVariables = Exact<{ spaceId: Scalars['UUID']; }>; diff --git a/src/core/i18n/en/translation.en.json b/src/core/i18n/en/translation.en.json index 13ea0ad7db..9b626eac99 100644 --- a/src/core/i18n/en/translation.en.json +++ b/src/core/i18n/en/translation.en.json @@ -344,6 +344,7 @@ "sources": "Sources", "license": "License", "virtual-contributors": "VC", + "virtual-contributor": "Virtual Contributor", "collaborationTool": "Collaboration tool", "genders": { "notSpecified": "not specified", @@ -1905,6 +1906,10 @@ "createSubspaces": "Create Subspaces: allow members to create Subspaces in this Space. If you deactivate this, you can still create Subspaces yourself and add other people as an admin inside the Subspace.", "inheritRights": "Allow Space members to contribute.", "supportAsAdmin": "Alkemio Support: Allow the Alkemio Support team to act as an admin in this Space." + }, + "account": { + "vc-section-title": "Virtual Contributors created from this Space", + "vc-create-button": "Create Virtual Contributor" } } }, @@ -2454,6 +2459,37 @@ "help": "Credentials that the user holds issued by trusted parties" } }, + "virtualContributorProfile": { + "title": "Virtual Contributor Profile", + "default-name": "Alkemio Help", + "description": "Description", + "references": "References", + "host": "Host", + "sections": { + "knowledge": { + "title": "Knowledge", + "description": "Answers {{name}} gives are based on the body of knowledge coming from:" + }, + + "personality": { + "title": "Basic Prompts & Engine", + "description": "To allow people to interact with the body of knowledge described above, Alkemio uses an engine and a basic set of instructions. These instructions make sure that the Virtual Contributor for example only answers questions using the specified body of knowledge so you can trust the answers it is giving." + }, + "context": { + "title": "Context", + "description": "{{name}} uses the following information from the Space it is invited to so it can provide you with meaningful answers:", + "bullets": "
  • Space about page:
    • Name, Tagline, location, etc.
    • Context information
    • Statistics
" + }, + "privacy": { + "title": "Privacy", + "description": "For Alkemio, safeguarding your data is of utmost importance. We are committed to maintaining the security and privacy of your information.", + "bullets": "
  • When interacting with a Virtual Contributor, only the data explicitly specified on the left (Context) is used to generate meaningful answers.
  • Importantly, your (Space) data is not utilized for training the Virtual Contributor.
  • Additionally, please note that questions and answers exchanged with the Virtual Contributor may be visible to the Alkemio team.
" + } + }, + "settings": { + "title": "Virtual Contributor Settings" + } + }, "user-credentials": { "your-credentials": { "title": "My Verifiable Credentials", @@ -2772,5 +2808,14 @@ } } } + }, + "virtualContributorSpaceSettings": { + "title": "Create a Virtual Contributor", + "name": "Name", + "body-of-knowledge": "Body Of Knowledge", + "info-text": "Select the Space or Subspace that you want to use as a body of knowledge for this Virtual Contributor", + "confirm-deletion": { + "description": "Are you certain you want to delete this {{entity}}? Keep in mind that this action is irreversible. All profile information will be removed and people will no longer be able to interact with the {{entity}}. " + } } } diff --git a/src/core/ui/palette/palette.ts b/src/core/ui/palette/palette.ts index 8e96f8a211..87c1b16f0e 100644 --- a/src/core/ui/palette/palette.ts +++ b/src/core/ui/palette/palette.ts @@ -35,6 +35,9 @@ export const paletteOptions: PaletteOptions = { space: { dark: '#152A37', }, + icons: { + dark: '#1C1B1F', + }, }; declare module '@mui/material/styles/createPalette' { @@ -47,6 +50,7 @@ declare module '@mui/material/styles/createPalette' { neutralLight: PaletteColorOptions; highlight: PaletteColorOptions; space: PaletteColorOptions; + icons: PaletteColorOptions; } interface Palette { @@ -58,5 +62,6 @@ declare module '@mui/material/styles/createPalette' { neutralLight: PaletteColor; highlight: PaletteColor; space: PaletteColor; + icons: PaletteColorOptions; } } diff --git a/src/domain/common/profile/ProfilePageBanner.tsx b/src/domain/common/profile/ProfilePageBanner.tsx index abf5fe1ad3..9a98034ccc 100644 --- a/src/domain/common/profile/ProfilePageBanner.tsx +++ b/src/domain/common/profile/ProfilePageBanner.tsx @@ -13,6 +13,7 @@ import { Visual } from '../visual/Visual'; import { Location } from '../../../core/ui/location/getLocationString'; import { useTranslation } from 'react-i18next'; import PageBannerWatermark from '../../../main/ui/platformNavigation/PageBannerWatermark'; +import VirtualContributorLabel from '../../community/virtualContributor/VirtualContributorLabel'; const banner: Visual = { uri: '/alkemio-banner/global-banner.jpg', @@ -37,6 +38,7 @@ export interface ProfilePageBannerProps { settingsUri?: string; onSendMessage?: (messageText: string) => Promise; loading?: boolean; + isVirtualContributor?: boolean; } const ProfilePageBanner = ({ @@ -45,6 +47,7 @@ const ProfilePageBanner = ({ settingsUri, onSendMessage, loading = false, + isVirtualContributor = false, }: ProfilePageBannerProps) => { const isMobile = useMediaQuery(theme => theme.breakpoints.down('lg')); @@ -97,6 +100,7 @@ const ProfilePageBanner = ({ {profile?.location && } + {isVirtualContributor && } {onSendMessage && ( diff --git a/src/domain/community/virtualContributor/VCRoute.tsx b/src/domain/community/virtualContributor/VCRoute.tsx new file mode 100644 index 0000000000..ab88447f9a --- /dev/null +++ b/src/domain/community/virtualContributor/VCRoute.tsx @@ -0,0 +1,28 @@ +import React, { FC } from 'react'; +import { Route, Routes } from 'react-router-dom'; +import VCProfilePage from './vcProfilePage/VCProfilePage'; +import { PageLayoutHolderWithOutlet } from '../../journey/common/EntityPageLayout'; +import TopLevelLayout from '../../../main/ui/layout/TopLevelLayout'; +import { Error404 } from '../../../core/pages/Errors/Error404'; +import VCSettingsPage from './vcSettingsPage/VCSettingsPage'; + +export const VCRoute: FC = () => { + return ( + + }> + } /> + + } /> + + + + } + /> + + ); +}; + +export default VCRoute; diff --git a/src/domain/community/virtualContributor/VirtualContributor.graphql b/src/domain/community/virtualContributor/VirtualContributor.graphql new file mode 100644 index 0000000000..3b70faeb77 --- /dev/null +++ b/src/domain/community/virtualContributor/VirtualContributor.graphql @@ -0,0 +1,66 @@ +query VirtualContributor ($id: UUID_NAMEID!) { + virtualContributor (ID: $id) { + id + nameID + bodyOfKnowledgeID + authorization { + id + myPrivileges + } + account { + id + spaceID + host { + id + profile { + id + displayName + tagline + avatar: visual(type: AVATAR) { + uri + } + location { + id + city + country + } + } + } + } + profile { + id + displayName + description + tagline + tagsets { + ...TagsetDetails + } + url + avatar: visual(type: AVATAR) { + ...VisualFull + } + } + } +} + +query BodyOfKnowledgeProfile($spaceId: UUID!) { + lookup { + space(ID: $spaceId) { + id + profile { + id + displayName + tagline + url + avatar: visual(type: AVATAR) { + id + uri + } + cardBanner: visual(type: CARD) { + id + uri + } + } + } + } +} \ No newline at end of file diff --git a/src/domain/community/virtualContributor/VirtualContributorLabel.tsx b/src/domain/community/virtualContributor/VirtualContributorLabel.tsx index 6049ab67c5..d1dddead8f 100644 --- a/src/domain/community/virtualContributor/VirtualContributorLabel.tsx +++ b/src/domain/community/virtualContributor/VirtualContributorLabel.tsx @@ -1,18 +1,25 @@ import { CaptionSmall } from '../../../core/ui/typography'; import { useTranslation } from 'react-i18next'; -import { ReactComponent as VirtualContributorIcon } from './VirtualContributor.svg'; -import { SvgIcon } from '@mui/material'; +import { Chip, SvgIcon } from '@mui/material'; import { gutters } from '../../../core/ui/grid/utils'; +import VCIcon from './VirtualContributorsIcons'; -const VirtualContributorLabel = () => { +const VirtualContributorLabel = ({ chip = false }) => { const { t } = useTranslation(); + if (chip) { + return ( + } + /> + ); + } + return ( - + {t('community.virtualContributor')} ); diff --git a/src/domain/community/virtualContributor/VirtualContributorsIcons.tsx b/src/domain/community/virtualContributor/VirtualContributorsIcons.tsx new file mode 100644 index 0000000000..804dc34512 --- /dev/null +++ b/src/domain/community/virtualContributor/VirtualContributorsIcons.tsx @@ -0,0 +1,17 @@ +import React from 'react'; + +const VCIcon = ({ fill = '#1C1B1F', ...props }) => ( + + + + + + + + +); + +export default VCIcon; diff --git a/src/domain/community/virtualContributor/components/BasicSpaceCard.tsx b/src/domain/community/virtualContributor/components/BasicSpaceCard.tsx new file mode 100644 index 0000000000..2eda3ce81c --- /dev/null +++ b/src/domain/community/virtualContributor/components/BasicSpaceCard.tsx @@ -0,0 +1,61 @@ +import React, { FC } from 'react'; +import BadgeCardView from '../../../../core/ui/list/BadgeCardView'; +import Avatar from '../../../../core/ui/avatar/Avatar'; +import { BlockSectionTitle } from '../../../../core/ui/typography'; +import { useTranslation } from 'react-i18next'; +import RouterLink from '../../../../core/ui/link/RouterLink'; +import defaultJourneyCardBanner from '../../../../domain/journey/defaultVisuals/Card.jpg'; + +// TODO: add cardBanner if we want support of Spaces as BOK +export interface BasicSpaceProps { + avatar?: { + uri: string; + }; + displayName: string; + tagline: string; + url: string; +} + +interface Props { + space: BasicSpaceProps | undefined; + showDefaults?: boolean; +} + +const DEFULT_SPACE_DATA = { + avatar: { + uri: 'https://alkem.io/api/private/rest/storage/document/1057e0c1-2d47-4821-8848-20ec19cb2a0d', + }, + displayName: 'Welcome @ Alkemio!', + tagline: 'Take 5 minutes to get started', + url: 'https://alkem.io/welcome-space', +}; + +const BasicSpaceCard: FC = ({ space, showDefaults }) => { + const { t } = useTranslation(); + + const spaceData = space ? space : showDefaults ? DEFULT_SPACE_DATA : undefined; + + if (!spaceData) { + return null; + } + + return ( + + {spaceData.displayName} + + } + component={RouterLink} + to={spaceData.url} + > + {spaceData.displayName} + {spaceData.tagline} + + ); +}; + +export default BasicSpaceCard; diff --git a/src/domain/community/virtualContributor/components/HostCard.tsx b/src/domain/community/virtualContributor/components/HostCard.tsx new file mode 100644 index 0000000000..c724646860 --- /dev/null +++ b/src/domain/community/virtualContributor/components/HostCard.tsx @@ -0,0 +1,65 @@ +import React, { FC } from 'react'; +import PageContentBlock from '../../../../core/ui/content/PageContentBlock'; +import PageContentBlockHeader from '../../../../core/ui/content/PageContentBlockHeader'; +import BadgeCardView from '../../../../core/ui/list/BadgeCardView'; +import Avatar from '../../../../core/ui/avatar/Avatar'; +import { BlockSectionTitle } from '../../../../core/ui/typography'; +import getLocationString from '../../../../core/ui/location/getLocationString'; +import { useTranslation } from 'react-i18next'; +import { LocationIcon } from '../../../timeline/calendar/icons/LocationIcon'; +import { theme } from '../../../../core/ui/themes/default/Theme'; + +interface HostProps { + hostProfile?: { + avatar?: { + uri: string; + }; + displayName: string; + location?: { + city: string; + country: string; + }; + }; +} + +const DEFAULT_PROFILE = { + avatar: { + uri: 'https://alkem.io/api/private/rest/storage/document/e58662b2-50f1-4c33-a8b4-40d601000afd', + }, + displayName: 'Alkemio Foundation', + location: { + city: 'Hague', + country: 'NL', + }, +}; + +const HostCard: FC = ({ hostProfile }) => { + const { t } = useTranslation(); + + const profile = hostProfile || DEFAULT_PROFILE; + + return ( + <> + + + + {profile.displayName[0]} + + } + > + {profile.displayName} + {profile.location && ( + + + {getLocationString(profile.location)} + + )} + + + + ); +}; + +export default HostCard; diff --git a/src/domain/community/virtualContributor/layout/VCPageBanner.tsx b/src/domain/community/virtualContributor/layout/VCPageBanner.tsx new file mode 100644 index 0000000000..dbbb42084b --- /dev/null +++ b/src/domain/community/virtualContributor/layout/VCPageBanner.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { useVirtualContributorQuery } from '../../../../core/apollo/generated/apollo-hooks'; +import { useUrlParams } from '../../../../core/routing/useUrlParams'; +import ProfilePageBanner from '../../../common/profile/ProfilePageBanner'; +import { AuthorizationPrivilege } from '../../../../core/apollo/generated/graphql-schema'; +import { buildSettingsUrl } from '../../../../main/routing/urlBuilders'; + +const VCPageBanner = () => { + const { vcNameId = '' } = useUrlParams(); + + const { data, loading } = useVirtualContributorQuery({ + variables: { + id: vcNameId, + }, + }); + + const profile = data?.virtualContributor.profile; + + const vcId = data?.virtualContributor.id; + + const hasSettingsAccess = data?.virtualContributor.authorization?.myPrivileges?.includes( + AuthorizationPrivilege.Update + ); + + return ( + + ); +}; + +export default VCPageBanner; diff --git a/src/domain/community/virtualContributor/layout/VCPageLayout.tsx b/src/domain/community/virtualContributor/layout/VCPageLayout.tsx new file mode 100644 index 0000000000..0649d194ae --- /dev/null +++ b/src/domain/community/virtualContributor/layout/VCPageLayout.tsx @@ -0,0 +1,48 @@ +import React, { PropsWithChildren } from 'react'; +import TopLevelPageBreadcrumbs from '../../../../main/topLevelPages/topLevelPageBreadcrumbs/TopLevelPageBreadcrumbs'; +import { AssignmentIndOutlined } from '@mui/icons-material'; +import { useUrlParams } from '../../../../core/routing/useUrlParams'; +import TopLevelLayout from '../../../../main/ui/layout/TopLevelLayout'; +import BreadcrumbsItem from '../../../../core/ui/navigation/BreadcrumbsItem'; +import GroupOutlinedIcon from '@mui/icons-material/GroupOutlined'; +import { useTranslation } from 'react-i18next'; +import VCPageBanner from './VCPageBanner'; +import { useVirtualContributorQuery } from '../../../../core/apollo/generated/apollo-hooks'; + +interface VCPageLayoutProps {} + +const VCPageLayout = ({ ...props }: PropsWithChildren) => { + const { vcNameId = '' } = useUrlParams(); + + const { data, loading } = useVirtualContributorQuery({ + variables: { + id: vcNameId, + }, + }); + + const { t } = useTranslation(); + + return ( + + + {t('pages.contributors.shortName')} + + + {data?.virtualContributor.profile.displayName} + + + } + header={} + {...props} + /> + ); +}; + +export default VCPageLayout; diff --git a/src/domain/community/virtualContributor/vcProfilePage/VCProfilePage.tsx b/src/domain/community/virtualContributor/vcProfilePage/VCProfilePage.tsx new file mode 100644 index 0000000000..2fa0c4bcbb --- /dev/null +++ b/src/domain/community/virtualContributor/vcProfilePage/VCProfilePage.tsx @@ -0,0 +1,55 @@ +import React from 'react'; +import Loading from '../../../../core/ui/loading/Loading'; +import { useUrlParams } from '../../../../core/routing/useUrlParams'; +import { Error404 } from '../../../../core/pages/Errors/Error404'; +import VCPageLayout from '../layout/VCPageLayout'; +import VCProfilePageView from './VCProfilePageView'; +import { + useBodyOfKnowledgeProfileQuery, + useVirtualContributorQuery, +} from '../../../../core/apollo/generated/apollo-hooks'; +import { useTranslation } from 'react-i18next'; + +export const VCProfilePage = () => { + const { t } = useTranslation(); + + const { vcNameId = '' } = useUrlParams(); + + const { data, loading, error } = useVirtualContributorQuery({ + variables: { + id: vcNameId, + }, + }); + + const { data: bokProfile, loading: loadingBok } = useBodyOfKnowledgeProfileQuery({ + variables: { + spaceId: data?.virtualContributor.bodyOfKnowledgeID!, + }, + skip: !data?.virtualContributor.bodyOfKnowledgeID, + }); + + if (loading) + return ( + + ); + + if (error) { + return ( + + + + ); + } + + return ( + + + + ); +}; + +export default VCProfilePage; diff --git a/src/domain/community/virtualContributor/vcProfilePage/VCProfilePageView.tsx b/src/domain/community/virtualContributor/vcProfilePage/VCProfilePageView.tsx new file mode 100644 index 0000000000..dbf70f6a94 --- /dev/null +++ b/src/domain/community/virtualContributor/vcProfilePage/VCProfilePageView.tsx @@ -0,0 +1,103 @@ +import React, { FC, PropsWithChildren } from 'react'; +import RecordVoiceOverIcon from '@mui/icons-material/RecordVoiceOver'; +import ShieldIcon from '@mui/icons-material/Shield'; +import CloudDownloadIcon from '@mui/icons-material/CloudDownload'; +import BookIcon from '@mui/icons-material/Book'; +import PageContent from '../../../../core/ui/content/PageContent'; +import PageContentColumn from '../../../../core/ui/content/PageContentColumn'; +import { VirtualContributorQuery } from '../../../../core/apollo/generated/graphql-schema'; +import { BlockTitle, Text } from '../../../../core/ui/typography'; +import PageContentBlock from '../../../../core/ui/content/PageContentBlock'; +import HostCard from '../components/HostCard'; +import useTheme from '@mui/material/styles/useTheme'; +import { Trans, useTranslation } from 'react-i18next'; +import ProfileDetail from '../../profile/ProfileDetail/ProfileDetail'; +import BasicSpaceCard, { BasicSpaceProps } from '../components/BasicSpaceCard'; +import Spacer from '../../../../core/ui/content/Spacer'; + +interface Props { + virtualContributor: VirtualContributorQuery['virtualContributor'] | undefined; + bokProfile?: BasicSpaceProps; + showDefaults?: boolean; +} + +const SectionTitle = ({ children }) => ( + theme.spacing(1)}> + {children} + +); + +const SectionContent = ({ children }) => {children}; + +export const VCProfilePageView: FC> = ({ + virtualContributor, + bokProfile, + showDefaults = false, +}) => { + const theme = useTheme(); + const { t } = useTranslation(); + + const name = virtualContributor?.profile.displayName || t('pages.virtualContributorProfile.default-name'); + + return ( + + + + + + + + + + + + {t('pages.virtualContributorProfile.sections.knowledge.title')} + + + + + + + + + {t('pages.virtualContributorProfile.sections.personality.title')} + + + + + + + + {t('pages.virtualContributorProfile.sections.context.title')} + + + + , li:
  • }} + /> + + + + + + {t('pages.virtualContributorProfile.sections.privacy.title')} + + + + , li:
  • }} + /> + + + + + ); +}; + +export default VCProfilePageView; diff --git a/src/domain/community/virtualContributor/vcSettingsPage/VCSettingsPage.tsx b/src/domain/community/virtualContributor/vcSettingsPage/VCSettingsPage.tsx new file mode 100644 index 0000000000..3ab991493f --- /dev/null +++ b/src/domain/community/virtualContributor/vcSettingsPage/VCSettingsPage.tsx @@ -0,0 +1,83 @@ +import React from 'react'; +import Loading from '../../../../core/ui/loading/Loading'; +import { useUrlParams } from '../../../../core/routing/useUrlParams'; +import VCPageLayout from '../layout/VCPageLayout'; +import { + useBodyOfKnowledgeProfileQuery, + useUpdateVirtualContributorMutation, + useVirtualContributorQuery, +} from '../../../../core/apollo/generated/apollo-hooks'; +import VirtualContributorForm from './VirtualContributorForm'; +import PageContentColumn from '../../../../core/ui/content/PageContentColumn'; +import PageContentBlock from '../../../../core/ui/content/PageContentBlock'; +import PageContent from '../../../../core/ui/content/PageContent'; +import { useNotification } from '../../../../core/ui/notifications/useNotification'; +import { StorageConfigContextProvider } from '../../../storage/StorageBucket/StorageConfigContext'; +import { useTranslation } from 'react-i18next'; + +export const VCSettingsPage = () => { + const { t } = useTranslation(); + + const { vcNameId = '' } = useUrlParams(); + + const notify = useNotification(); + + const { data, loading } = useVirtualContributorQuery({ + variables: { + id: vcNameId, + }, + }); + + const { data: bokProfile } = useBodyOfKnowledgeProfileQuery({ + variables: { + spaceId: data?.virtualContributor.bodyOfKnowledgeID!, + }, + skip: !data?.virtualContributor.bodyOfKnowledgeID, + }); + + const [updateContributorMutation] = useUpdateVirtualContributorMutation(); + + const handleUpdate = virtualContributor => { + updateContributorMutation({ + variables: { + virtualContributorData: { + ID: virtualContributor.ID, + profileData: virtualContributor.profileData, + }, + }, + onCompleted: () => { + notify('Profile updated successfully', 'success'); + }, + }); + }; + + if (loading) + return ( + + ); + + return ( + + + + + + {data?.virtualContributor && ( + + )} + + + + + + ); +}; + +export default VCSettingsPage; diff --git a/src/domain/community/virtualContributor/vcSettingsPage/VirtualContributorForm.tsx b/src/domain/community/virtualContributor/vcSettingsPage/VirtualContributorForm.tsx new file mode 100644 index 0000000000..0fe38978a4 --- /dev/null +++ b/src/domain/community/virtualContributor/vcSettingsPage/VirtualContributorForm.tsx @@ -0,0 +1,212 @@ +import { Form, Formik } from 'formik'; +import React, { FC } from 'react'; +import { useTranslation } from 'react-i18next'; +import * as yup from 'yup'; +import { Box, Button } from '@mui/material'; +import { LoadingButton } from '@mui/lab'; +import { Tagset, UpdateVirtualContributorInput, Visual } from '../../../../core/apollo/generated/graphql-schema'; +import useNavigate from '../../../../core/routing/useNavigate'; +import { NameSegment, nameSegmentSchema } from '../../../platform/admin/components/Common/NameSegment'; +import { ProfileSegment, profileSegmentSchema } from '../../../platform/admin/components/Common/ProfileSegment'; +import VisualUpload from '../../../../core/ui/upload/VisualUpload/VisualUpload'; +import Gutters from '../../../../core/ui/grid/Gutters'; +import useLoadingState from '../../../shared/utils/useLoadingState'; +import { Actions } from '../../../../core/ui/actions/Actions'; +import { TagsetSegment } from '../../../platform/admin/components/Common/TagsetSegment'; +import { UpdateTagset } from '../../../common/profile/Profile'; +import FormikInputField from '../../../../core/ui/forms/FormikInputField/FormikInputField'; +import { theme } from '../../../../core/ui/themes/default/Theme'; +import GridContainer from '../../../../core/ui/grid/GridContainer'; +import GridProvider from '../../../../core/ui/grid/GridProvider'; +import GridItem from '../../../../core/ui/grid/GridItem'; +import { BasicSpaceProps } from '../components/BasicSpaceCard'; +import { useColumns } from '../../../../core/ui/grid/GridContext'; + +interface VirtualContributorProps { + id: string; + nameID: string; + account?: { + host?: { + profile: { + displayName: string; + }; + }; + }; + profile: { + id: string; + displayName: string; + description?: string; + tagline: string; + tagsets?: Tagset[] | undefined; + url: string; + avatar?: Visual | undefined; + }; +} + +interface VirtualContributorFromProps { + name: string; + nameID: string; + description: string; + tagline: string; + tagsets?: Tagset[]; + avatar: Visual | undefined; + hostDisplayName: string; + subSpaceName: string; +} + +interface Props { + virtualContributor: VirtualContributorProps; + bokProfile?: BasicSpaceProps; + avatar: Visual | undefined; + onSave?: (virtualContributor: UpdateVirtualContributorInput) => void; + title?: string; +} + +export const VirtualContributorForm: FC = ({ + virtualContributor: currentVirtualContributor, + bokProfile, + avatar, + onSave, +}) => { + const { t } = useTranslation(); + const navigate = useNavigate(); + const handleBack = () => navigate(-1); + const cols = useColumns(); + const isMobile = cols < 5; + + const { + nameID, + profile: { displayName, description, tagline, tagsets }, + account, + } = currentVirtualContributor; + const { displayName: subSpaceName } = bokProfile ?? {}; + + const initialValues: VirtualContributorFromProps = { + name: displayName, + nameID: nameID, + description: description ?? '', + tagline: tagline, + avatar: avatar, + tagsets: tagsets, + hostDisplayName: account?.host?.profile.displayName ?? '', + subSpaceName: subSpaceName ?? '', + }; + + const validationSchema = yup.object().shape({ + name: nameSegmentSchema.fields?.name ?? yup.string(), + nameID: nameSegmentSchema.fields?.nameID ?? yup.string(), + description: profileSegmentSchema.fields?.description ?? yup.string(), + }); + + const getUpdatedTagsets = (updatedTagsets: Tagset[]) => { + const result: UpdateTagset[] = []; + updatedTagsets.forEach(updatedTagset => { + const originalTagset = tagsets?.find(value => value.name === updatedTagset.name); + if (originalTagset) { + result.push({ ...originalTagset, tags: updatedTagset.tags }); + } + }); + + return result; + }; + + const [handleSubmit, loading] = useLoadingState(async (values: VirtualContributorFromProps) => { + const { tagsets, description, tagline, name, ...otherData } = values; + const updatedTagsets = getUpdatedTagsets(tagsets ?? []); + + const virtualContributor = { + ID: currentVirtualContributor.id, + profileData: { + displayName: name, + description, + tagline, + tagsets: updatedTagsets.map(r => ({ + ID: r.id, + tags: r.tags ?? [], + })), + }, + ...otherData, + }; + + await onSave?.(virtualContributor); + }); + + const backButton = ( + + ); + + const HostFields = () => ( + <> + + + + ); + + if (!currentVirtualContributor) { + return ( + <> +
    Virtual Contributor not found!
    + {backButton} + + ); + } else { + return ( + <> + + {({ values: { avatar, tagsets }, handleSubmit }) => { + return ( +
    + + + + {avatar && ( + + + + )} + + + + + + {tagsets && } + + + {backButton} + + {t('buttons.save')} + + + + + + +
    + ); + }} +
    + + ); + } +}; + +export default VirtualContributorForm; diff --git a/src/domain/journey/space/pages/SpaceAccount/SpaceAccountView.tsx b/src/domain/journey/space/pages/SpaceAccount/SpaceAccountView.tsx index 9741b21457..9f482e808c 100644 --- a/src/domain/journey/space/pages/SpaceAccount/SpaceAccountView.tsx +++ b/src/domain/journey/space/pages/SpaceAccount/SpaceAccountView.tsx @@ -1,7 +1,9 @@ import { FC, useMemo, useState } from 'react'; import { Trans, useTranslation } from 'react-i18next'; -import { useNavigate } from 'react-router-dom'; -import { Box, CircularProgress } from '@mui/material'; +import { Box, Button, CircularProgress } from '@mui/material'; +import ControlPointIcon from '@mui/icons-material/ControlPoint'; +import { v4 as uuidv4 } from 'uuid'; +import { buildSettingsUrl } from '../../../../../main/routing/urlBuilders'; import PageContent from '../../../../../core/ui/content/PageContent'; import PageContentBlock from '../../../../../core/ui/content/PageContentBlock'; import PageContentBlockHeader from '../../../../../core/ui/content/PageContentBlockHeader'; @@ -10,16 +12,25 @@ import { BlockTitle, Caption } from '../../../../../core/ui/typography'; import { useNotification } from '../../../../../core/ui/notifications/useNotification'; import ContributorCardHorizontal from '../../../../../core/ui/card/ContributorCardHorizontal'; import Gutters from '../../../../../core/ui/grid/Gutters'; -import { AuthorizationPrivilege } from '../../../../../core/apollo/generated/graphql-schema'; +import { AuthorizationPrivilege, BodyOfKnowledgeType } from '../../../../../core/apollo/generated/graphql-schema'; import { - refetchAdminSpacesListQuery, + useCreateVirtualContributorOnAccountMutation, useDeleteSpaceMutation, + refetchAdminSpacesListQuery, useSpaceAccountQuery, + useSpaceSubspacesQuery, + useDeleteVirtualContributorOnAccountMutation, + refetchSpaceSubspacesQuery, } from '../../../../../core/apollo/generated/apollo-hooks'; import { gutters } from '../../../../../core/ui/grid/utils'; import { ROUTE_HOME } from '../../../../platform/routes/constants'; import { DeleteIcon } from '../SpaceSettings/icon/DeleteIcon'; import SpaceProfileDeleteDialog from '../SpaceSettings/SpaceProfileDeleteDialog'; +import CreateVirtualContributorDialog, { + VirtualContributorFormValues, +} from '../SpaceSettings/CreateVirtualContributorDialog'; +import ContributorOnAccountCard from '../SpaceSettings/ContributorOnAccountCard'; +import useNavigate from '../../../../../core/routing/useNavigate'; import { PlanFeatures, PlanFooter, PlanName, PlanPrice } from '../../../../license/plans/ui/PlanCardsComponents'; import { getPlanTranslations } from '../../../../license/plans/utils/getPlanTranslations'; import RouterLink from '../../../../../core/ui/link/RouterLink'; @@ -39,6 +50,13 @@ const SpaceAccountView: FC = ({ journeyId }) => { const [openDeleteDialog, setOpenDeleteDialog] = useState(false); const openDialog = () => setOpenDeleteDialog(true); const closeDialog = () => setOpenDeleteDialog(false); + const [isCreateVCDialogOpen, setIsCreateVCDialogOpen] = useState(false); + const openCreateVCDialog = () => setIsCreateVCDialogOpen(true); + const closeCreateVCDialog = () => setIsCreateVCDialogOpen(false); + const [isOpenDeleteVCDialog, setIsOpenDeleteVCDialog] = useState(false); + const openDeleteVCDialog = () => setIsOpenDeleteVCDialog(true); + const closeDeleteVCDialog = () => setIsOpenDeleteVCDialog(false); + const { data, loading: loadingAccount } = useSpaceAccountQuery({ variables: { spaceId: journeyId }, }); @@ -110,6 +128,93 @@ const SpaceAccountView: FC = ({ journeyId }) => { }); }; + const [deleteVirtualContributor, { loading: deletingVirtualContributor }] = + useDeleteVirtualContributorOnAccountMutation({ + refetchQueries: [refetchSpaceSubspacesQuery({ spaceId: journeyId })], + awaitRefetchQueries: true, + }); + + const handleDeleteVC = async () => { + await deleteVirtualContributor({ + variables: { + virtualContributorData: { + ID: spaceData?.space?.account?.virtualContributors[0].nameID || '', + }, + }, + }); + + notify('Virtual Contribuotr deleted successfuly!', 'success'); + closeDeleteVCDialog(); + }; + + const { data: spaceData, loading: spaceDataLoading } = useSpaceSubspacesQuery({ + variables: { + spaceId: journeyId, + }, + skip: !journeyId, + }); + + const accountPrivileges = spaceData?.space?.account.authorization?.myPrivileges ?? []; + const canCreateVirtualContributor = accountPrivileges?.includes(AuthorizationPrivilege.CreateVirtualContributor); + + const subspaces = useMemo(() => { + const result = + spaceData?.space?.subspaces.map(subspace => ({ + id: subspace.id, + name: subspace?.profile.displayName, + })) ?? []; + + result.push({ + id: journeyId, + name: spaceData?.space?.profile.displayName || '', + }); + + return result; + }, [spaceData]); + + const bokSpaceData = useMemo( + () => + spaceData?.space?.subspaces + .filter(subspace => subspace.id === spaceData?.space?.account?.virtualContributors[0]?.bodyOfKnowledgeID) + .map(data => ({ profile: { displayName: data.profile.displayName } }))[0], + [spaceData] + ); + + const currentVirtualContributor = useMemo(() => { + if (spaceData?.space?.account?.id && spaceData?.space?.account?.virtualContributors) { + return spaceData?.space?.account?.virtualContributors[0]; + } + + return null; + }, [spaceData]); + + const [createVirtualContributorOnAccount, { loading: loadingVCCreation }] = + useCreateVirtualContributorOnAccountMutation({ + refetchQueries: [refetchSpaceSubspacesQuery({ spaceId: journeyId })], + awaitRefetchQueries: true, + }); + + const handleCreateVirtualContributor = async ({ displayName, bodyOfKnowledgeID }: VirtualContributorFormValues) => { + const vsResponse = await createVirtualContributorOnAccount({ + variables: { + virtualContributorData: { + // todo: guarantee uniqueness but use createNameId(displayName) + nameID: `v-c-${uuidv4()}`.slice(0, 25).toLocaleLowerCase(), + profileData: { + displayName, + }, + accountID: spaceData?.space.account.id ?? '', + bodyOfKnowledgeID, + bodyOfKnowledgeType: BodyOfKnowledgeType.Space, + }, + }, + }); + + notify('Virtual Contributor Created Successfully!', 'success'); + closeCreateVCDialog(); + navigate(buildSettingsUrl(vsResponse.data?.createVirtualContributor.profile.url ?? '')); + }; + const loading = loadingAccount && deletingSpace; return ( @@ -236,6 +341,29 @@ const SpaceAccountView: FC = ({ journeyId }) => { )} + + + {t('pages.admin.space.settings.account.vc-section-title')} + {currentVirtualContributor && ( + + )} + {canCreateVirtualContributor && ( + + )} + + {canDelete && ( @@ -254,6 +382,21 @@ const SpaceAccountView: FC = ({ journeyId }) => { submitting={deletingSpace} /> )} + + )} {loading && ( diff --git a/src/domain/journey/space/pages/SpaceSettings/ContributorOnAccountCard.tsx b/src/domain/journey/space/pages/SpaceSettings/ContributorOnAccountCard.tsx new file mode 100644 index 0000000000..47ad42cb23 --- /dev/null +++ b/src/domain/journey/space/pages/SpaceSettings/ContributorOnAccountCard.tsx @@ -0,0 +1,59 @@ +import { FC } from 'react'; +import IconButton from '@mui/material/IconButton'; +import BasicSpaceCard from '../../../../community/virtualContributor/components/BasicSpaceCard'; +import { DeleteIcon } from '../SpaceSettings/icon/DeleteIcon'; +import Gutters from '../../../../../core/ui/grid/Gutters'; + +interface ContributorOnAccountCardProps { + contributor?: { + profile: { + displayName: string; + url: string; + avatar?: { + uri: string; + }; + }; + }; + space?: { + profile: { + displayName: string; + avatar?: { + uri: string; + }; + }; + }; + hasDelete?: boolean; + onDeleteClick: () => void; +} + +const ContributorOnAccountCard: FC = ({ + contributor, + space, + hasDelete = false, + onDeleteClick, +}) => { + const spaceData = { + displayName: contributor?.profile.displayName ?? '', + url: contributor?.profile.url ? contributor?.profile.url : '', + avatar: { + uri: contributor?.profile.avatar?.uri ?? '', + }, + tagline: space?.profile.displayName ?? '', + }; + + return ( + + + {hasDelete && ( + + + + )} + + ); +}; + +export default ContributorOnAccountCard; diff --git a/src/domain/journey/space/pages/SpaceSettings/CreateVirtualContributorDialog.tsx b/src/domain/journey/space/pages/SpaceSettings/CreateVirtualContributorDialog.tsx new file mode 100644 index 0000000000..771be0d7e5 --- /dev/null +++ b/src/domain/journey/space/pages/SpaceSettings/CreateVirtualContributorDialog.tsx @@ -0,0 +1,91 @@ +import { FC } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Button, Dialog, DialogContent } from '@mui/material'; +import LoadingButton from '@mui/lab/LoadingButton'; +import * as yup from 'yup'; +import DialogHeader from '../../../../../core/ui/dialog/DialogHeader'; +import Gutters from '../../../../../core/ui/grid/Gutters'; +import { Actions } from '../../../../../core/ui/actions/Actions'; +import { gutters } from '../../../../../core/ui/grid/utils'; +import { Form, Formik } from 'formik'; +import FormikInputField from '../../../../../core/ui/forms/FormikInputField/FormikInputField'; +import FormikSelect from '../../../../../core/ui/forms/FormikSelect'; +import useLoadingState from '../../../../shared/utils/useLoadingState'; +import { Caption } from '../../../../../core/ui/typography'; +import { nameSegmentSchema } from '../../../../platform/admin/components/Common/NameSegment'; + +export interface VirtualContributorFormValues { + displayName: string; + bodyOfKnowledgeID: string; +} + +interface CreateVirtualContributorDialogProps { + spaces: { name: string; id: string }[]; + open: boolean; + onClose: () => void; + onCreate: ({ bodyOfKnowledgeID, displayName }) => void; + submitting: boolean; +} + +const CreateVirtualContributorDialog: FC = ({ + spaces, + open, + onClose, + onCreate, + submitting, +}) => { + const { t } = useTranslation(); + + const initialValues = { + displayName: '', + spaces: [], + bodyOfKnowledgeID: '', + }; + + const validationSchema = yup.object().shape({ + displayName: nameSegmentSchema.fields?.name ?? yup.string(), + bodyOfKnowledgeID: yup.string().required(t('forms.validations.required')), + }); + + const [handleCreate, loading] = useLoadingState(async (values: VirtualContributorFormValues) => { + await onCreate?.({ + ...values, + }); + }); + + return ( + + + + +
    + + + + {t('virtualContributorSpaceSettings.info-text')} + + + + {t('buttons.create')} + + + +
    +
    +
    +
    + ); +}; + +export default CreateVirtualContributorDialog; diff --git a/src/domain/journey/space/pages/SpaceSettings/SpaceProfileDeleteDialog.tsx b/src/domain/journey/space/pages/SpaceSettings/SpaceProfileDeleteDialog.tsx index 188514b3b0..e0ff44da79 100644 --- a/src/domain/journey/space/pages/SpaceSettings/SpaceProfileDeleteDialog.tsx +++ b/src/domain/journey/space/pages/SpaceSettings/SpaceProfileDeleteDialog.tsx @@ -7,9 +7,11 @@ import Gutters from '../../../../../core/ui/grid/Gutters'; import { Actions } from '../../../../../core/ui/actions/Actions'; import { Caption } from '../../../../../core/ui/typography'; import { gutters } from '../../../../../core/ui/grid/utils'; +import TranslationKey from '../../../../../core/i18n/utils/TranslationKey'; interface SpaceProfileDeleteDialogProps { entity: string; + description?: TranslationKey; open: boolean; onClose: () => void; onDelete: () => void; @@ -18,6 +20,7 @@ interface SpaceProfileDeleteDialogProps { const SpaceProfileDeleteDialog: FC = ({ entity, + description, open, onClose, onDelete, @@ -32,7 +35,9 @@ const SpaceProfileDeleteDialog: FC = ({ - {t('components.deleteSpace.confirmDialog.description', { entity: entity })} + + {t(description ?? 'components.deleteSpace.confirmDialog.description', { entity: entity })}{' '} + setChecked(!checked)} />} label={{t('components.deleteSpace.confirmDialog.checkbox', { entity: entity })}} diff --git a/src/domain/journey/space/pages/SpaceSettings/VirtualContributor.graphql b/src/domain/journey/space/pages/SpaceSettings/VirtualContributor.graphql new file mode 100644 index 0000000000..39440af497 --- /dev/null +++ b/src/domain/journey/space/pages/SpaceSettings/VirtualContributor.graphql @@ -0,0 +1,53 @@ +mutation CreateVirtualContributorOnAccount($virtualContributorData: CreateVirtualContributorOnAccountInput!) { + createVirtualContributor(virtualContributorData: $virtualContributorData) { + id + profile { + id + url + } + } +} + +mutation DeleteVirtualContributorOnAccount($virtualContributorData: DeleteVirtualContributorInput!) { + deleteVirtualContributor(deleteData: $virtualContributorData) { + id + } +} + +query SpaceSubspaces($spaceId: UUID_NAMEID!) { + space (ID: $spaceId) { + id + profile { + id + displayName + } + account { + id + authorization { + myPrivileges + } + virtualContributors { + id + nameID + bodyOfKnowledgeID + profile { + displayName + url + avatar: visual(type: AVATAR) { + uri + } + } + } + } + subspaces { + id + profile { + id + displayName + avatar: visual(type: AVATAR) { + uri + } + } + } + } +} \ No newline at end of file diff --git a/src/domain/platform/admin/virtual-contributors/NewVirtualContributorForm.tsx b/src/domain/platform/admin/virtual-contributors/NewVirtualContributorForm.tsx index 480a1d8a85..8e606948b1 100644 --- a/src/domain/platform/admin/virtual-contributors/NewVirtualContributorForm.tsx +++ b/src/domain/platform/admin/virtual-contributors/NewVirtualContributorForm.tsx @@ -20,11 +20,17 @@ import FormikSelect from '../../../../core/ui/forms/FormikSelect'; import { useBackToStaticPath } from '../../../../core/routing/useBackToPath'; import PageContentBlock from '../../../../core/ui/content/PageContentBlock'; import PageContentBlockHeader from '../../../../core/ui/content/PageContentBlockHeader'; +import { TagsetSegment } from '../components/Common/TagsetSegment'; +import { Tagset, TagsetType } from '../../../../core/apollo/generated/graphql-schema'; +import { DEFAULT_TAGSET } from '../../../common/tags/tagset.constants'; +import { SMALL_TEXT_LENGTH } from '../../../../core/ui/forms/field-length.constants'; import { BodyOfKnowledgeType } from '../../../../core/apollo/generated/graphql-schema'; interface NewVirtualContributorFormValues { displayName: string; virtualPersonaID: string; + tagline: string; + tagsets: Tagset[]; } interface NewVirtualContributorFormProps { @@ -35,7 +41,7 @@ const NewVirtualContributorForm = ({ parentPagePath }: NewVirtualContributorForm const { t } = useTranslation(); const navigateBack = useBackToStaticPath(parentPagePath); const notify = useNotification(); - const initialValues = { displayName: '', virtualPersonaID: '' }; + const initialValues = { displayName: '', virtualPersonaID: '', tagline: '', tagsets: [] }; const { data: virtualPersonas } = useVirtualContributorAvailablePersonasQuery(); const [createVirtualContributor, { loading }] = useCreateVirtualContributorMutation({ refetchQueries: [refetchAdminVirtualContributorsQuery()], @@ -46,7 +52,7 @@ const NewVirtualContributorForm = ({ parentPagePath }: NewVirtualContributorForm }; const [handleSubmit] = useLoadingState(async (values: NewVirtualContributorFormValues) => { - const { displayName, virtualPersonaID } = values; + const { displayName, virtualPersonaID, tagline, tagsets } = values; // TODO: fix accountID: '' & bodyOfKnowledgeID: '' in order to work await createVirtualContributor({ @@ -56,6 +62,13 @@ const NewVirtualContributorForm = ({ parentPagePath }: NewVirtualContributorForm nameID: `V-P-${uuidv4()}`.slice(0, 25).toLocaleLowerCase(), profileData: { displayName, + tagline, + tagsets: [ + { + ...tagsets[0], + name: DEFAULT_TAGSET, + }, + ], }, accountID: '', bodyOfKnowledgeID: '', @@ -77,6 +90,16 @@ const NewVirtualContributorForm = ({ parentPagePath }: NewVirtualContributorForm [virtualPersonas] ); + const tagsets = [ + { + id: '', + name: DEFAULT_TAGSET, + tags: [], + allowedValues: [], + type: TagsetType.Freeform, + }, + ] as Tagset[]; + return ( @@ -86,6 +109,13 @@ const NewVirtualContributorForm = ({ parentPagePath }: NewVirtualContributorForm + +