diff --git a/CHANGELOG.md b/CHANGELOG.md index bc344c05c..300ef7ebf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added - Added pictures in the dropdown list for engines +- Editing dataset readme file on Overview tab ## [0.7.0] - 2023-07-27 ### Added diff --git a/resources/schema.graphql b/resources/schema.graphql index c0351059d..c494c5eef 100644 --- a/resources/schema.graphql +++ b/resources/schema.graphql @@ -51,7 +51,7 @@ type AttachmentsEmbedded { items: [AttachmentEmbedded!]! } -type Auth { +type AuthMut { githubLogin(code: String!): LoginResponse! accountInfo(accessToken: String!): AccountInfo! } @@ -75,11 +75,11 @@ interface CommitResult { message: String! } -type CommitResultAppendError implements CommitResult { +type CommitResultAppendError implements CommitResult & UpdateReadmeResult { message: String! } -type CommitResultSuccess implements CommitResult { +type CommitResultSuccess implements CommitResult & UpdateReadmeResult { oldHead: Multihash newHead: Multihash! message: String! @@ -317,6 +317,24 @@ type DatasetMetadata { currentVocab: SetVocab } +type DatasetMetadataMut { + """ + Access to the mutable metadata chain of the dataset + """ + chain: MetadataChainMut! + """ + Updates or clears the dataset readme + """ + updateReadme(content: String): UpdateReadmeResult! +} + +type DatasetMut { + """ + Access to the mutable metadata of the dataset + """ + metadata: DatasetMetadataMut! +} + scalar DatasetName scalar DatasetRefAny @@ -346,6 +364,13 @@ type Datasets { page: Int perPage: Int ): DatasetConnection! +} + +type DatasetsMut { + """ + Returns a mutable dataset by its ID + """ + byId(datasetId: DatasetID!): DatasetMut """ Creates a new empty dataset """ @@ -519,6 +544,9 @@ type MetadataChain { Iterates all metadata blocks in the reverse chronological order """ blocks(page: Int, perPage: Int): MetadataBlockConnection! +} + +type MetadataChainMut { """ Commits new event to the metadata chain """ @@ -555,8 +583,28 @@ type MetadataManifestUnsupportedVersion implements CommitResult & CreateDatasetF scalar Multihash type Mutation { - auth: Auth! - tasks: TasksMutations! + """ + Authentication and authorization-related functionality group + """ + auth: AuthMut! + """ + Dataset-related functionality group. + + Datasets are historical streams of events recorded under a cetrain + schema. + """ + datasets: DatasetsMut! + """ + Tasks-related functionality group. + + Tasks are units of work scheduled and executed by the system to query + and process data. + """ + tasks: TasksMut! +} + +type NoChanges implements CommitResult & UpdateReadmeResult { + message: String! } type OffsetInterval { @@ -910,7 +958,7 @@ type Tasks { ): TaskConnection! } -type TasksMutations { +type TasksMut { """ Requests cancellation of the specified task """ @@ -952,6 +1000,10 @@ type TransformSql { temporalTables: [TemporalTable!] } +interface UpdateReadmeResult { + message: String! +} + type User implements Account { """ Unique and stable identitfier of this user account diff --git a/src/app/api/dataset.api.spec.ts b/src/app/api/dataset.api.spec.ts index 60a926428..b08c8c281 100644 --- a/src/app/api/dataset.api.spec.ts +++ b/src/app/api/dataset.api.spec.ts @@ -19,7 +19,7 @@ import { import { DatasetApi } from "./dataset.api"; import { CommitEventToDatasetDocument, - CommitEventToDatasetQuery, + CommitEventToDatasetMutation, DatasetsByAccountNameDocument, DatasetsByAccountNameQuery, GetDatasetDataSqlRunDocument, @@ -188,22 +188,25 @@ describe("DatasetApi", () => { }); it("should commit event", () => { + const mockDatasetId = "mockId"; + const mockEvent = "mock event"; service .commitEvent({ - accountName: TEST_USER_NAME, - datasetName: TEST_DATASET_NAME, - event: "mock event", + datasetId: mockDatasetId, + event: mockEvent, }) - .subscribe((res: CommitEventToDatasetQuery) => { - expect( - res.datasets.byOwnerAndName?.metadata.chain.commitEvent - .__typename, - ).toEqual("CommitResultSuccess"); - }); + .subscribe( + (res: CommitEventToDatasetMutation | null | undefined) => { + expect( + res?.datasets.byId?.metadata.chain.commitEvent + .__typename, + ).toEqual("CommitResultSuccess"); + }, + ); const op = controller.expectOne(CommitEventToDatasetDocument); - expect(op.operation.variables.accountName).toEqual(TEST_USER_NAME); - expect(op.operation.variables.datasetName).toEqual(TEST_DATASET_NAME); + expect(op.operation.variables.datasetId).toEqual(mockDatasetId); + expect(op.operation.variables.event).toEqual(mockEvent); op.flush({ data: mockCommitEventResponse, }); diff --git a/src/app/api/dataset.api.ts b/src/app/api/dataset.api.ts index 8e67e7704..e4f99d2e3 100644 --- a/src/app/api/dataset.api.ts +++ b/src/app/api/dataset.api.ts @@ -1,12 +1,16 @@ import { CommitEventToDatasetGQL, - CommitEventToDatasetQuery, + CommitEventToDatasetMutation, CreateDatasetFromSnapshotGQL, - CreateDatasetFromSnapshotQuery, - CreateEmptyDatasetQuery, + CreateDatasetFromSnapshotMutation, + CreateEmptyDatasetMutation, + DatasetByAccountAndDatasetNameGQL, + DatasetByAccountAndDatasetNameQuery, DatasetKind, GetDatasetSchemaGQL, GetDatasetSchemaQuery, + UpdateReadmeGQL, + UpdateReadmeMutation, } from "src/app/api/kamu.graphql.interface"; import AppValues from "src/app/common/app.values"; import { ApolloQueryResult } from "@apollo/client/core"; @@ -30,6 +34,7 @@ import { DatasetByIdGQL, CreateEmptyDatasetGQL, } from "./kamu.graphql.interface"; +import { MutationResult } from "apollo-angular"; @Injectable({ providedIn: "root" }) export class DatasetApi { @@ -40,10 +45,12 @@ export class DatasetApi { private datasetsByAccountNameGQL: DatasetsByAccountNameGQL, private metadataBlockGQL: GetMetadataBlockGQL, private datasetByIdGQL: DatasetByIdGQL, + private datasetByAccountAndDatasetNameGQL: DatasetByAccountAndDatasetNameGQL, private createEmptyDatasetGQL: CreateEmptyDatasetGQL, private createDatasetFromSnapshotGQL: CreateDatasetFromSnapshotGQL, - private commitEventToDataset: CommitEventToDatasetGQL, + private commitEventToDatasetGQL: CommitEventToDatasetGQL, private datasetSchemaGQL: GetDatasetSchemaGQL, + private updateReadmeGQL: UpdateReadmeGQL, ) {} public getDatasetMainData(params: { @@ -52,11 +59,17 @@ export class DatasetApi { numRecords?: number; }): Observable { return this.datasetMainDataGQL - .watch({ - accountName: params.accountName, - datasetName: params.datasetName, - limit: params.numRecords ?? AppValues.SQL_QUERY_LIMIT, - }) + .watch( + { + accountName: params.accountName, + datasetName: params.datasetName, + limit: params.numRecords ?? AppValues.SQL_QUERY_LIMIT, + }, + { + fetchPolicy: "network-only", + errorPolicy: "all", + }, + ) .valueChanges.pipe( first(), map((result: ApolloQueryResult) => { @@ -162,17 +175,38 @@ export class DatasetApi { ); } + public getDatasetInfoByAccountAndDatasetName( + accountName: string, + datasetName: string, + ): Observable { + return this.datasetByAccountAndDatasetNameGQL + .watch({ + accountName, + datasetName, + }) + .valueChanges.pipe( + first(), + map( + ( + result: ApolloQueryResult, + ) => { + return result.data; + }, + ), + ); + } + public createDatasetFromSnapshot( accountId: string, snapshot: string, - ): Observable { + ): Observable { return this.createDatasetFromSnapshotGQL - .watch({ accountId, snapshot }) - .valueChanges.pipe( + .mutate({ accountId, snapshot }) + .pipe( first(), map( ( - result: ApolloQueryResult, + result: MutationResult, ) => { return result.data; }, @@ -184,31 +218,46 @@ export class DatasetApi { accountId: string, datasetKind: DatasetKind, datasetName: string, - ): Observable { + ): Observable { return this.createEmptyDatasetGQL - .watch({ accountId, datasetKind, datasetName }) - .valueChanges.pipe( + .mutate({ accountId, datasetKind, datasetName }) + .pipe( first(), - map((result: ApolloQueryResult) => { + map((result: MutationResult) => { return result.data; }), ); } public commitEvent(params: { - accountName: string; - datasetName: string; + datasetId: string; event: string; - }): Observable { - return this.commitEventToDataset - .watch({ - accountName: params.accountName, - datasetName: params.datasetName, + }): Observable { + return this.commitEventToDatasetGQL + .mutate({ + datasetId: params.datasetId, event: params.event, }) - .valueChanges.pipe( + .pipe( + first(), + map((result: MutationResult) => { + return result.data; + }), + ); + } + + public updateReadme( + datasetId: string, + content: string, + ): Observable { + return this.updateReadmeGQL + .mutate({ + datasetId, + content, + }) + .pipe( first(), - map((result: ApolloQueryResult) => { + map((result: MutationResult) => { return result.data; }), ); diff --git a/src/app/api/gql/create-dataset/commit-event.graphql b/src/app/api/gql/create-dataset/commit-event.graphql index 913c70027..ecae479ba 100644 --- a/src/app/api/gql/create-dataset/commit-event.graphql +++ b/src/app/api/gql/create-dataset/commit-event.graphql @@ -1,10 +1,6 @@ -query commitEventToDataset( - $accountName: AccountName! - $datasetName: DatasetName! - $event: String! -) { +mutation commitEventToDataset($datasetId: DatasetID!, $event: String!) { datasets { - byOwnerAndName(accountName: $accountName, datasetName: $datasetName) { + byId(datasetId: $datasetId) { metadata { chain { commitEvent(event: $event, eventFormat: YAML) { diff --git a/src/app/api/gql/create-dataset/create-empty-dataset.graphql b/src/app/api/gql/create-dataset/create-empty-dataset.graphql index ca148b55a..451f26892 100644 --- a/src/app/api/gql/create-dataset/create-empty-dataset.graphql +++ b/src/app/api/gql/create-dataset/create-empty-dataset.graphql @@ -1,4 +1,4 @@ -query createEmptyDataset( +mutation createEmptyDataset( $accountId: AccountID! $datasetKind: DatasetKind! $datasetName: DatasetName! diff --git a/src/app/api/gql/create-dataset/create-from-snapshot.graphql b/src/app/api/gql/create-dataset/create-from-snapshot.graphql index ed2891c68..dfa041cb0 100644 --- a/src/app/api/gql/create-dataset/create-from-snapshot.graphql +++ b/src/app/api/gql/create-dataset/create-from-snapshot.graphql @@ -1,4 +1,4 @@ -query createDatasetFromSnapshot($accountId: AccountID!, $snapshot: String!) { +mutation createDatasetFromSnapshot($accountId: AccountID!, $snapshot: String!) { datasets { createFromSnapshot( accountId: $accountId diff --git a/src/app/api/gql/create-dataset/update-readme.graphql b/src/app/api/gql/create-dataset/update-readme.graphql new file mode 100644 index 000000000..4e4d9b685 --- /dev/null +++ b/src/app/api/gql/create-dataset/update-readme.graphql @@ -0,0 +1,15 @@ +mutation updateReadme($datasetId: DatasetID!, $content: String!) { + datasets { + byId(datasetId: $datasetId) { + metadata { + updateReadme(content: $content) { + __typename + message + ... on CommitResultSuccess { + oldHead + } + } + } + } + } +} diff --git a/src/app/api/gql/dataset-by-account-and-dataset-name.graphql b/src/app/api/gql/dataset-by-account-and-dataset-name.graphql new file mode 100644 index 000000000..6b066ab32 --- /dev/null +++ b/src/app/api/gql/dataset-by-account-and-dataset-name.graphql @@ -0,0 +1,10 @@ +query datasetByAccountAndDatasetName( + $accountName: AccountName! + $datasetName: DatasetName! +) { + datasets { + byOwnerAndName(accountName: $accountName, datasetName: $datasetName) { + ...DatasetBasics + } + } +} diff --git a/src/app/api/kamu.graphql.interface.ts b/src/app/api/kamu.graphql.interface.ts index 68dbcd762..45057e2bc 100644 --- a/src/app/api/kamu.graphql.interface.ts +++ b/src/app/api/kamu.graphql.interface.ts @@ -94,17 +94,17 @@ export type AttachmentsEmbedded = { items: Array; }; -export type Auth = { - __typename?: "Auth"; +export type AuthMut = { + __typename?: "AuthMut"; accountInfo: AccountInfo; githubLogin: LoginResponse; }; -export type AuthAccountInfoArgs = { +export type AuthMutAccountInfoArgs = { accessToken: Scalars["String"]; }; -export type AuthGithubLoginArgs = { +export type AuthMutGithubLoginArgs = { code: Scalars["String"]; }; @@ -130,17 +130,19 @@ export type CommitResult = { message: Scalars["String"]; }; -export type CommitResultAppendError = CommitResult & { - __typename?: "CommitResultAppendError"; - message: Scalars["String"]; -}; +export type CommitResultAppendError = CommitResult & + UpdateReadmeResult & { + __typename?: "CommitResultAppendError"; + message: Scalars["String"]; + }; -export type CommitResultSuccess = CommitResult & { - __typename?: "CommitResultSuccess"; - message: Scalars["String"]; - newHead: Scalars["Multihash"]; - oldHead?: Maybe; -}; +export type CommitResultSuccess = CommitResult & + UpdateReadmeResult & { + __typename?: "CommitResultSuccess"; + message: Scalars["String"]; + newHead: Scalars["Multihash"]; + oldHead?: Maybe; + }; export enum CompressionFormat { Gzip = "GZIP", @@ -353,6 +355,24 @@ export type DatasetMetadataCurrentSchemaArgs = { format?: InputMaybe; }; +export type DatasetMetadataMut = { + __typename?: "DatasetMetadataMut"; + /** Access to the mutable metadata chain of the dataset */ + chain: MetadataChainMut; + /** Updates or clears the dataset readme */ + updateReadme: UpdateReadmeResult; +}; + +export type DatasetMetadataMutUpdateReadmeArgs = { + content?: InputMaybe; +}; + +export type DatasetMut = { + __typename?: "DatasetMut"; + /** Access to the mutable metadata of the dataset */ + metadata: DatasetMetadataMut; +}; + export type Datasets = { __typename?: "Datasets"; /** Returns datasets belonging to the specified account */ @@ -363,10 +383,6 @@ export type Datasets = { byId?: Maybe; /** Returns dataset by its owner and name */ byOwnerAndName?: Maybe; - /** Creates a new empty dataset */ - createEmpty: CreateDatasetResult; - /** Creates a new dataset from provided DatasetSnapshot manifest */ - createFromSnapshot: CreateDatasetFromSnapshotResult; }; export type DatasetsByAccountIdArgs = { @@ -390,13 +406,27 @@ export type DatasetsByOwnerAndNameArgs = { datasetName: Scalars["DatasetName"]; }; -export type DatasetsCreateEmptyArgs = { +export type DatasetsMut = { + __typename?: "DatasetsMut"; + /** Returns a mutable dataset by its ID */ + byId?: Maybe; + /** Creates a new empty dataset */ + createEmpty: CreateDatasetResult; + /** Creates a new dataset from provided DatasetSnapshot manifest */ + createFromSnapshot: CreateDatasetFromSnapshotResult; +}; + +export type DatasetsMutByIdArgs = { + datasetId: Scalars["DatasetID"]; +}; + +export type DatasetsMutCreateEmptyArgs = { accountId: Scalars["AccountID"]; datasetKind: DatasetKind; datasetName: Scalars["DatasetName"]; }; -export type DatasetsCreateFromSnapshotArgs = { +export type DatasetsMutCreateFromSnapshotArgs = { accountId: Scalars["AccountID"]; snapshot: Scalars["String"]; snapshotFormat: MetadataManifestFormat; @@ -553,8 +583,6 @@ export type MetadataChain = { blockByHashEncoded?: Maybe; /** Iterates all metadata blocks in the reverse chronological order */ blocks: MetadataBlockConnection; - /** Commits new event to the metadata chain */ - commitEvent: CommitResult; /** Returns all named metadata block references */ refs: Array; }; @@ -573,7 +601,13 @@ export type MetadataChainBlocksArgs = { perPage?: InputMaybe; }; -export type MetadataChainCommitEventArgs = { +export type MetadataChainMut = { + __typename?: "MetadataChainMut"; + /** Commits new event to the metadata chain */ + commitEvent: CommitResult; +}; + +export type MetadataChainMutCommitEventArgs = { event: Scalars["String"]; eventFormat: MetadataManifestFormat; }; @@ -608,10 +642,30 @@ export type MetadataManifestUnsupportedVersion = CommitResult & export type Mutation = { __typename?: "Mutation"; - auth: Auth; - tasks: TasksMutations; + /** Authentication and authorization-related functionality group */ + auth: AuthMut; + /** + * Dataset-related functionality group. + * + * Datasets are historical streams of events recorded under a cetrain + * schema. + */ + datasets: DatasetsMut; + /** + * Tasks-related functionality group. + * + * Tasks are units of work scheduled and executed by the system to query + * and process data. + */ + tasks: TasksMut; }; +export type NoChanges = CommitResult & + UpdateReadmeResult & { + __typename?: "NoChanges"; + message: Scalars["String"]; + }; + export type OffsetInterval = { __typename?: "OffsetInterval"; end: Scalars["Int"]; @@ -941,8 +995,8 @@ export type TasksListTasksByDatasetArgs = { perPage?: InputMaybe; }; -export type TasksMutations = { - __typename?: "TasksMutations"; +export type TasksMut = { + __typename?: "TasksMut"; /** Requests cancellation of the specified task */ cancelTask: Task; /** @@ -957,17 +1011,17 @@ export type TasksMutations = { createUpdateDatasetTask: Task; }; -export type TasksMutationsCancelTaskArgs = { +export type TasksMutCancelTaskArgs = { taskId: Scalars["TaskID"]; }; -export type TasksMutationsCreateProbeTaskArgs = { +export type TasksMutCreateProbeTaskArgs = { busyTimeMs?: InputMaybe; datasetId?: InputMaybe; endWithOutcome?: InputMaybe; }; -export type TasksMutationsCreateUpdateDatasetTaskArgs = { +export type TasksMutCreateUpdateDatasetTaskArgs = { datasetId: Scalars["DatasetID"]; }; @@ -995,6 +1049,10 @@ export type TransformSql = { version?: Maybe; }; +export type UpdateReadmeResult = { + message: Scalars["String"]; +}; + export type User = Account & { __typename?: "User"; /** Unique and stable identitfier of this user account */ @@ -1003,22 +1061,21 @@ export type User = Account & { name: Scalars["String"]; }; -export type CommitEventToDatasetQueryVariables = Exact<{ - accountName: Scalars["AccountName"]; - datasetName: Scalars["DatasetName"]; +export type CommitEventToDatasetMutationVariables = Exact<{ + datasetId: Scalars["DatasetID"]; event: Scalars["String"]; }>; -export type CommitEventToDatasetQuery = { - __typename?: "Query"; +export type CommitEventToDatasetMutation = { + __typename?: "Mutation"; datasets: { - __typename?: "Datasets"; - byOwnerAndName?: { - __typename?: "Dataset"; + __typename?: "DatasetsMut"; + byId?: { + __typename?: "DatasetMut"; metadata: { - __typename?: "DatasetMetadata"; + __typename?: "DatasetMetadataMut"; chain: { - __typename?: "MetadataChain"; + __typename?: "MetadataChainMut"; commitEvent: | { __typename: "CommitResultAppendError"; @@ -1034,23 +1091,24 @@ export type CommitEventToDatasetQuery = { __typename: "MetadataManifestMalformed"; message: string; } - | { __typename: "MetadataManifestUnsupportedVersion" }; + | { __typename: "MetadataManifestUnsupportedVersion" } + | { __typename: "NoChanges" }; }; }; } | null; }; }; -export type CreateEmptyDatasetQueryVariables = Exact<{ +export type CreateEmptyDatasetMutationVariables = Exact<{ accountId: Scalars["AccountID"]; datasetKind: DatasetKind; datasetName: Scalars["DatasetName"]; }>; -export type CreateEmptyDatasetQuery = { - __typename?: "Query"; +export type CreateEmptyDatasetMutation = { + __typename?: "Mutation"; datasets: { - __typename?: "Datasets"; + __typename?: "DatasetsMut"; createEmpty: | { __typename?: "CreateDatasetResultNameCollision"; @@ -1060,15 +1118,15 @@ export type CreateEmptyDatasetQuery = { }; }; -export type CreateDatasetFromSnapshotQueryVariables = Exact<{ +export type CreateDatasetFromSnapshotMutationVariables = Exact<{ accountId: Scalars["AccountID"]; snapshot: Scalars["String"]; }>; -export type CreateDatasetFromSnapshotQuery = { - __typename?: "Query"; +export type CreateDatasetFromSnapshotMutation = { + __typename?: "Mutation"; datasets: { - __typename?: "Datasets"; + __typename?: "DatasetsMut"; createFromSnapshot: | { __typename?: "CreateDatasetResultInvalidSnapshot"; @@ -1095,6 +1153,47 @@ export type CreateDatasetFromSnapshotQuery = { }; }; +export type UpdateReadmeMutationVariables = Exact<{ + datasetId: Scalars["DatasetID"]; + content: Scalars["String"]; +}>; + +export type UpdateReadmeMutation = { + __typename?: "Mutation"; + datasets: { + __typename?: "DatasetsMut"; + byId?: { + __typename?: "DatasetMut"; + metadata: { + __typename?: "DatasetMetadataMut"; + updateReadme: + | { __typename: "CommitResultAppendError"; message: string } + | { + __typename: "CommitResultSuccess"; + oldHead?: any | null; + message: string; + } + | { __typename: "NoChanges"; message: string }; + }; + } | null; + }; +}; + +export type DatasetByAccountAndDatasetNameQueryVariables = Exact<{ + accountName: Scalars["AccountName"]; + datasetName: Scalars["DatasetName"]; +}>; + +export type DatasetByAccountAndDatasetNameQuery = { + __typename?: "Query"; + datasets: { + __typename?: "Datasets"; + byOwnerAndName?: + | ({ __typename?: "Dataset" } & DatasetBasicsFragment) + | null; + }; +}; + export type DatasetByIdQueryVariables = Exact<{ datasetId: Scalars["DatasetID"]; }>; @@ -1790,7 +1889,7 @@ export type GithubLoginMutationVariables = Exact<{ export type GithubLoginMutation = { __typename?: "Mutation"; auth: { - __typename?: "Auth"; + __typename?: "AuthMut"; githubLogin: { __typename?: "LoginResponse"; token: { @@ -1813,7 +1912,7 @@ export type FetchAccountInfoMutationVariables = Exact<{ export type FetchAccountInfoMutation = { __typename?: "Mutation"; auth: { - __typename?: "Auth"; + __typename?: "AuthMut"; accountInfo: { __typename?: "AccountInfo" } & AccountDetailsFragment; }; }; @@ -2441,16 +2540,9 @@ export const DatasetSearchOverviewFragmentDoc = gql` ${LicenseFragmentDoc} `; export const CommitEventToDatasetDocument = gql` - query commitEventToDataset( - $accountName: AccountName! - $datasetName: DatasetName! - $event: String! - ) { + mutation commitEventToDataset($datasetId: DatasetID!, $event: String!) { datasets { - byOwnerAndName( - accountName: $accountName - datasetName: $datasetName - ) { + byId(datasetId: $datasetId) { metadata { chain { commitEvent(event: $event, eventFormat: YAML) { @@ -2477,9 +2569,9 @@ export const CommitEventToDatasetDocument = gql` @Injectable({ providedIn: "root", }) -export class CommitEventToDatasetGQL extends Apollo.Query< - CommitEventToDatasetQuery, - CommitEventToDatasetQueryVariables +export class CommitEventToDatasetGQL extends Apollo.Mutation< + CommitEventToDatasetMutation, + CommitEventToDatasetMutationVariables > { document = CommitEventToDatasetDocument; @@ -2488,7 +2580,7 @@ export class CommitEventToDatasetGQL extends Apollo.Query< } } export const CreateEmptyDatasetDocument = gql` - query createEmptyDataset( + mutation createEmptyDataset( $accountId: AccountID! $datasetKind: DatasetKind! $datasetName: DatasetName! @@ -2508,9 +2600,9 @@ export const CreateEmptyDatasetDocument = gql` @Injectable({ providedIn: "root", }) -export class CreateEmptyDatasetGQL extends Apollo.Query< - CreateEmptyDatasetQuery, - CreateEmptyDatasetQueryVariables +export class CreateEmptyDatasetGQL extends Apollo.Mutation< + CreateEmptyDatasetMutation, + CreateEmptyDatasetMutationVariables > { document = CreateEmptyDatasetDocument; @@ -2519,7 +2611,7 @@ export class CreateEmptyDatasetGQL extends Apollo.Query< } } export const CreateDatasetFromSnapshotDocument = gql` - query createDatasetFromSnapshot( + mutation createDatasetFromSnapshot( $accountId: AccountID! $snapshot: String! ) { @@ -2544,9 +2636,9 @@ export const CreateDatasetFromSnapshotDocument = gql` @Injectable({ providedIn: "root", }) -export class CreateDatasetFromSnapshotGQL extends Apollo.Query< - CreateDatasetFromSnapshotQuery, - CreateDatasetFromSnapshotQueryVariables +export class CreateDatasetFromSnapshotGQL extends Apollo.Mutation< + CreateDatasetFromSnapshotMutation, + CreateDatasetFromSnapshotMutationVariables > { document = CreateDatasetFromSnapshotDocument; @@ -2554,6 +2646,67 @@ export class CreateDatasetFromSnapshotGQL extends Apollo.Query< super(apollo); } } +export const UpdateReadmeDocument = gql` + mutation updateReadme($datasetId: DatasetID!, $content: String!) { + datasets { + byId(datasetId: $datasetId) { + metadata { + updateReadme(content: $content) { + __typename + message + ... on CommitResultSuccess { + oldHead + } + } + } + } + } + } +`; + +@Injectable({ + providedIn: "root", +}) +export class UpdateReadmeGQL extends Apollo.Mutation< + UpdateReadmeMutation, + UpdateReadmeMutationVariables +> { + document = UpdateReadmeDocument; + + constructor(apollo: Apollo.Apollo) { + super(apollo); + } +} +export const DatasetByAccountAndDatasetNameDocument = gql` + query datasetByAccountAndDatasetName( + $accountName: AccountName! + $datasetName: DatasetName! + ) { + datasets { + byOwnerAndName( + accountName: $accountName + datasetName: $datasetName + ) { + ...DatasetBasics + } + } + } + ${DatasetBasicsFragmentDoc} +`; + +@Injectable({ + providedIn: "root", +}) +export class DatasetByAccountAndDatasetNameGQL extends Apollo.Query< + DatasetByAccountAndDatasetNameQuery, + DatasetByAccountAndDatasetNameQueryVariables +> { + document = DatasetByAccountAndDatasetNameDocument; + + constructor(apollo: Apollo.Apollo) { + super(apollo); + } +} export const DatasetByIdDocument = gql` query datasetById($datasetId: DatasetID!) { datasets { diff --git a/src/app/api/mock/auth.mock.ts b/src/app/api/mock/auth.mock.ts index 8a84cad85..5450bf1dd 100644 --- a/src/app/api/mock/auth.mock.ts +++ b/src/app/api/mock/auth.mock.ts @@ -19,14 +19,14 @@ export const mockAccountDetails: AccountDetailsFragment = { export const mockUserInfoFromAccessToken: FetchAccountInfoMutation = { auth: { - __typename: "Auth", + __typename: "AuthMut", accountInfo: mockAccountDetails, }, }; export const mockGithubLoginResponse: GithubLoginMutation = { auth: { - __typename: "Auth", + __typename: "AuthMut", githubLogin: { __typename: "LoginResponse", token: { diff --git a/src/app/dataset-create/dataset-create.service.spec.ts b/src/app/dataset-create/dataset-create.service.spec.ts index a0e5a964f..cbc3071c5 100644 --- a/src/app/dataset-create/dataset-create.service.spec.ts +++ b/src/app/dataset-create/dataset-create.service.spec.ts @@ -1,4 +1,7 @@ -import { CreateDatasetFromSnapshotQuery } from "./../api/kamu.graphql.interface"; +import { + CreateDatasetFromSnapshotMutation, + CreateEmptyDatasetMutation, +} from "./../api/kamu.graphql.interface"; import { mockDatasetBasicsFragment, mockDatasetInfo, @@ -7,10 +10,7 @@ import { TestBed } from "@angular/core/testing"; import { Apollo } from "apollo-angular"; import { of } from "rxjs"; import { DatasetApi } from "../api/dataset.api"; -import { - CreateEmptyDatasetQuery, - DatasetKind, -} from "../api/kamu.graphql.interface"; +import { DatasetKind } from "../api/kamu.graphql.interface"; import { DatasetViewTypeEnum } from "../dataset-view/dataset-view.interface"; import { NavigationService } from "../services/navigation.service"; import { AppDatasetCreateService } from "./dataset-create.service"; @@ -34,7 +34,7 @@ describe("AppDatasetCreateService", () => { }); it("should be create empty dataset with success", () => { - const mockResponseSuccess: CreateEmptyDatasetQuery = { + const mockResponseSuccess: CreateEmptyDatasetMutation = { datasets: { createEmpty: { message: "Success", @@ -66,7 +66,7 @@ describe("AppDatasetCreateService", () => { }); it("should be create empty dataset with error", () => { - const mockResponseError: CreateEmptyDatasetQuery = { + const mockResponseError: CreateEmptyDatasetMutation = { datasets: { createEmpty: { message: "Fail", @@ -101,7 +101,7 @@ describe("AppDatasetCreateService", () => { }); it("should be create dataset using shapshot with success", () => { - const mockResponseSuccess: CreateDatasetFromSnapshotQuery = { + const mockResponseSuccess: CreateDatasetFromSnapshotMutation = { datasets: { createFromSnapshot: { message: "Success", @@ -135,7 +135,7 @@ describe("AppDatasetCreateService", () => { }); it("should be create dataset using shapshot with error", () => { - const mockResponseError: CreateDatasetFromSnapshotQuery = { + const mockResponseError: CreateDatasetFromSnapshotMutation = { datasets: { createFromSnapshot: { message: "Fail", diff --git a/src/app/dataset-create/dataset-create.service.ts b/src/app/dataset-create/dataset-create.service.ts index 9376a6aed..74cf9290d 100644 --- a/src/app/dataset-create/dataset-create.service.ts +++ b/src/app/dataset-create/dataset-create.service.ts @@ -1,7 +1,6 @@ import { - CommitEventToDatasetQuery, - CreateDatasetFromSnapshotQuery, - CreateEmptyDatasetQuery, + CreateDatasetFromSnapshotMutation, + CreateEmptyDatasetMutation, } from "./../api/kamu.graphql.interface"; import { Observable, Subject } from "rxjs"; import { DatasetApi } from "src/app/api/dataset.api"; @@ -10,7 +9,6 @@ import { DatasetKind } from "../api/kamu.graphql.interface"; import { map } from "rxjs/operators"; import { NavigationService } from "../services/navigation.service"; import { DatasetViewTypeEnum } from "../dataset-view/dataset-view.interface"; -import { DatasetService } from "../dataset-view/dataset.service"; @Injectable({ providedIn: "root" }) export class AppDatasetCreateService { @@ -24,20 +22,9 @@ export class AppDatasetCreateService { return this.errorMessageChanges$.asObservable(); } - private errorCommitEventChanges$: Subject = new Subject(); - - public errorCommitEventChanges(message: string): void { - this.errorCommitEventChanges$.next(message); - } - - public get onErrorCommitEventChanges(): Observable { - return this.errorCommitEventChanges$.asObservable(); - } - public constructor( private datasetApi: DatasetApi, private navigationService: NavigationService, - private datasetService: DatasetService, ) {} public createEmptyDataset( @@ -48,9 +35,9 @@ export class AppDatasetCreateService { return this.datasetApi .createEmptyDataset(accountId, datasetKind, datasetName) .pipe( - map((data: CreateEmptyDatasetQuery) => { + map((data: CreateEmptyDatasetMutation | null | undefined) => { if ( - data.datasets.createEmpty.__typename === + data?.datasets.createEmpty.__typename === "CreateDatasetResultSuccess" ) { this.navigationService.navigateToDatasetView({ @@ -59,9 +46,10 @@ export class AppDatasetCreateService { tab: DatasetViewTypeEnum.Overview, }); } else { - this.errorMessageChanges( - data.datasets.createEmpty.message, - ); + if (data) + this.errorMessageChanges( + data.datasets.createEmpty.message, + ); } }), ); @@ -74,60 +62,32 @@ export class AppDatasetCreateService { return this.datasetApi .createDatasetFromSnapshot(accountId, snapshot) .pipe( - map((data: CreateDatasetFromSnapshotQuery) => { - if ( - data.datasets.createFromSnapshot.__typename === - "CreateDatasetResultSuccess" - ) { - const datasetName = data.datasets.createFromSnapshot - .dataset.name as string; - this.navigationService.navigateToDatasetView({ - accountName: accountId, - datasetName, - tab: DatasetViewTypeEnum.Overview, - }); - } else { - this.errorMessageChanges( - data.datasets.createFromSnapshot.message, - ); - } - }), - ); - } - - public commitEventToDataset( - accountName: string, - datasetName: string, - event: string, - ): Observable { - return this.datasetApi - .commitEvent({ accountName, datasetName, event }) - .pipe( - map((data: CommitEventToDatasetQuery) => { - if ( - data.datasets.byOwnerAndName?.metadata.chain.commitEvent - .__typename === "CommitResultAppendError" || - data.datasets.byOwnerAndName?.metadata.chain.commitEvent - .__typename === "MetadataManifestMalformed" - ) { - this.errorCommitEventChanges( - data.datasets.byOwnerAndName.metadata.chain - .commitEvent.message, - ); - } else { - this.datasetService - .requestDatasetMainData({ - accountName, + map( + ( + data: + | CreateDatasetFromSnapshotMutation + | null + | undefined, + ) => { + if ( + data?.datasets.createFromSnapshot.__typename === + "CreateDatasetResultSuccess" + ) { + const datasetName = data.datasets.createFromSnapshot + .dataset.name as string; + this.navigationService.navigateToDatasetView({ + accountName: accountId, datasetName, - }) - .subscribe(); - this.navigationService.navigateToDatasetView({ - accountName, - datasetName, - tab: DatasetViewTypeEnum.Overview, - }); - } - }), + tab: DatasetViewTypeEnum.Overview, + }); + } else { + if (data) + this.errorMessageChanges( + data.datasets.createFromSnapshot.message, + ); + } + }, + ), ); } } diff --git a/src/app/dataset-view/additional-components/data-tabs.mock.ts b/src/app/dataset-view/additional-components/data-tabs.mock.ts index 175f56070..632a7244f 100644 --- a/src/app/dataset-view/additional-components/data-tabs.mock.ts +++ b/src/app/dataset-view/additional-components/data-tabs.mock.ts @@ -4,7 +4,11 @@ import { DataSqlErrorUpdate, DataUpdate, } from "../dataset.subscriptions.interface"; -import { DatasetKind } from "src/app/api/kamu.graphql.interface"; +import { + CommitEventToDatasetMutation, + DatasetKind, + UpdateReadmeMutation, +} from "src/app/api/kamu.graphql.interface"; export const mockDataUpdate: DataUpdate = { schema: { @@ -814,3 +818,66 @@ export const mockOverviewWithSetLicense = { createdAt: "2022-08-05T21:10:57.332924745+00:00", lastUpdatedAt: "2022-08-05T21:15:03.947245004+00:00", }; + +export const mockCommitEventToDatasetMutationErrorMessage = "Fail"; + +export const mockCommitEventToDatasetMutationError: CommitEventToDatasetMutation = + { + datasets: { + byId: { + metadata: { + chain: { + commitEvent: { + __typename: "CommitResultAppendError", + message: + mockCommitEventToDatasetMutationErrorMessage, + }, + __typename: "MetadataChainMut", + }, + __typename: "DatasetMetadataMut", + }, + __typename: "DatasetMut", + }, + __typename: "DatasetsMut", + }, + }; + +export const mockCommitEventToDatasetMutation: CommitEventToDatasetMutation = { + datasets: { + byId: { + metadata: { + chain: { + commitEvent: { + __typename: "CommitResultSuccess", + message: "Success", + oldHead: + "zW1cMmaF6PdmJPM6LNyy2RyyWFWkF3EojZ54ezAvT2dVgKB", + newHead: + "zW1eXXAXqgtfNDFt7oXpMfLfDy5Tzg3dMDLWQTz2YJE6ooX", + }, + __typename: "MetadataChainMut", + }, + __typename: "DatasetMetadataMut", + }, + __typename: "DatasetMut", + }, + __typename: "DatasetsMut", + }, +}; + +export const mockUpdateReadmeMutation: UpdateReadmeMutation = { + datasets: { + byId: { + metadata: { + updateReadme: { + __typename: "CommitResultSuccess", + message: "Success", + oldHead: "zW1oSh19bxPZqLhY9awS7cnFrmQUueZ5MF21wVf8poHDnaX", + }, + __typename: "DatasetMetadataMut", + }, + __typename: "DatasetMut", + }, + __typename: "DatasetsMut", + }, +}; diff --git a/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.spec.ts b/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.spec.ts index 23b9a433b..2e322878c 100644 --- a/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.spec.ts +++ b/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.spec.ts @@ -13,7 +13,6 @@ import { ComponentFixture, TestBed } from "@angular/core/testing"; import { AddPollingSourceComponent } from "./add-polling-source.component"; import { NgbModal, NgbModalRef, NgbModule } from "@ng-bootstrap/ng-bootstrap"; import { FinalYamlModalComponent } from "../final-yaml-modal/final-yaml-modal.component"; -import { AppDatasetCreateService } from "src/app/dataset-create/dataset-create.service"; import { SetPollingSourceSection } from "src/app/shared/shared.types"; import { MonacoEditorModule } from "ngx-monaco-editor"; import { StepperNavigationComponent } from "../stepper-navigation/stepper-navigation.component"; @@ -28,13 +27,14 @@ import { } from "src/app/api/kamu.graphql.interface"; import { EditPollingSourceService } from "./edit-polling-source.service"; import { SharedTestModule } from "src/app/common/shared-test.module"; +import { DatasetCommitService } from "../../../overview-component/services/dataset-commit.service"; describe("AddPollingSourceComponent", () => { let component: AddPollingSourceComponent; let fixture: ComponentFixture; let modalService: NgbModal; let modalRef: NgbModalRef; - let createDatasetService: AppDatasetCreateService; + let datasetCommitService: DatasetCommitService; let editService: EditPollingSourceService; beforeEach(async () => { @@ -64,7 +64,7 @@ describe("AddPollingSourceComponent", () => { modalService = TestBed.inject(NgbModal); editService = TestBed.inject(EditPollingSourceService); - createDatasetService = TestBed.inject(AppDatasetCreateService); + datasetCommitService = TestBed.inject(DatasetCommitService); modalRef = modalService.open(FinalYamlModalComponent); component = fixture.componentInstance; component.showPreprocessStep = false; @@ -120,7 +120,7 @@ describe("AddPollingSourceComponent", () => { const mockError = "Some error"; expect(component.errorMessage).toBe(""); expect(component.changedEventYamlByHash).toBeUndefined(); - createDatasetService.errorCommitEventChanges(mockError); + datasetCommitService.errorCommitEventChanges(mockError); expect(component.errorMessage).toBe(mockError); component.onEditYaml(); @@ -145,7 +145,7 @@ describe("AddPollingSourceComponent", () => { it("should check submit yaml", () => { component.ngOnInit(); const submitYamlSpy = spyOn( - createDatasetService, + datasetCommitService, "commitEventToDataset", ).and.returnValue(of()); component.onSaveEvent(); @@ -166,7 +166,7 @@ describe("AddPollingSourceComponent", () => { const errorMessage = "test error message"; expect(component.errorMessage).toBe(""); - createDatasetService.errorCommitEventChanges(errorMessage); + datasetCommitService.errorCommitEventChanges(errorMessage); expect(component.errorMessage).toBe(errorMessage); }); diff --git a/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.ts b/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.ts index e73ae82d8..a3a2c0ecd 100644 --- a/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.ts +++ b/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.ts @@ -137,7 +137,7 @@ export class AddPollingSourceComponent public onSaveEvent(): void { this.processFormService.transformForm(this.pollingSourceForm); this.trackSubscription( - this.createDatasetService + this.datasetCommitService .commitEventToDataset( this.getDatasetInfoFromUrl().accountName, this.getDatasetInfoFromUrl().datasetName, diff --git a/src/app/dataset-view/additional-components/metadata-component/components/base-main-event.component.ts b/src/app/dataset-view/additional-components/metadata-component/components/base-main-event.component.ts index 00d7f59be..b2d2773f3 100644 --- a/src/app/dataset-view/additional-components/metadata-component/components/base-main-event.component.ts +++ b/src/app/dataset-view/additional-components/metadata-component/components/base-main-event.component.ts @@ -3,13 +3,13 @@ import { NgbModal } from "@ng-bootstrap/ng-bootstrap"; import { DatasetKind } from "src/app/api/kamu.graphql.interface"; import { MaybeNull } from "src/app/common/app.types"; import { BaseComponent } from "src/app/common/base.component"; -import { AppDatasetCreateService } from "src/app/dataset-create/dataset-create.service"; import { DatasetHistoryUpdate } from "src/app/dataset-view/dataset.subscriptions.interface"; import { TemplatesYamlEventsService } from "src/app/services/templates-yaml-events.service"; +import { DatasetCommitService } from "../../overview-component/services/dataset-commit.service"; export abstract class BaseMainEventComponent extends BaseComponent { public modalService = inject(NgbModal); - public createDatasetService = inject(AppDatasetCreateService); + public datasetCommitService = inject(DatasetCommitService); public cdr = inject(ChangeDetectorRef); public yamlEventService = inject(TemplatesYamlEventsService); @@ -21,7 +21,7 @@ export abstract class BaseMainEventComponent extends BaseComponent { protected subsribeErrorMessage(): void { this.trackSubscription( - this.createDatasetService.onErrorCommitEventChanges.subscribe( + this.datasetCommitService.onErrorCommitEventChanges.subscribe( (message: string) => { this.errorMessage = message; this.cdr.detectChanges(); diff --git a/src/app/dataset-view/additional-components/metadata-component/components/final-yaml-modal/final-yaml-modal.component.spec.ts b/src/app/dataset-view/additional-components/metadata-component/components/final-yaml-modal/final-yaml-modal.component.spec.ts index 5300e2fec..eaf797b0c 100644 --- a/src/app/dataset-view/additional-components/metadata-component/components/final-yaml-modal/final-yaml-modal.component.spec.ts +++ b/src/app/dataset-view/additional-components/metadata-component/components/final-yaml-modal/final-yaml-modal.component.spec.ts @@ -2,13 +2,13 @@ import { ComponentFixture, TestBed } from "@angular/core/testing"; import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap"; import { ApolloModule } from "apollo-angular"; import { FinalYamlModalComponent } from "./final-yaml-modal.component"; -import { AppDatasetCreateService } from "src/app/dataset-create/dataset-create.service"; import { emitClickOnElementByDataTestId } from "src/app/common/base-test.helpers.spec"; import { DatasetInfo } from "src/app/interface/navigation.interface"; import { of } from "rxjs"; import { FormsModule } from "@angular/forms"; import { MonacoEditorModule } from "ngx-monaco-editor"; import { SharedTestModule } from "src/app/common/shared-test.module"; +import { DatasetCommitService } from "../../../overview-component/services/dataset-commit.service"; const testDatasetInfo: DatasetInfo = { accountName: "testAccountName", @@ -18,7 +18,7 @@ const testDatasetInfo: DatasetInfo = { describe("FinalYamlModalComponent", () => { let component: FinalYamlModalComponent; let fixture: ComponentFixture; - let createDatasetService: AppDatasetCreateService; + let datasetCommitService: DatasetCommitService; let activeModal: NgbActiveModal; beforeEach(async () => { @@ -34,7 +34,7 @@ describe("FinalYamlModalComponent", () => { }).compileComponents(); fixture = TestBed.createComponent(FinalYamlModalComponent); - createDatasetService = TestBed.inject(AppDatasetCreateService); + datasetCommitService = TestBed.inject(DatasetCommitService); activeModal = TestBed.inject(NgbActiveModal); component = fixture.componentInstance; component.yamlTemplate = "test yaml"; @@ -48,7 +48,7 @@ describe("FinalYamlModalComponent", () => { it("should save event", () => { const commitEventToDatasetSpy = spyOn( - createDatasetService, + datasetCommitService, "commitEventToDataset", ).and.returnValue(of()); const closeModalSpy = spyOn(activeModal, "close"); diff --git a/src/app/dataset-view/additional-components/metadata-component/components/final-yaml-modal/final-yaml-modal.component.ts b/src/app/dataset-view/additional-components/metadata-component/components/final-yaml-modal/final-yaml-modal.component.ts index cb6dbf8b9..b21122a00 100644 --- a/src/app/dataset-view/additional-components/metadata-component/components/final-yaml-modal/final-yaml-modal.component.ts +++ b/src/app/dataset-view/additional-components/metadata-component/components/final-yaml-modal/final-yaml-modal.component.ts @@ -2,10 +2,8 @@ import { BaseComponent } from "src/app/common/base.component"; import { ChangeDetectionStrategy, Component, Input } from "@angular/core"; import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap"; import * as monaco from "monaco-editor"; - -import { AppDatasetCreateService } from "src/app/dataset-create/dataset-create.service"; - import { DatasetInfo } from "src/app/interface/navigation.interface"; +import { DatasetCommitService } from "../../../overview-component/services/dataset-commit.service"; @Component({ selector: "app-final-yaml-modal", @@ -30,14 +28,14 @@ export class FinalYamlModalComponent extends BaseComponent { constructor( public activeModal: NgbActiveModal, - private createDatasetService: AppDatasetCreateService, + private datasetCommitService: DatasetCommitService, ) { super(); } public saveEvent(): void { this.trackSubscription( - this.createDatasetService + this.datasetCommitService .commitEventToDataset( this.datasetInfo.accountName, this.datasetInfo.datasetName, diff --git a/src/app/dataset-view/additional-components/metadata-component/components/set-transform/components/engine-section/components/engine-select/engine-select.component.ts b/src/app/dataset-view/additional-components/metadata-component/components/set-transform/components/engine-section/components/engine-select/engine-select.component.ts index d10aad548..11ab9a94c 100644 --- a/src/app/dataset-view/additional-components/metadata-component/components/set-transform/components/engine-section/components/engine-select/engine-select.component.ts +++ b/src/app/dataset-view/additional-components/metadata-component/components/set-transform/components/engine-section/components/engine-select/engine-select.component.ts @@ -49,7 +49,10 @@ export class EngineSelectComponent implements OnInit { } } public get value(): string { - return DataHelpers.descriptionForEngine(this.engine).label ?? ""; + return ( + DataHelpers.descriptionForEngine(this.engine.toLowerCase()).label ?? + "" + ); } public getLogo(name: string): EventPropertyLogo { diff --git a/src/app/dataset-view/additional-components/metadata-component/components/set-transform/set-transform.component.spec.ts b/src/app/dataset-view/additional-components/metadata-component/components/set-transform/set-transform.component.spec.ts index 052439354..8a6a1b0a5 100644 --- a/src/app/dataset-view/additional-components/metadata-component/components/set-transform/set-transform.component.spec.ts +++ b/src/app/dataset-view/additional-components/metadata-component/components/set-transform/set-transform.component.spec.ts @@ -5,7 +5,6 @@ import { ActivatedRoute } from "@angular/router"; import { ApolloTestingModule } from "apollo-angular/testing"; import { EditSetTransformService } from "./edit-set-transform..service"; import { DatasetKind } from "src/app/api/kamu.graphql.interface"; -import { AppDatasetCreateService } from "src/app/dataset-create/dataset-create.service"; import { of } from "rxjs"; import { NgbModal, NgbModalRef } from "@ng-bootstrap/ng-bootstrap"; import { FinalYamlModalComponent } from "../final-yaml-modal/final-yaml-modal.component"; @@ -19,12 +18,13 @@ import { import { DatasetService } from "src/app/dataset-view/dataset.service"; import { MatTreeNestedDataSource } from "@angular/material/tree"; import { DatasetNode } from "./set-transform.types"; +import { DatasetCommitService } from "../../../overview-component/services/dataset-commit.service"; describe("SetTransformComponent", () => { let component: SetTransformComponent; let fixture: ComponentFixture; let editService: EditSetTransformService; - let createDatasetService: AppDatasetCreateService; + let datasetCommitService: DatasetCommitService; let modalService: NgbModal; let modalRef: NgbModalRef; let datasetService: DatasetService; @@ -70,7 +70,7 @@ describe("SetTransformComponent", () => { modalService = TestBed.inject(NgbModal); modalRef = modalService.open(FinalYamlModalComponent); editService = TestBed.inject(EditSetTransformService); - createDatasetService = TestBed.inject(AppDatasetCreateService); + datasetCommitService = TestBed.inject(DatasetCommitService); datasetService = TestBed.inject(DatasetService); fixture.detectChanges(); }); @@ -88,7 +88,7 @@ describe("SetTransformComponent", () => { it("should check save event", () => { const commitEventToDatasetSpy = spyOn( - createDatasetService, + datasetCommitService, "commitEventToDataset", ).and.returnValue(of()); component.onSaveEvent(); diff --git a/src/app/dataset-view/additional-components/metadata-component/components/set-transform/set-transform.component.ts b/src/app/dataset-view/additional-components/metadata-component/components/set-transform/set-transform.component.ts index d920dcdb8..6ee769f0b 100644 --- a/src/app/dataset-view/additional-components/metadata-component/components/set-transform/set-transform.component.ts +++ b/src/app/dataset-view/additional-components/metadata-component/components/set-transform/set-transform.component.ts @@ -162,7 +162,7 @@ export class SetTransformComponent public onSaveEvent(): void { this.trackSubscription( - this.createDatasetService + this.datasetCommitService .commitEventToDataset( this.getDatasetInfoFromUrl().accountName, this.getDatasetInfoFromUrl().datasetName, diff --git a/src/app/dataset-view/additional-components/metadata-component/metadata.component.html b/src/app/dataset-view/additional-components/metadata-component/metadata.component.html index 9ae6e43fd..bd38a9029 100644 --- a/src/app/dataset-view/additional-components/metadata-component/metadata.component.html +++ b/src/app/dataset-view/additional-components/metadata-component/metadata.component.html @@ -519,8 +519,10 @@

There is no metadata.

" >

- There is no metadata. Need add - SetTransform event + There is no metadata. Need to add + + SetTransform event

diff --git a/src/app/dataset-view/additional-components/overview-component/components/edit-details-modal/edit-details-modal.component.ts b/src/app/dataset-view/additional-components/overview-component/components/edit-details-modal/edit-details-modal.component.ts index 2a6dfa33d..031e2fae1 100644 --- a/src/app/dataset-view/additional-components/overview-component/components/edit-details-modal/edit-details-modal.component.ts +++ b/src/app/dataset-view/additional-components/overview-component/components/edit-details-modal/edit-details-modal.component.ts @@ -9,9 +9,9 @@ import { } from "src/app/api/kamu.graphql.interface"; import { MaybeNull } from "src/app/common/app.types"; import { BaseComponent } from "src/app/common/base.component"; -import { AppDatasetCreateService } from "src/app/dataset-create/dataset-create.service"; import { DatasetSchema, DataRow } from "src/app/interface/dataset.interface"; import { TemplatesYamlEventsService } from "src/app/services/templates-yaml-events.service"; +import { DatasetCommitService } from "../../services/dataset-commit.service"; @Component({ selector: "app-details-modal", @@ -31,7 +31,7 @@ export class EditDetailsModalComponent extends BaseComponent implements OnInit { public initialDescription = ""; public initialKeywords: string[] = []; constructor( - private createDatasetService: AppDatasetCreateService, + private datasetCommitService: DatasetCommitService, private yamlEventService: TemplatesYamlEventsService, public activeModal: NgbActiveModal, ) { @@ -74,7 +74,7 @@ export class EditDetailsModalComponent extends BaseComponent implements OnInit { public commitSetInfoEvent(): void { if (this.datasetBasics) this.trackSubscription( - this.createDatasetService + this.datasetCommitService .commitEventToDataset( this.datasetBasics.owner.name, this.datasetBasics.name as string, diff --git a/src/app/dataset-view/additional-components/overview-component/components/edit-license-modal/edit-license-modal.component.ts b/src/app/dataset-view/additional-components/overview-component/components/edit-license-modal/edit-license-modal.component.ts index 39995200a..483cdad0e 100644 --- a/src/app/dataset-view/additional-components/overview-component/components/edit-license-modal/edit-license-modal.component.ts +++ b/src/app/dataset-view/additional-components/overview-component/components/edit-license-modal/edit-license-modal.component.ts @@ -12,8 +12,8 @@ import { } from "src/app/api/kamu.graphql.interface"; import { MaybeNull } from "src/app/common/app.types"; import { DatasetSchema, DataRow } from "src/app/interface/dataset.interface"; -import { AppDatasetCreateService } from "src/app/dataset-create/dataset-create.service"; import { TemplatesYamlEventsService } from "src/app/services/templates-yaml-events.service"; +import { DatasetCommitService } from "../../services/dataset-commit.service"; @Component({ selector: "app-edit-license-modal", @@ -41,7 +41,7 @@ export class EditLicenseModalComponent extends BaseComponent implements OnInit { constructor( public activeModal: NgbActiveModal, private fb: FormBuilder, - private createDatasetService: AppDatasetCreateService, + private datasetCommitService: DatasetCommitService, private yamlEventService: TemplatesYamlEventsService, ) { super(); @@ -63,7 +63,7 @@ export class EditLicenseModalComponent extends BaseComponent implements OnInit { public onEditLicense(): void { if (this.datasetBasics) this.trackSubscription( - this.createDatasetService + this.datasetCommitService .commitEventToDataset( this.datasetBasics.owner.name, this.datasetBasics.name as string, diff --git a/src/app/dataset-view/additional-components/overview-component/components/edit-watermark-modal/edit-watermark-modal.component.spec.ts b/src/app/dataset-view/additional-components/overview-component/components/edit-watermark-modal/edit-watermark-modal.component.spec.ts index b66c59ca0..23d3f9772 100644 --- a/src/app/dataset-view/additional-components/overview-component/components/edit-watermark-modal/edit-watermark-modal.component.spec.ts +++ b/src/app/dataset-view/additional-components/overview-component/components/edit-watermark-modal/edit-watermark-modal.component.spec.ts @@ -13,14 +13,14 @@ import { FormsModule } from "@angular/forms"; import timekeeper from "timekeeper"; import { mockDatasetBasicsFragment } from "src/app/search/mock.data"; import { emitClickOnElementByDataTestId } from "src/app/common/base-test.helpers.spec"; -import { AppDatasetCreateService } from "src/app/dataset-create/dataset-create.service"; import { of } from "rxjs"; import { SharedTestModule } from "src/app/common/shared-test.module"; +import { DatasetCommitService } from "../../services/dataset-commit.service"; describe("EditWatermarkModalComponent", () => { let component: EditWatermarkModalComponent; let fixture: ComponentFixture; - let appDatasetCreateService: AppDatasetCreateService; + let datasetCommitService: DatasetCommitService; const FROZEN_TIME = new Date("2022-10-01 12:00:00"); beforeEach(async () => { @@ -40,7 +40,7 @@ describe("EditWatermarkModalComponent", () => { fixture = TestBed.createComponent(EditWatermarkModalComponent); component = fixture.componentInstance; - appDatasetCreateService = TestBed.inject(AppDatasetCreateService); + datasetCommitService = TestBed.inject(DatasetCommitService); component.datasetBasics = mockDatasetBasicsFragment; }); @@ -71,7 +71,7 @@ describe("EditWatermarkModalComponent", () => { component, "commitSetWatermarkEvent", ).and.callThrough(); - spyOn(appDatasetCreateService, "commitEventToDataset").and.returnValue( + spyOn(datasetCommitService, "commitEventToDataset").and.returnValue( of(), ); emitClickOnElementByDataTestId(fixture, "commit-setWatermark-event"); diff --git a/src/app/dataset-view/additional-components/overview-component/components/edit-watermark-modal/edit-watermark-modal.component.ts b/src/app/dataset-view/additional-components/overview-component/components/edit-watermark-modal/edit-watermark-modal.component.ts index c89dc3c3b..1c61c2e7c 100644 --- a/src/app/dataset-view/additional-components/overview-component/components/edit-watermark-modal/edit-watermark-modal.component.ts +++ b/src/app/dataset-view/additional-components/overview-component/components/edit-watermark-modal/edit-watermark-modal.component.ts @@ -11,8 +11,8 @@ import moment from "moment-timezone"; import { DatasetBasicsFragment } from "src/app/api/kamu.graphql.interface"; import { BaseComponent } from "src/app/common/base.component"; import { MY_MOMENT_FORMATS } from "src/app/common/data.helpers"; -import { AppDatasetCreateService } from "src/app/dataset-create/dataset-create.service"; import { TemplatesYamlEventsService } from "src/app/services/templates-yaml-events.service"; +import { DatasetCommitService } from "../../services/dataset-commit.service"; @Component({ selector: "app-edit-watermark-modal", @@ -35,7 +35,7 @@ export class EditWatermarkModalComponent constructor( public activeModal: NgbActiveModal, private yamlEventService: TemplatesYamlEventsService, - private createDatasetService: AppDatasetCreateService, + private datasetCommitService: DatasetCommitService, ) { super(); } @@ -73,7 +73,7 @@ export class EditWatermarkModalComponent const date = moment.utc(this.date).tz(this.timeZone).format(); if (this.datasetBasics) { this.trackSubscription( - this.createDatasetService + this.datasetCommitService .commitEventToDataset( this.datasetBasics.owner.name, this.datasetBasics.name as string, diff --git a/src/app/dataset-view/additional-components/overview-component/components/readme-section/readme-section.component.html b/src/app/dataset-view/additional-components/overview-component/components/readme-section/readme-section.component.html new file mode 100644 index 000000000..a850750b4 --- /dev/null +++ b/src/app/dataset-view/additional-components/overview-component/components/readme-section/readme-section.component.html @@ -0,0 +1,82 @@ +
+
+
+ + + +

+ README.md +

+
+ +
+
+
+ + +
+
+ + +
+
+
+ + + + + + +
+
diff --git a/src/app/dataset-view/additional-components/overview-component/components/readme-section/readme-section.component.sass b/src/app/dataset-view/additional-components/overview-component/components/readme-section/readme-section.component.sass new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/dataset-view/additional-components/overview-component/components/readme-section/readme-section.component.spec.ts b/src/app/dataset-view/additional-components/overview-component/components/readme-section/readme-section.component.spec.ts new file mode 100644 index 000000000..554428f08 --- /dev/null +++ b/src/app/dataset-view/additional-components/overview-component/components/readme-section/readme-section.component.spec.ts @@ -0,0 +1,105 @@ +import { + ComponentFixture, + TestBed, + fakeAsync, + tick, +} from "@angular/core/testing"; +import { ReadmeSectionComponent } from "./readme-section.component"; +import { mockDatasetBasicsFragment } from "src/app/search/mock.data"; +import { Apollo, ApolloModule } from "apollo-angular"; +import { ApolloTestingModule } from "apollo-angular/testing"; +import { SharedTestModule } from "src/app/common/shared-test.module"; +import { DatasetCommitService } from "../../services/dataset-commit.service"; +import { SecurityContext } from "@angular/core"; +import { HttpClient } from "@angular/common/http"; +import { HttpClientTestingModule } from "@angular/common/http/testing"; +import { FormsModule } from "@angular/forms"; +import { AngularSvgIconModule } from "angular-svg-icon"; +import { MarkdownModule } from "ngx-markdown"; +import { emitClickOnElementByDataTestId } from "src/app/common/base-test.helpers.spec"; +import { EditMode } from "./readme-section.types"; +import { of } from "rxjs"; + +describe("ReadmeSectionComponent", () => { + let component: ReadmeSectionComponent; + let fixture: ComponentFixture; + let datasetCommitService: DatasetCommitService; + + const mockReadmeContent = "Mock README.md content"; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + providers: [Apollo], + declarations: [ReadmeSectionComponent], + imports: [ + ApolloModule, + ApolloTestingModule, + SharedTestModule, + MarkdownModule.forRoot({ + loader: HttpClient, + sanitize: SecurityContext.NONE, + }), + AngularSvgIconModule.forRoot(), + HttpClientTestingModule, + FormsModule, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(ReadmeSectionComponent); + component = fixture.componentInstance; + datasetCommitService = TestBed.inject(DatasetCommitService); + component.datasetBasics = mockDatasetBasicsFragment; + component.currentReadme = mockReadmeContent; + + fixture.detectChanges(); + }); + + it("should create", () => { + expect(component).toBeTruthy(); + }); + + it("should check show select tab", () => { + expect(component.editViewShow).toEqual(false); + emitClickOnElementByDataTestId(fixture, "show-edit-tabs"); + fixture.detectChanges(); + expect(component.editViewShow).toEqual(true); + }); + + it("should check switch edit/preview mode", () => { + emitClickOnElementByDataTestId(fixture, "show-edit-tabs"); + fixture.detectChanges(); + expect(component.viewMode).toEqual(EditMode.Edit); + emitClickOnElementByDataTestId(fixture, "select-preview-tab"); + expect(component.viewMode).toEqual(EditMode.Preview); + emitClickOnElementByDataTestId(fixture, "select-edit-tab"); + expect(component.viewMode).toEqual(EditMode.Edit); + }); + + it("should check push button 'cancel changes' when currentReadme exist", () => { + emitClickOnElementByDataTestId(fixture, "show-edit-tabs"); + fixture.detectChanges(); + emitClickOnElementByDataTestId(fixture, "cancel-changes"); + expect(component.readmeState).toEqual(mockReadmeContent); + }); + + it("should check push button 'cancel changes' when currentReadme is not exist", () => { + component.currentReadme = null; + emitClickOnElementByDataTestId(fixture, "show-edit-tabs"); + fixture.detectChanges(); + emitClickOnElementByDataTestId(fixture, "cancel-changes"); + expect(component.readmeState).toEqual(""); + }); + + it("should check save changes", fakeAsync(() => { + component.readmeState = mockReadmeContent + "modified"; + const updateReadmeSpy = spyOn( + datasetCommitService, + "updateReadme", + ).and.returnValue(of()); + emitClickOnElementByDataTestId(fixture, "show-edit-tabs"); + fixture.detectChanges(); + emitClickOnElementByDataTestId(fixture, "save-changes"); + tick(); + expect(updateReadmeSpy).toHaveBeenCalledTimes(1); + })); +}); diff --git a/src/app/dataset-view/additional-components/overview-component/components/readme-section/readme-section.component.ts b/src/app/dataset-view/additional-components/overview-component/components/readme-section/readme-section.component.ts new file mode 100644 index 000000000..e4fef5d80 --- /dev/null +++ b/src/app/dataset-view/additional-components/overview-component/components/readme-section/readme-section.component.ts @@ -0,0 +1,86 @@ +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + OnInit, + Output, +} from "@angular/core"; +import { DatasetBasicsFragment } from "src/app/api/kamu.graphql.interface"; +import { MaybeNull } from "src/app/common/app.types"; +import { BaseComponent } from "src/app/common/base.component"; +import { EditMode } from "./readme-section.types"; +import { DatasetCommitService } from "../../services/dataset-commit.service"; + +@Component({ + selector: "app-readme-section", + templateUrl: "./readme-section.component.html", + styleUrls: ["./readme-section.component.sass"], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ReadmeSectionComponent extends BaseComponent implements OnInit { + @Input() public datasetBasics?: DatasetBasicsFragment; + @Input() public currentReadme?: MaybeNull; + public editMode: typeof EditMode = EditMode; + public viewMode = EditMode.Edit; + public readmeState = ""; + @Input() public editViewShow = false; + @Output() public editViewShowEmmiter = new EventEmitter(); + + public get readmeChanged(): boolean { + return this.currentReadme !== this.readmeState; + } + + constructor(private datasetCommitService: DatasetCommitService) { + super(); + } + + ngOnInit(): void { + if (this.currentReadme) { + this.readmeState = this.currentReadme; + } + } + + public get isEditView(): boolean { + return this.viewMode === EditMode.Edit; + } + + public get isPreviewView(): boolean { + return this.viewMode === EditMode.Preview; + } + + public selectMode(mode: EditMode): void { + this.viewMode = mode; + } + + public showEditTabs(): void { + this.editViewShow = !this.editViewShow; + this.editViewShowEmmiter.emit(this.editViewShow); + } + + public onCancelChanges(): void { + this.readmeState = this.currentReadme ?? ""; + this.reset(); + } + + public saveChanges(): void { + if (this.datasetBasics) + this.trackSubscription( + this.datasetCommitService + .updateReadme( + this.datasetBasics.owner.name, + this.datasetBasics.name as string, + this.readmeState, + ) + .subscribe(() => { + this.reset(); + }), + ); + } + + private reset(): void { + this.viewMode = EditMode.Edit; + this.editViewShow = false; + this.editViewShowEmmiter.emit(this.editViewShow); + } +} diff --git a/src/app/dataset-view/additional-components/overview-component/components/readme-section/readme-section.types.ts b/src/app/dataset-view/additional-components/overview-component/components/readme-section/readme-section.types.ts new file mode 100644 index 000000000..8b2e8472a --- /dev/null +++ b/src/app/dataset-view/additional-components/overview-component/components/readme-section/readme-section.types.ts @@ -0,0 +1,4 @@ +export enum EditMode { + Edit = "edit", + Preview = "preview", +} diff --git a/src/app/dataset-view/additional-components/overview-component/overview-component.html b/src/app/dataset-view/additional-components/overview-component/overview-component.html index 63a7a3934..ff7620575 100644 --- a/src/app/dataset-view/additional-components/overview-component/overview-component.html +++ b/src/app/dataset-view/additional-components/overview-component/overview-component.html @@ -123,52 +123,26 @@

-
-
+ You can + - - - -

- README.md -

-
- -
-
- - - - - - -
+

+
diff --git a/src/app/dataset-view/additional-components/overview-component/overview-component.sass b/src/app/dataset-view/additional-components/overview-component/overview-component.sass index 1df6e550c..1178a2342 100644 --- a/src/app/dataset-view/additional-components/overview-component/overview-component.sass +++ b/src/app/dataset-view/additional-components/overview-component/overview-component.sass @@ -11,3 +11,41 @@ .no-data-container background-color: rgba(97,144,195,.15) + +.edit-title + border-bottom: 1px solid #DEDEDE + padding: 10px + .left-part + font-size: 14px + .edit-button + border: none + outline: none + padding: 5px 15px + &:first-child + border-top-left-radius: 5px + border-bottom-left-radius: 5px + &:nth-child(2) + border-top-right-radius: 5px + border-bottom-right-radius: 5px + &.active + background: #fff + font-weight: 500 + border: 1px solid #000 + border-radius: 5px + &:not(.active):hover + background: #DEDEDE + + .right-part + .button-changes + border: none + outline: none + border-radius: 6px + padding: 6px 9px + border: 1px solid #DEDEDE + &:hover:first-child + background-color: #e8e3e3 + &:nth-child(2) + background-color: rgb(26, 127, 55) + color: #fff + &:nth-child(2):disabled + background-color: rgb(148, 211, 162) diff --git a/src/app/dataset-view/additional-components/overview-component/overview-component.spec.ts b/src/app/dataset-view/additional-components/overview-component/overview-component.spec.ts index 14bb24efd..13c8d8ba5 100644 --- a/src/app/dataset-view/additional-components/overview-component/overview-component.spec.ts +++ b/src/app/dataset-view/additional-components/overview-component/overview-component.spec.ts @@ -70,14 +70,6 @@ describe("OverviewComponent", () => { expect(component.metadataFragmentBlock).toEqual(undefined); }); - it("should check toggle readme view", () => { - const emitterSubscription$ = component.toggleReadmeViewEmit - .pipe(first()) - .subscribe(); - component.toggleReadmeView(); - expect(emitterSubscription$.closed).toBeTrue(); - }); - [ { kind: DatasetKind.Derivative, result: "Derivative" }, { kind: DatasetKind.Root, result: "Root" }, diff --git a/src/app/dataset-view/additional-components/overview-component/overview-component.ts b/src/app/dataset-view/additional-components/overview-component/overview-component.ts index 4b0ce837e..9744d0c9b 100644 --- a/src/app/dataset-view/additional-components/overview-component/overview-component.ts +++ b/src/app/dataset-view/additional-components/overview-component/overview-component.ts @@ -3,6 +3,7 @@ import { OverviewDataUpdate } from "src/app/dataset-view/dataset.subscriptions.i import { DatasetKind } from "./../../../api/kamu.graphql.interface"; import { ChangeDetectionStrategy, + ChangeDetectorRef, Component, EventEmitter, Input, @@ -34,10 +35,10 @@ import { EditWatermarkModalComponent } from "./components/edit-watermark-modal/e changeDetection: ChangeDetectionStrategy.OnPush, }) export class OverviewComponent extends BaseComponent implements OnInit { - @Input() public isMarkdownEditView: boolean; @Input() public datasetBasics?: DatasetBasicsFragment; @Output() toggleReadmeViewEmit = new EventEmitter(); @Output() selectTopicEmit = new EventEmitter(); + public addReadme = false; public currentState?: { schema: MaybeNull; @@ -50,6 +51,7 @@ export class OverviewComponent extends BaseComponent implements OnInit { private appDatasetSubsService: AppDatasetSubscriptionsService, private navigationService: NavigationService, private modalService: NgbModal, + private cdr: ChangeDetectorRef, ) { super(); } @@ -73,10 +75,6 @@ export class OverviewComponent extends BaseComponent implements OnInit { this.navigationService.navigateToWebsite(url); } - public toggleReadmeView(): void { - this.toggleReadmeViewEmit.emit(); - } - public selectTopic(topicName: string): void { this.selectTopicEmit.emit(topicName); } @@ -137,4 +135,8 @@ export class OverviewComponent extends BaseComponent implements OnInit { datasetName: this.datasetBasics.name as string, }); } + + public onAddReadme(): void { + this.addReadme = true; + } } diff --git a/src/app/dataset-view/additional-components/overview-component/services/dataset-commit.service.spec.ts b/src/app/dataset-view/additional-components/overview-component/services/dataset-commit.service.spec.ts new file mode 100644 index 000000000..5ee0d02fc --- /dev/null +++ b/src/app/dataset-view/additional-components/overview-component/services/dataset-commit.service.spec.ts @@ -0,0 +1,209 @@ +import { TestBed, fakeAsync, flush, tick } from "@angular/core/testing"; +import { DatasetCommitService } from "./dataset-commit.service"; +import { Apollo, ApolloModule } from "apollo-angular"; +import { ApolloTestingModule } from "apollo-angular/testing"; +import { DatasetApi } from "src/app/api/dataset.api"; +import { Observable, Subscription, of } from "rxjs"; +import { mockDatasetMainDataResponse } from "src/app/search/mock.data"; +import { DatasetByAccountAndDatasetNameQuery } from "src/app/api/kamu.graphql.interface"; +import { NavigationService } from "src/app/services/navigation.service"; +import { + mockCommitEventToDatasetMutation, + mockCommitEventToDatasetMutationError, + mockCommitEventToDatasetMutationErrorMessage, + mockUpdateReadmeMutation, +} from "../../data-tabs.mock"; +import { DatasetViewTypeEnum } from "src/app/dataset-view/dataset-view.interface"; +import { DatasetService } from "src/app/dataset-view/dataset.service"; +import { first } from "rxjs/operators"; + +describe("DatasetCommitService", () => { + let commitService: DatasetCommitService; + let datasetService: DatasetService; + let datasetApi: DatasetApi; + let navigationService: NavigationService; + + let getDatasetInfoSpy: jasmine.Spy; + let navigationServiceSpy: jasmine.Spy; + let requestDatasetMainDataSpy: jasmine.Spy; + + const TEST_ACCOUNT_NAME = "accountName"; + const TEST_DATASET_NAME = "datasetName"; + const TEST_DATASET_ID: string = mockDatasetMainDataResponse.datasets + .byOwnerAndName?.id as string; + const TEST_EVENT_CONTENT = "event content"; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [Apollo], + imports: [ApolloModule, ApolloTestingModule], + }); + datasetApi = TestBed.inject(DatasetApi); + navigationService = TestBed.inject(NavigationService); + commitService = TestBed.inject(DatasetCommitService); + datasetService = TestBed.inject(DatasetService); + + getDatasetInfoSpy = spyOn( + datasetApi, + "getDatasetInfoByAccountAndDatasetName", + ).and.returnValue( + of( + mockDatasetMainDataResponse as DatasetByAccountAndDatasetNameQuery, + ), + ); + + requestDatasetMainDataSpy = spyOn( + datasetService, + "requestDatasetMainData", + ).and.returnValue(of()); + + navigationServiceSpy = spyOn( + navigationService, + "navigateToDatasetView", + ); + }); + + it("should be created", () => { + expect(commitService).toBeTruthy(); + }); + + function requestDatasetId(): Observable { + return commitService.getIdByAccountNameAndDatasetName( + TEST_ACCOUNT_NAME, + TEST_DATASET_NAME, + ); + } + + function requestCommitEvent(): Observable { + return commitService.commitEventToDataset( + TEST_ACCOUNT_NAME, + TEST_DATASET_NAME, + TEST_EVENT_CONTENT, + ); + } + + function expectNavigatedToDatasetOverview() { + expect(navigationServiceSpy).toHaveBeenCalledOnceWith({ + accountName: TEST_ACCOUNT_NAME, + datasetName: TEST_DATASET_NAME, + tab: DatasetViewTypeEnum.Overview, + }); + } + + function expectRequestedDatasetMainData() { + expect(requestDatasetMainDataSpy).toHaveBeenCalledOnceWith({ + accountName: TEST_ACCOUNT_NAME, + datasetName: TEST_DATASET_NAME, + }); + } + + it("should check getIdByAccountNameAndDatasetName() method with cache", fakeAsync(() => { + // 1st requests queries the API + let eventsCount = 0; + requestDatasetId().subscribe((data) => { + ++eventsCount; + expect(data).toEqual(TEST_DATASET_ID); + tick(); + + // Issue 2nd request after first to ensure previous value was cached + requestDatasetId().subscribe((data) => { + ++eventsCount; + expect(data).toEqual(TEST_DATASET_ID); + tick(); + }); + }); + flush(); + + expect(eventsCount).toEqual(2); + expect(getDatasetInfoSpy).toHaveBeenCalledOnceWith( + TEST_ACCOUNT_NAME, + TEST_DATASET_NAME, + ); + })); + + it("should check getIdByAccountNameAndDatasetName() method without cache", fakeAsync(() => { + let eventsCount = 0; + requestDatasetId().subscribe((data) => { + ++eventsCount; + expect(data).toEqual(TEST_DATASET_ID); + tick(); + }); + flush(); + + expect(eventsCount).toEqual(1); + expect(getDatasetInfoSpy).toHaveBeenCalledOnceWith( + TEST_ACCOUNT_NAME, + TEST_DATASET_NAME, + ); + })); + + it("should check commitEventToDataset() method", fakeAsync(() => { + const commitEventSpy = spyOn(datasetApi, "commitEvent").and.returnValue( + of(mockCommitEventToDatasetMutation), + ); + + requestCommitEvent().subscribe(() => { + tick(); + }); + flush(); + + expect(commitEventSpy).toHaveBeenCalledOnceWith({ + datasetId: TEST_DATASET_ID, + event: TEST_EVENT_CONTENT, + }); + expectNavigatedToDatasetOverview(); + expectRequestedDatasetMainData(); + })); + + it("should check commitEventToDataset() method with error", fakeAsync(() => { + const commitEventSpy = spyOn(datasetApi, "commitEvent").and.returnValue( + of(mockCommitEventToDatasetMutationError), + ); + + const errorSubscription$: Subscription = + commitService.onErrorCommitEventChanges + .pipe(first()) + .subscribe((message) => { + expect(message).toEqual( + mockCommitEventToDatasetMutationErrorMessage, + ); + }); + + requestCommitEvent().subscribe(() => { + tick(); + }); + flush(); + + expect(commitEventSpy).toHaveBeenCalledOnceWith({ + datasetId: TEST_DATASET_ID, + event: TEST_EVENT_CONTENT, + }); + expect(navigationServiceSpy).not.toHaveBeenCalled(); + expect(requestDatasetMainDataSpy).not.toHaveBeenCalled(); + + // If error triggered, our subscription will be closed + expect(errorSubscription$.closed).toBeTrue(); + })); + + it("should check updateReadme() method ", fakeAsync(() => { + const updateReadmeSpy = spyOn( + datasetApi, + "updateReadme", + ).and.returnValue(of(mockUpdateReadmeMutation)); + const README_CONTENT = "readme content"; + + commitService + .updateReadme(TEST_ACCOUNT_NAME, TEST_DATASET_NAME, README_CONTENT) + .subscribe(() => { + tick(); + }); + flush(); + + expect(updateReadmeSpy).toHaveBeenCalledOnceWith( + TEST_DATASET_ID, + README_CONTENT, + ); + expectNavigatedToDatasetOverview(); + expectRequestedDatasetMainData(); + })); +}); diff --git a/src/app/dataset-view/additional-components/overview-component/services/dataset-commit.service.ts b/src/app/dataset-view/additional-components/overview-component/services/dataset-commit.service.ts new file mode 100644 index 000000000..53472aaa7 --- /dev/null +++ b/src/app/dataset-view/additional-components/overview-component/services/dataset-commit.service.ts @@ -0,0 +1,127 @@ +import { Injectable } from "@angular/core"; +import { Observable, Subject, of } from "rxjs"; +import { switchMap, map } from "rxjs/operators"; +import { DatasetApi } from "src/app/api/dataset.api"; +import { + CommitEventToDatasetMutation, + DatasetByAccountAndDatasetNameQuery, + UpdateReadmeMutation, +} from "src/app/api/kamu.graphql.interface"; +import { DatasetViewTypeEnum } from "src/app/dataset-view/dataset-view.interface"; +import { DatasetService } from "src/app/dataset-view/dataset.service"; +import { NavigationService } from "src/app/services/navigation.service"; + +@Injectable({ + providedIn: "root", +}) +export class DatasetCommitService { + private errorCommitEventChanges$: Subject = new Subject(); + + public errorCommitEventChanges(message: string): void { + this.errorCommitEventChanges$.next(message); + } + + public get onErrorCommitEventChanges(): Observable { + return this.errorCommitEventChanges$.asObservable(); + } + + private datasetIdsByAccountDatasetName = new Map(); + + constructor( + private datasetApi: DatasetApi, + private navigationService: NavigationService, + private datasetService: DatasetService, + ) {} + + public commitEventToDataset( + accountName: string, + datasetName: string, + event: string, + ): Observable { + return this.getIdByAccountNameAndDatasetName( + accountName, + datasetName, + ).pipe( + switchMap((id: string) => + this.datasetApi.commitEvent({ + datasetId: id, + event, + }), + ), + map((data: CommitEventToDatasetMutation | undefined | null) => { + if ( + data?.datasets.byId?.metadata.chain.commitEvent + .__typename === "CommitResultAppendError" || + data?.datasets.byId?.metadata.chain.commitEvent + .__typename === "MetadataManifestMalformed" + ) { + this.errorCommitEventChanges( + data.datasets.byId.metadata.chain.commitEvent.message, + ); + } else { + this.updatePage(accountName, datasetName); + } + }), + ); + } + + public getIdByAccountNameAndDatasetName( + accountName: string, + datasetName: string, + ): Observable { + const key = `${accountName}${datasetName}`; + const cachedId: string | undefined = + this.datasetIdsByAccountDatasetName.get(key); + if (cachedId) { + return of(cachedId); + } else { + return this.datasetApi + .getDatasetInfoByAccountAndDatasetName(accountName, datasetName) + .pipe( + map((data: DatasetByAccountAndDatasetNameQuery) => { + const id = data.datasets.byOwnerAndName?.id as string; + this.datasetIdsByAccountDatasetName.set(key, id); + return id; + }), + ); + } + } + + public updateReadme( + accountName: string, + datasetName: string, + content: string, + ): Observable { + return this.getIdByAccountNameAndDatasetName( + accountName, + datasetName, + ).pipe( + switchMap((id: string) => + this.datasetApi.updateReadme(id, content), + ), + map((data: UpdateReadmeMutation | null | undefined) => { + if ( + data?.datasets.byId?.metadata.updateReadme.__typename === + "CommitResultSuccess" + ) { + this.updatePage(accountName, datasetName); + } + }), + ); + } + + private updatePage(accountName: string, datasetName: string): void { + this.datasetService + .requestDatasetMainData({ + accountName, + datasetName, + }) + .subscribe(); + + this.navigationService.navigateToDatasetView({ + accountName, + datasetName, + tab: DatasetViewTypeEnum.Overview, + }); + } +} diff --git a/src/app/dataset-view/dataset-view-header/dataset-view-header.html b/src/app/dataset-view/dataset-view-header/dataset-view-header.html index 132cd92d0..467e118e1 100644 --- a/src/app/dataset-view/dataset-view-header/dataset-view-header.html +++ b/src/app/dataset-view/dataset-view-header/dataset-view-header.html @@ -10,7 +10,7 @@ rel="author" data-hovercard-type="organization" (click)="showOwnerPage()" - data-test-id='show-owner-link' + data-test-id="show-owner-link" >{{ datasetInfo.accountName}} @@ -19,7 +19,7 @@ {{ datasetInfo.datasetName }} diff --git a/src/app/dataset-view/dataset.component.html b/src/app/dataset-view/dataset.component.html index 4b3e749fa..45e1946e1 100644 --- a/src/app/dataset-view/dataset.component.html +++ b/src/app/dataset-view/dataset.component.html @@ -30,9 +30,7 @@ diff --git a/src/app/dataset-view/dataset.component.spec.ts b/src/app/dataset-view/dataset.component.spec.ts index ab6fd5835..57f2dffc9 100644 --- a/src/app/dataset-view/dataset.component.spec.ts +++ b/src/app/dataset-view/dataset.component.spec.ts @@ -149,14 +149,6 @@ describe("DatasetComponent", () => { expect(getMainDataByLineageNodeSpy).toHaveBeenCalledTimes(1); }); - it("should check toggle readme view", () => { - component.isMarkdownEditView = false; - component.toggleReadmeView(); - expect(component.isMarkdownEditView).toBe(true); - component.toggleReadmeView(); - expect(component.isMarkdownEditView).toBe(false); - }); - it("should check run SQL request", () => { const sqlQuery = "select * from test.table"; const requestDatasetDataSqlRunSpy = spyOn( diff --git a/src/app/dataset-view/dataset.component.ts b/src/app/dataset-view/dataset.component.ts index 6bc38758f..18d3534af 100644 --- a/src/app/dataset-view/dataset.component.ts +++ b/src/app/dataset-view/dataset.component.ts @@ -35,7 +35,6 @@ export class DatasetComponent public datasetViewType: DatasetViewTypeEnum = DatasetViewTypeEnum.Overview; public lineageGraphView: [number, number] = [500, 600]; - public isMarkdownEditView = false; @HostListener("window:resize") private checkWindowSize(): void { @@ -159,10 +158,6 @@ export class DatasetComponent console.log("initDiscussionsTab"); } - public toggleReadmeView(): void { - this.isMarkdownEditView = !this.isMarkdownEditView; - } - public selectTopic(topicName: string): void { promiseWithCatch( this.modalService.warning({ diff --git a/src/app/dataset-view/dataset.module.ts b/src/app/dataset-view/dataset.module.ts index 15ee11d2b..09cf4f891 100644 --- a/src/app/dataset-view/dataset.module.ts +++ b/src/app/dataset-view/dataset.module.ts @@ -61,6 +61,7 @@ import { PageNotFoundComponent } from "../components/page-not-found/page-not-fou import { AddPollingSourceComponent } from "./additional-components/metadata-component/components/add-polling-source/add-polling-source.component"; import { MatStepperModule } from "@angular/material/stepper"; import { EngineSelectComponent } from "./additional-components/metadata-component/components/set-transform/components/engine-section/components/engine-select/engine-select.component"; +import { ReadmeSectionComponent } from "./additional-components/overview-component/components/readme-section/readme-section.component"; @NgModule({ imports: [ CommonModule, @@ -146,6 +147,7 @@ import { EngineSelectComponent } from "./additional-components/metadata-componen PageNotFoundComponent, AddPollingSourceComponent, EngineSelectComponent, + ReadmeSectionComponent, ], }) export class DatasetModule { diff --git a/src/app/search/mock.data.ts b/src/app/search/mock.data.ts index 4dc46775e..9f318feba 100644 --- a/src/app/search/mock.data.ts +++ b/src/app/search/mock.data.ts @@ -1,5 +1,5 @@ import { - CommitEventToDatasetQuery, + CommitEventToDatasetMutation, PageBasedInfo, } from "./../api/kamu.graphql.interface"; import { mockSetVocab } from "./../dataset-block/metadata-block/components/event-details/mock.events"; @@ -763,9 +763,9 @@ export const mockDatasetDataSqlRunInternalErrorResponse: GetDatasetDataSqlRunQue }, }; -export const mockCommitEventResponse: CommitEventToDatasetQuery = { +export const mockCommitEventResponse: CommitEventToDatasetMutation = { datasets: { - byOwnerAndName: { + byId: { metadata: { chain: { commitEvent: { @@ -776,13 +776,9 @@ export const mockCommitEventResponse: CommitEventToDatasetQuery = { newHead: "zW1hgfvGgmdsbrDMhVoBE5TRX2RX4DV2mhh4QgEAeA3fx4Q", }, - __typename: "MetadataChain", }, - __typename: "DatasetMetadata", }, - __typename: "Dataset", }, - __typename: "Datasets", }, }; diff --git a/src/assets/styles/var.sass b/src/assets/styles/var.sass index 562423e6f..c2d585b69 100644 --- a/src/assets/styles/var.sass +++ b/src/assets/styles/var.sass @@ -390,13 +390,13 @@ $app-color-action-list-item-inline-divider: #d0d7de7a font-size: 12px line-height: 32px & .file-content - padding: 16px + padding: 40px 25px & .variable-textarea width: 100% min-height: 300px - max-height: 600px height: max-content border: none + outline: none markdown & * font: revert !important