Skip to content

Commit d40fa1f

Browse files
feat(metadata): update metadata for file
1 parent 6ec5ed6 commit d40fa1f

16 files changed

Lines changed: 76 additions & 791 deletions

File tree

src/app/core/guards/is-file.guard.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,17 @@ import { Store } from '@ngxs/store';
33
import { map, switchMap } from 'rxjs/operators';
44

55
import { inject } from '@angular/core';
6-
import { CanMatchFn, Route, UrlSegment } from '@angular/router';
6+
import { CanMatchFn, Route, Router, UrlSegment } from '@angular/router';
77

88
import { CurrentResourceType } from '../../shared/enums';
99
import { CurrentResourceSelectors, GetResource } from '../../shared/stores';
1010

1111
export const isFileGuard: CanMatchFn = (route: Route, segments: UrlSegment[]) => {
1212
const store = inject(Store);
13+
const router = inject(Router);
1314

1415
const id = segments[0]?.path;
16+
const isMetadataPath = segments[1]?.path === 'metadata';
1517
if (!id) {
1618
return false;
1719
}
@@ -20,7 +22,13 @@ export const isFileGuard: CanMatchFn = (route: Route, segments: UrlSegment[]) =>
2022

2123
if (currentResource && currentResource.id === id) {
2224
if (currentResource.type === CurrentResourceType.Files) {
23-
return true;
25+
if (isMetadataPath) {
26+
return true;
27+
}
28+
if (currentResource.parentId) {
29+
router.navigate(['/', currentResource.parentId, 'files', id]);
30+
return false;
31+
}
2432
}
2533

2634
return currentResource.type === CurrentResourceType.Files;
@@ -34,7 +42,13 @@ export const isFileGuard: CanMatchFn = (route: Route, segments: UrlSegment[]) =>
3442
}
3543

3644
if (resource.type === CurrentResourceType.Files) {
37-
return true;
45+
if (isMetadataPath) {
46+
return true;
47+
}
48+
if (resource.parentId) {
49+
router.navigate(['/', resource.parentId, 'files', id]);
50+
return false;
51+
}
3852
}
3953
return resource.type === CurrentResourceType.Files;
4054
})

src/app/features/files/pages/file-detail/file-detail.component.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@
100100
[cedarFormReadonly]="cedarFormReadonly()"
101101
(changeTab)="onMetadataTabChange($event)"
102102
(formSubmit)="onCedarFormSubmit($event)"
103-
(cedarFormChangeTemplate)="onCedarFormChangeTemplate()"
104103
(cedarFormEdit)="onCedarFormEdit()"
105104
>
106105
<div class="w-full flex flex-column gap-4 flex-1 -mt-4">

src/app/features/files/pages/file-detail/file-detail.component.ts

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,6 @@ export class FileDetailComponent {
203203
})) || [];
204204

205205
this.tabs.set([...baseTabs, ...cedarTabs]);
206-
// this.handleRouteBasedTabSelection();
207206
});
208207

209208
this.route.params.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((params) => {
@@ -301,24 +300,21 @@ export class FileDetailComponent {
301300
}
302301

303302
onCedarFormSubmit(data: CedarRecordDataBinding): void {
304-
// const selectedRecord = this.selectedCedarRecord();
305-
// if (!this.resourceId || !selectedRecord) return;
306-
// if (selectedRecord.id) {
307-
// this.actions
308-
// .updateCedarRecord(data, selectedRecord.id, this.resourceId, this.resourceType())
309-
// .pipe(takeUntilDestroyed(this.destroyRef))
310-
// .subscribe({
311-
// next: () => {
312-
// this.cedarFormReadonly.set(true);
313-
// this.toastService.showSuccess('CEDAR record updated successfully');
314-
// this.actions.getCedarRecords(this.resourceId, this.resourceType());
315-
// },
316-
// });
317-
// }
318-
}
319-
320-
onCedarFormChangeTemplate(): void {
321-
// this.router.navigate(['add'], { relativeTo: this.activeRoute });
303+
const selectedRecord = this.selectedCedarRecord();
304+
if (!this.resourceId || !selectedRecord) return;
305+
if (selectedRecord.id) {
306+
this.actions
307+
.updateCedarRecord(data, selectedRecord.id, this.resourceId, ResourceType.File)
308+
.pipe(takeUntilDestroyed(this.destroyRef))
309+
.subscribe({
310+
next: () => {
311+
this.cedarFormReadonly.set(true);
312+
this.toastService.showSuccess('files.detail.toast.cedarUpdated');
313+
const fileId = this.file()?.path.replaceAll('/', '') || '';
314+
this.actions.getCedarRecords(fileId, ResourceType.File);
315+
},
316+
});
317+
}
322318
}
323319

324320
private loadCedarRecord(recordId: string): void {

src/app/features/metadata/mappers/metadata.mapper.ts

Lines changed: 1 addition & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export class MetadataMapper {
2727
value: identifier.attributes.value,
2828
})),
2929
provider: response.embeds?.provider?.data.id,
30+
public: response.attributes.public,
3031
};
3132
}
3233

@@ -65,55 +66,4 @@ export class MetadataMapper {
6566
},
6667
};
6768
}
68-
69-
// static fromMetadataApiResponse(response: Record<string, unknown>): ProjectOverview {
70-
// const attributes = response['attributes'] as Record<string, unknown>;
71-
// const embeds = response['embeds'] as Record<string, unknown>;
72-
73-
// const contributors: ProjectOverviewContributor[] = [];
74-
// if (embeds['contributors']) {
75-
// const contributorsData = (embeds['contributors'] as Record<string, unknown>)['data'] as Record<string, unknown>[];
76-
// contributorsData?.forEach((contributor) => {
77-
// const contributorEmbeds = contributor['embeds'] as Record<string, unknown>;
78-
// const userData = (contributorEmbeds['users'] as Record<string, unknown>)['data'] as Record<string, unknown>;
79-
// const userAttributes = userData['attributes'] as Record<string, unknown>;
80-
81-
// contributors.push({
82-
// id: userData['id'] as string,
83-
// type: userData['type'] as string,
84-
// fullName: userAttributes['full_name'] as string,
85-
// givenName: userAttributes['given_name'] as string,
86-
// familyName: userAttributes['family_name'] as string,
87-
// middleName: '',
88-
// });
89-
// });
90-
// }
91-
92-
// return {
93-
// id: response['id'] as string,
94-
// type: (response['type'] as string) || 'nodes',
95-
// title: attributes['title'] as string,
96-
// description: attributes['description'] as string,
97-
// category: attributes['category'] as string,
98-
// tags: (attributes['tags'] as string[]) || [],
99-
// dateCreated: attributes['date_created'] as string,
100-
// dateModified: attributes['date_modified'] as string,
101-
// isPublic: attributes['public'] as boolean,
102-
// isRegistration: attributes['registration'] as boolean,
103-
// isPreprint: attributes['preprint'] as boolean,
104-
// isFork: attributes['fork'] as boolean,
105-
// isCollection: attributes['collection'] as boolean,
106-
// accessRequestsEnabled: attributes['access_requests_enabled'] as boolean,
107-
// wikiEnabled: attributes['wiki_enabled'] as boolean,
108-
// currentUserCanComment: attributes['current_user_can_comment'] as boolean,
109-
// currentUserPermissions: (attributes['current_user_permissions'] as string[]) || [],
110-
// currentUserIsContributor: attributes['current_user_is_contributor'] as boolean,
111-
// currentUserIsContributorOrGroupMember: attributes['current_user_is_contributor_or_group_member'] as boolean,
112-
// analyticsKey: '',
113-
// contributors: contributors,
114-
// subjects: Array.isArray(attributes['subjects']) ? attributes['subjects'].flat() : attributes['subjects'],
115-
// forksCount: 0,
116-
// viewOnlyLinksCount: 0,
117-
// } as ProjectOverview;
118-
// }
11969
}

src/app/features/metadata/metadata.component.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,10 @@ export class MetadataComponent implements OnInit {
154154
});
155155

156156
hideEditDoi = computed(() => {
157-
return !!(this.metadata()?.identifiers?.length && this.resourceType() === ResourceType.Project);
157+
return (
158+
!!(this.metadata()?.identifiers?.length && this.resourceType() === ResourceType.Project) ||
159+
!this.metadata()?.public
160+
);
158161
});
159162

160163
constructor() {
@@ -473,7 +476,9 @@ export class MetadataComponent implements OnInit {
473476
acceptLabelType: 'primary',
474477
onConfirm: () => {
475478
this.actions.createDoi(this.resourceId, this.resourceType()).subscribe({
476-
next: () => this.toastService.showSuccess('project.metadata.doi.created'),
479+
next: () => {
480+
this.toastService.showSuccess('project.metadata.doi.created');
481+
},
477482
});
478483
},
479484
});

src/app/features/metadata/models/metadata-json-api.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export interface MetadataAttributesJsonApi {
2222
doi?: boolean;
2323
category?: string;
2424
node_license?: LicenseRecordJsonApi;
25+
public?: boolean;
2526
}
2627

2728
interface MetadataEmbedsJsonApi {

src/app/features/metadata/models/metadata.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export interface Metadata {
2020
copyrightHolders: string[];
2121
year: string;
2222
};
23+
public?: boolean;
2324
}
2425

2526
export interface CustomItemMetadataRecord {

src/app/features/metadata/pages/add-metadata/add-metadata.component.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export class AddMetadataComponent implements OnInit {
5555
readonly cedarTemplates = select(MetadataSelectors.getCedarTemplates);
5656
readonly cedarRecords = select(MetadataSelectors.getCedarRecords);
5757
readonly cedarTemplatesLoading = select(MetadataSelectors.getCedarTemplatesLoading);
58+
readonly cedarRecord = select(MetadataSelectors.getCedarRecord);
5859

5960
actions = createDispatchMap({
6061
getCedarTemplates: GetCedarMetadataTemplates,
@@ -155,6 +156,9 @@ export class AddMetadataComponent implements OnInit {
155156
createRecordMetadata(data: CedarRecordDataBinding): void {
156157
const recordId = this.activatedRoute.snapshot.params['recordId'];
157158

159+
console.log('Creating or updating record metadata:', this.resourceType());
160+
console.log('Creating or updating record metadata:', this.resourceId);
161+
158162
if (recordId && this.existingRecord) {
159163
this.actions
160164
.updateCedarMetadataRecord(data, recordId, this.resourceId, this.resourceType())
@@ -173,6 +177,7 @@ export class AddMetadataComponent implements OnInit {
173177
next: () => {
174178
this.toggleEditMode();
175179
this.toastService.showSuccess('project.metadata.addMetadata.recordCreatedSuccessfully');
180+
this.navigateToRecord(this.resourceId, this.resourceType());
176181
},
177182
});
178183
}
@@ -181,4 +186,15 @@ export class AddMetadataComponent implements OnInit {
181186
toggleEditMode(): void {
182187
this.isEditMode = !this.isEditMode;
183188
}
189+
190+
private navigateToRecord(resourceId: string, resourceType: ResourceType): void {
191+
const recordId = this.cedarRecord()?.data.id;
192+
console.log('Navigating to record:', recordId);
193+
console.log('Navigating to record:', resourceType);
194+
if (resourceType === ResourceType.File) {
195+
this.router.navigate([resourceId]);
196+
} else {
197+
this.router.navigate(['../', recordId], { relativeTo: this.activatedRoute });
198+
}
199+
}
184200
}

src/app/features/metadata/services/metadata.service.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { map } from 'rxjs/operators';
44
import { inject, Injectable } from '@angular/core';
55

66
import { ResourceType } from '@osf/shared/enums';
7-
import { LicenseOptions } from '@osf/shared/models';
7+
import { Identifier, LicenseOptions } from '@osf/shared/models';
88
import { JsonApiService } from '@osf/shared/services';
99

1010
import { CedarRecordsMapper, MetadataMapper } from '../mappers';
@@ -49,7 +49,7 @@ export class MetadataService {
4949
.pipe(map((response) => MetadataMapper.fromCustomMetadataApiResponse(response)));
5050
}
5151

52-
createDoi(resourceId: string, resourceType: ResourceType): Observable<Metadata> {
52+
createDoi(resourceId: string, resourceType: ResourceType): Observable<Identifier> {
5353
const payload = {
5454
data: {
5555
type: 'identifiers',
@@ -59,12 +59,10 @@ export class MetadataService {
5959
},
6060
};
6161

62-
return this.jsonApiService
63-
.post<MetadataJsonApiResponse>(
64-
`${this.apiUrl}/${this.urlMap.get(resourceType)}/${resourceId}/identifiers/`,
65-
payload
66-
)
67-
.pipe(map((response) => MetadataMapper.fromMetadataApiResponse(response.data)));
62+
return this.jsonApiService.post(
63+
`${this.apiUrl}/${this.urlMap.get(resourceType)}/${resourceId}/identifiers/`,
64+
payload
65+
);
6866
}
6967

7068
getFundersList(searchQuery?: string): Observable<CrossRefFundersResponse> {

src/app/features/metadata/store/metadata.state.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,11 @@ export class MetadataState {
117117

118118
return this.metadataService.createDoi(action.resourceId, action.resourceType).pipe(
119119
tap({
120-
next: (response) => {
120+
next: () => {
121121
ctx.patchState({
122-
metadata: { data: response, isLoading: false, error: null },
122+
metadata: { ...ctx.getState().metadata, isLoading: false, error: null },
123123
});
124+
ctx.dispatch(new GetResourceMetadata(action.resourceId, action.resourceType));
124125
},
125126
}),
126127
catchError((error) => handleSectionError(ctx, 'metadata', error))
@@ -213,6 +214,13 @@ export class MetadataState {
213214
createCedarMetadataRecord(ctx: StateContext<MetadataStateModel>, action: CreateCedarMetadataRecord) {
214215
return this.metadataService.createMetadataCedarRecord(action.record, action.resourceId, action.resourceType).pipe(
215216
tap((response: CedarMetadataRecord) => {
217+
ctx.patchState({
218+
cedarRecord: {
219+
data: response,
220+
error: null,
221+
isLoading: false,
222+
},
223+
});
216224
ctx.dispatch(new AddCedarMetadataRecordToState(response.data));
217225
})
218226
);

0 commit comments

Comments
 (0)