Skip to content

Commit

Permalink
Add UI to configure Sharing Settings
Browse files Browse the repository at this point in the history
  • Loading branch information
pmachapman committed Nov 25, 2024
1 parent 8797925 commit 6add968
Show file tree
Hide file tree
Showing 9 changed files with 738 additions and 275 deletions.
7 changes: 6 additions & 1 deletion src/SIL.XForge.Scripture/ClientApp/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ServiceWorkerModule } from '@angular/service-worker';
import { TranslocoModule } from '@ngneat/transloco';
import { CookieService } from 'ngx-cookie-service';
import { defaultTranslocoMarkupTranspilers, provideTranslationMarkupTranspiler } from 'ngx-transloco-markup';
import {
defaultTranslocoMarkupTranspilers,
provideTranslationMarkupTranspiler,
TranslocoMarkupModule
} from 'ngx-transloco-markup';
import { translocoMarkupRouterLinkRenderer } from 'ngx-transloco-markup-router-link';
import { AvatarComponent } from 'xforge-common/avatar/avatar.component';
import { EditNameDialogComponent } from 'xforge-common/edit-name-dialog/edit-name-dialog.component';
Expand Down Expand Up @@ -72,6 +76,7 @@ import { UsersModule } from './users/users.module';
UICommonModule.forRoot(),
XForgeCommonModule,
TranslocoModule,
TranslocoMarkupModule,
AppRoutingModule,
SharedModule,
AvatarComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export interface SFProjectSettings {
translationSuggestionsEnabled?: boolean | null;
sourceParatextId?: string | null;
biblicalTermsEnabled?: boolean | null;
translateShareEnabled?: boolean | null;

additionalTrainingData?: boolean | null;
additionalTrainingSourceEnabled?: boolean | null;
Expand All @@ -20,7 +19,11 @@ export interface SFProjectSettings {

checkingEnabled?: boolean | null;
usersSeeEachOthersResponses?: boolean | null;
checkingShareEnabled?: boolean | null;
checkingAnswerExport?: CheckingAnswerExport | null;
hideCommunityCheckingText?: boolean | null;

translatorsShareEnabled?: boolean | null;
communityCheckersShareEnabled?: boolean | null;
commentersShareEnabled?: boolean | null;
viewersShareEnabled?: boolean | null;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
import { fakeAsync, TestBed } from '@angular/core/testing';
import { anything, mock, verify } from 'ts-mockito';
import { CommandService } from 'xforge-common/command.service';
import { LocationService } from 'xforge-common/location.service';
import { RealtimeService } from 'xforge-common/realtime.service';
import { RetryingRequestService } from 'xforge-common/retrying-request.service';
import { configureTestingModule } from 'xforge-common/test-utils';
import { SFProjectService } from './sf-project.service';

const mockedCommandService = mock(CommandService);
const mockedLocationService = mock(LocationService);
const mockedRealtimeService = mock(RealtimeService);
const mockedRetryingRequestService = mock(RetryingRequestService);

describe('SFProjectService', () => {
configureTestingModule(() => ({
providers: [
{ provide: CommandService, useMock: mockedCommandService },
{ provide: LocationService, useMock: mockedLocationService },
{ provide: RealtimeService, useMock: mockedRealtimeService },
{ provide: RetryingRequestService, useMock: mockedRetryingRequestService },
provideHttpClient(withInterceptorsFromDi()),
provideHttpClientTesting()
]
}));

describe('onlineSetRoleProjectPermissions', () => {
it('should invoke the command service', fakeAsync(async () => {
const env = new TestEnvironment();
const projectId = 'project01';
const role = 'role01';
const permissions = ['permission01'];
await env.service.onlineSetRoleProjectPermissions(projectId, role, permissions);
verify(mockedCommandService.onlineInvoke(anything(), 'setRoleProjectPermissions', anything())).once();
expect().nothing();
}));
});

describe('onlineSetUserProjectPermissions', () => {
it('should invoke the command service', fakeAsync(async () => {
const env = new TestEnvironment();
const projectId = 'project01';
const userId = 'user01';
const permissions = ['permission01'];
await env.service.onlineSetUserProjectPermissions(projectId, userId, permissions);
verify(mockedCommandService.onlineInvoke(anything(), 'setUserProjectPermissions', anything())).once();
expect().nothing();
}));
});

class TestEnvironment {
readonly httpTestingController: HttpTestingController;
readonly service: SFProjectService;

constructor() {
this.httpTestingController = TestBed.inject(HttpTestingController);
this.service = TestBed.inject(SFProjectService);
}
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,14 @@ export class SFProjectService extends ProjectService<SFProject, SFProjectDoc> {
return this.onlineRetryInvoke<TransceleratorQuestion[]>('transceleratorQuestions', cancel, { projectId });
}

async onlineSetRoleProjectPermissions(projectId: string, role: string, permissions: string[]): Promise<void> {
return (await this.onlineInvoke<void>('setRoleProjectPermissions', {
projectId,
role,
permissions
}))!;
}

async onlineSetUserProjectPermissions(projectId: string, userId: string, permissions: string[]): Promise<void> {
return (await this.onlineInvoke<void>('setUserProjectPermissions', {
projectId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,42 +326,77 @@
}
</mat-card-content>
<mat-card-content>
<mat-card-title>{{ t("sharing") }}</mat-card-title>
<mat-card-title>{{ t("sharing_settings") }}</mat-card-title>
<p class="helper-text">{{ t("sharing_description") }}</p>
<h4>{{ t("sharing_paratext_members") }}</h4>
<div class="tool-setting">
<div class="tool-setting-field checkbox-field">
<mat-checkbox formControlName="translateShareEnabled" id="checkbox-translate-share">
{{ t("shareTranslate") }}
<mat-checkbox [checked]="true" [disabled]="true">
{{ t("sharing_administrators") }}
</mat-checkbox>
</div>
</div>
<div class="tool-setting">
<div class="tool-setting-field checkbox-field">
<mat-checkbox formControlName="translatorsShareEnabled" id="checkbox-translators-share">
{{ t("sharing_translators") }}
</mat-checkbox>
<app-info [text]="t('users_can_share_the_project')"></app-info>
<app-write-status
[state]="getControlState('translateShareEnabled')"
[state]="getControlState('translatorsShareEnabled')"
[formGroup]="form"
id="translate-share-status"
id="translators-share-status"
></app-write-status>
</div>
</div>
<h4>{{ t("sharing_scripture_forge_guests") }}</h4>
<p class="helper-text">
<transloco
key="settings.sharing_scripture_forge_guests_help"
[params]="{
rolesHelpUrl: 'https://help.scriptureforge.org/community-checking/#5aa7e3d8451f40cfa6b33c5dd39a3c6f'
}"
></transloco>
</p>
@if (isCheckingEnabled) {
<div class="tool-setting">
<div class="tool-setting-field checkbox-field">
<mat-checkbox formControlName="checkingShareEnabled" id="checkbox-checking-share">
{{ t("shareChecking") }}
<mat-checkbox formControlName="communityCheckersShareEnabled" id="checkbox-community-checkers-share">
<span>{{ t("sharing_community_checkers") }}</span>
<span class="description">{{ i18n.localizeRoleDescription(SFProjectRole.CommunityChecker) }}</span>
</mat-checkbox>
<app-info [text]="t('users_can_share_the_project')"></app-info>
<app-write-status
[state]="getControlState('checkingShareEnabled')"
[state]="getControlState('communityCheckersShareEnabled')"
[formGroup]="form"
id="checking-share-status"
id="community-checkers-share-status"
></app-write-status>
</div>
</div>
}
<div class="indent">
<mat-icon class="no-hover">admin_panel_settings</mat-icon>
<span>
<span [innerHTML]="shareDescription?.before"></span>
<a [appRouterLink]="['/projects', projectId, 'users']">{{ shareDescription?.templateTagText }}</a>
<span>{{ shareDescription?.after }}</span>
</span>
<div class="tool-setting">
<div class="tool-setting-field checkbox-field">
<mat-checkbox formControlName="commentersShareEnabled" id="checkbox-commenters-share">
<span>{{ t("sharing_commenters") }}</span>
<span class="description">{{ i18n.localizeRoleDescription(SFProjectRole.Commenter) }}</span>
</mat-checkbox>
<app-write-status
[state]="getControlState('commentersShareEnabled')"
[formGroup]="form"
id="commenters-share-status"
></app-write-status>
</div>
</div>
<div class="tool-setting">
<div class="tool-setting-field checkbox-field">
<mat-checkbox formControlName="viewersShareEnabled" id="checkbox-viewers-share">
<span>{{ t("sharing_viewers") }}</span>
<span class="description">{{ i18n.localizeRoleDescription(SFProjectRole.Viewer) }}</span>
</mat-checkbox>
<app-write-status
[state]="getControlState('viewersShareEnabled')"
[formGroup]="form"
id="viewers-share-status"
></app-write-status>
</div>
</div>
</mat-card-content>
</mat-card>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@

> .checkbox-field {
display: flex;

span {
display: block;
}

.description {
color: gray;
font-size: smaller;
}
}

> .tool-setting-field {
Expand Down
Loading

0 comments on commit 6add968

Please sign in to comment.