Add disucssion export into tsv, minor fixes
This commit is contained in:
parent
8af2a4d192
commit
250ecc8eb7
@ -42,3 +42,9 @@ export const removeCategoryFromDimension = createAction(
|
||||
'[Dimension] Remove Category From Dimension',
|
||||
props<{ id: any }>()
|
||||
);
|
||||
export const removeSelectedDimension = createAction(
|
||||
'[Dimension] Remove Selected Dimension'
|
||||
);
|
||||
export const removeSelectedDimensionSuccess = createAction(
|
||||
'[Dimension] Remove Selected Dimension Success'
|
||||
);
|
||||
|
@ -8,6 +8,9 @@ export const discussionLoadSuccess = createAction(
|
||||
'[DiscussionChooser] Load Discussions Success',
|
||||
props<{ discussions: any }>()
|
||||
);
|
||||
export const loadDimensions = createAction(
|
||||
'[DiscussionChooser] Load Available Dimensions'
|
||||
);
|
||||
export const availableDimensionsLoadSuccess = createAction(
|
||||
'[DiscussionChooser] Load Available Dimensions Success',
|
||||
props<{ dimensions: Array<Dimension> }>()
|
||||
|
@ -43,3 +43,13 @@ export const updateCategory = createAction(
|
||||
export const updateCategorySuccess = createAction(
|
||||
'[DiscussionViewer] Update Paragraph Category Success'
|
||||
);
|
||||
|
||||
export const exportFile = createAction('[DiscussionViewer] Export File');
|
||||
|
||||
export const exportFileSuccess = createAction(
|
||||
'[DiscussionViewer] Export File Success'
|
||||
);
|
||||
|
||||
export const exportFileFailure = createAction(
|
||||
'[DiscussionViewer] Export File Failure'
|
||||
);
|
||||
|
@ -8,12 +8,6 @@ const routes: Routes = [
|
||||
path: '',
|
||||
component: FrontPageComponent,
|
||||
},
|
||||
{
|
||||
path: 'view',
|
||||
canActivate: [AuthGuard],
|
||||
loadChildren: () =>
|
||||
import('./main-view/main-view.module').then((m) => m.MainViewModule),
|
||||
},
|
||||
{
|
||||
path: 'auth',
|
||||
loadChildren: () => import('./auth/auth.module').then((m) => m.AuthModule),
|
||||
|
@ -18,6 +18,8 @@ import {
|
||||
updateSelectedDimension,
|
||||
updateSelectedDimensionSuccess,
|
||||
removeCategoryFromDimension,
|
||||
removeSelectedDimension,
|
||||
removeSelectedDimensionSuccess,
|
||||
} from '../actions/dimension.actions';
|
||||
import { addDimensionToFile } from '../actions/discussion-chooser.actions';
|
||||
import { DimensionsService } from '../services/dimensions.service';
|
||||
@ -28,13 +30,15 @@ import {
|
||||
selectCurrentDimension,
|
||||
selectDimension,
|
||||
} from '../selectors/dimension.selectors';
|
||||
import { NbToastrService } from '@nebular/theme';
|
||||
|
||||
@Injectable()
|
||||
export class DimmensionEffects {
|
||||
constructor(
|
||||
private actions$: Actions,
|
||||
private dimensionService: DimensionsService,
|
||||
private store$: Store<State>
|
||||
private store$: Store<State>,
|
||||
private toastService: NbToastrService
|
||||
) {}
|
||||
|
||||
getDimmensions$ = createEffect(() =>
|
||||
@ -130,4 +134,22 @@ export class DimmensionEffects {
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
removeSelectedDimension = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(removeSelectedDimension),
|
||||
withLatestFrom(this.store$.select(selectDimension)),
|
||||
flatMap(([_, id]) => {
|
||||
this.store$.dispatch(removeDimension({ id: id! }));
|
||||
return this.dimensionService.removeDimension(id!).pipe(
|
||||
map(() => {
|
||||
this.toastService.info('', 'Pomyślnie usnięto wymiar', {
|
||||
icon: 'checkmark-outline',
|
||||
});
|
||||
return removeSelectedDimensionSuccess();
|
||||
})
|
||||
);
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
bindClassifier,
|
||||
bindClassifierSuccess,
|
||||
setBindClassifierLoading,
|
||||
loadDimensions,
|
||||
} from '../actions/discussion-chooser.actions';
|
||||
import {
|
||||
catchError,
|
||||
@ -17,7 +18,7 @@ import {
|
||||
tap,
|
||||
withLatestFrom,
|
||||
} from 'rxjs/operators';
|
||||
import { EMPTY, forkJoin, of } from 'rxjs';
|
||||
import { EMPTY, forkJoin, of, throwError } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { selectRouteParam, State as AppState } from '../reducers';
|
||||
import { GetDiscussionService } from '../services/get-discussion.service';
|
||||
@ -55,34 +56,50 @@ export class DiscussionChooserEffects {
|
||||
)
|
||||
);
|
||||
|
||||
$loadDimensions = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(loadDimensions),
|
||||
withLatestFrom(this.store$.select(selectRouteParam('id'))),
|
||||
flatMap(([_, id]) =>
|
||||
this.discussionService.getDiscussionDimensions(parseInt(id!)).pipe(
|
||||
map((res) =>
|
||||
availableDimensionsLoadSuccess({ dimensions: res.data })
|
||||
),
|
||||
catchError((error) => throwError(error))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$bind = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(bindClassifier),
|
||||
withLatestFrom(
|
||||
this.store$.select((state) => state.dataState.data?.discussions)
|
||||
),
|
||||
flatMap(([action, data]) =>
|
||||
flatMap(([_, data]) =>
|
||||
forkJoin(
|
||||
data?.map((el) => this.discussionService.bindClassfier(el.id))
|
||||
).pipe(
|
||||
map(() => bindClassifierSuccess()),
|
||||
catchError((err) => EMPTY)
|
||||
catchError(() => EMPTY)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$bindSuccess = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(bindClassifierSuccess),
|
||||
tap(() => {
|
||||
this.toastService.success('', 'Pomyślnie dodano klasyfikator', {
|
||||
icon: 'checkmark-circle',
|
||||
});
|
||||
this.store$.dispatch(setBindClassifierLoading({ status: false }));
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
$bindSuccess = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(bindClassifierSuccess),
|
||||
tap(() => {
|
||||
this.toastService.success('', 'Pomyślnie dodano klasyfikator', {
|
||||
icon: 'checkmark-circle',
|
||||
});
|
||||
return this.store$.dispatch(
|
||||
setBindClassifierLoading({ status: false })
|
||||
);
|
||||
}),
|
||||
map(() => loadDimensions())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -3,6 +3,9 @@ import { Actions, createEffect, ofType } from '@ngrx/effects';
|
||||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
discussionSuccess,
|
||||
exportFile,
|
||||
exportFileFailure,
|
||||
exportFileSuccess,
|
||||
getDimensionCategories,
|
||||
getDimensionCategoriesSuccess,
|
||||
getDiscussion,
|
||||
@ -18,11 +21,12 @@ import {
|
||||
catchError,
|
||||
flatMap,
|
||||
} from 'rxjs/operators';
|
||||
import { EMPTY, of } from 'rxjs';
|
||||
import { EMPTY, of, throwError } from 'rxjs';
|
||||
import { GetDiscussionService } from '../services/get-discussion.service';
|
||||
import { Router } from '@angular/router';
|
||||
import {
|
||||
selectCurrentDimension,
|
||||
selectCurrentDiscussion,
|
||||
selectSelectedParams,
|
||||
} from 'src/app/selectors/discussion.selectors';
|
||||
import { DimensionsService } from '../services/dimensions.service';
|
||||
@ -38,28 +42,6 @@ export class DiscussionEffects {
|
||||
private paragraphService: ParagraphService,
|
||||
private router: Router
|
||||
) {}
|
||||
// get$ = createEffect(() =>
|
||||
// this.actions$.pipe(
|
||||
// ofType(getDiscussion),
|
||||
// concatMap((action) =>
|
||||
// of(action).pipe(
|
||||
// withLatestFrom(this.store$.select(selectRouteParam('id')))
|
||||
// )
|
||||
// ),
|
||||
// flatMap(([_, id]) =>
|
||||
// this.getDiscussionService.getDiscussion(id!).pipe(
|
||||
// map((discussions) => {
|
||||
// console.log('Dupa!');
|
||||
// return discussionSuccess({ payload: discussions.posts });
|
||||
// }),
|
||||
// catchError(() => {
|
||||
// console.log('Dupa?');
|
||||
// return EMPTY;
|
||||
// })
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
// );
|
||||
get$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(getDiscussion),
|
||||
@ -106,16 +88,31 @@ export class DiscussionEffects {
|
||||
)
|
||||
);
|
||||
|
||||
// load$ = createEffect(
|
||||
// () =>
|
||||
// this.actions$.pipe(
|
||||
// ofType(ROUTER_NAVIGATED),
|
||||
// tap(() => {
|
||||
// if (this.router.url.includes('/topic/')) {
|
||||
// this.store$.dispatch(getDiscussion());
|
||||
// }
|
||||
// })
|
||||
// ),
|
||||
// { dispatch: false }
|
||||
// );
|
||||
exportFile$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(exportFile),
|
||||
withLatestFrom(
|
||||
this.store$.select(selectCurrentDimension),
|
||||
this.store$.select(selectCurrentDiscussion)
|
||||
),
|
||||
flatMap(([_, dimension, discussion]) =>
|
||||
this.getDiscussionService.exportFile(discussion, dimension).pipe(
|
||||
map((res) => {
|
||||
let blob = new Blob([res], { type: 'application/tsv' });
|
||||
let url = window.URL.createObjectURL(blob);
|
||||
let a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = 'export.tsv';
|
||||
a.click();
|
||||
a.remove();
|
||||
return exportFileSuccess();
|
||||
}),
|
||||
catchError(() => {
|
||||
this.store$.dispatch(exportFileFailure());
|
||||
return EMPTY;
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -109,6 +109,16 @@
|
||||
pliki <b>forum.xml</b> w każdym z podfolderów
|
||||
</p>
|
||||
<button nbButton nbStepperPrevious>Poprzedni krok</button>
|
||||
<button nbButton nbStepperNext>Następny krok</button>
|
||||
</nb-step>
|
||||
<nb-step label="Krok 5">
|
||||
<h5>Krok #5</h5>
|
||||
<p class="paragraph">
|
||||
Jeżeli nie masz dostępu do kopii zapasowej forum, to przykładowe
|
||||
forum możesz pobrać klikając
|
||||
<a download="forum.xml" href="assets/forum1.xml">tutaj</a>
|
||||
</p>
|
||||
<button nbButton nbStepperPrevious>Poprzedni krok</button>
|
||||
<button nbButton nbStepperNext disabled>Następny krok</button>
|
||||
</nb-step>
|
||||
</nb-stepper>
|
||||
@ -116,6 +126,6 @@
|
||||
</section>
|
||||
</nb-layout-column>
|
||||
<nb-layout-footer>
|
||||
Karolina Boczoń, Michał Romaszkin, Marcin Armacki 2020
|
||||
Karolina Boczoń, Michał Romaszkin, Marcin Armacki 2021
|
||||
</nb-layout-footer>
|
||||
</nb-layout>
|
||||
|
@ -1,13 +0,0 @@
|
||||
<div class="picker-container" *ngIf="data$ | async">
|
||||
<h1>
|
||||
Wybierz dyskusję z <i>{{ (data$ | async)?.name }}:</i>
|
||||
</h1>
|
||||
<nb-card
|
||||
*ngFor="let item of (data$ | async)?.discussions"
|
||||
class="picker-container__discussion"
|
||||
[accent]="getRandomColor()"
|
||||
(click)="onDiscussionClick(item.id)"
|
||||
>
|
||||
<h3 class="picker-container__disc-title">{{ item.title }}</h3>
|
||||
</nb-card>
|
||||
</div>
|
@ -1,8 +0,0 @@
|
||||
.picker-container {
|
||||
&__discussion {
|
||||
cursor: pointer;
|
||||
}
|
||||
&__disc-title {
|
||||
margin: 1rem;
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { SharedDataService } from '../../services/shared-data.service';
|
||||
import { Colors } from '../../_types/color';
|
||||
import { CustomForumData } from '../../_interfaces/customforumdata';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { NbMenuItem } from '@nebular/theme';
|
||||
import { Router } from '@angular/router';
|
||||
import { MapIdService } from 'src/app/services/map-id.service';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { State } from 'src/app/reducers';
|
||||
// import { selectData } from '../../selectors/discussion-chooser.selectors';
|
||||
// import { setDiscussion } from '../../actions/data.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'app-discussion-chooser',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
templateUrl: './discussion-chooser.component.html',
|
||||
styleUrls: ['./discussion-chooser.component.scss'],
|
||||
})
|
||||
export class DiscussionChooserComponent implements OnInit {
|
||||
public data: CustomForumData;
|
||||
colors: Colors[] = ['primary', 'danger', 'info', 'success', 'warning'];
|
||||
data$: Observable<CustomForumData>;
|
||||
|
||||
constructor(
|
||||
private sharedDataService: SharedDataService,
|
||||
private router: Router,
|
||||
private mapIdService: MapIdService,
|
||||
private store: Store<State>
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
// this.data$ = this.store.select(selectData);
|
||||
}
|
||||
|
||||
getRandomColor(): Colors {
|
||||
return this.colors[Math.floor(Math.random() * this.colors.length)];
|
||||
}
|
||||
|
||||
onDiscussionClick(id: number) {
|
||||
this.router.navigate([`/view/forum/${id}`]);
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
<!-- <div class="discussion-viewer">
|
||||
<div
|
||||
subheader
|
||||
class="discussion-viewer__buttons-container"
|
||||
[ngClass]="{ scrolled: scrollPosition.y > 40 }"
|
||||
>
|
||||
<button
|
||||
nbButton
|
||||
hero
|
||||
status="primary"
|
||||
class="discussion-viewer__save-button"
|
||||
(click)="onSaveChangesButtonClick(id)"
|
||||
>
|
||||
Zapisz zmiany
|
||||
</button>
|
||||
<button
|
||||
nbButton
|
||||
hero
|
||||
status="success"
|
||||
class="discussion-viewer__back-button"
|
||||
(click)="onBackButtonClick()"
|
||||
>
|
||||
Wróć do wyboru dyskusji
|
||||
</button>
|
||||
<button
|
||||
nbButton
|
||||
hero
|
||||
status="info"
|
||||
class="discussion-viewer__map-id-button"
|
||||
(click)="onMapIdClick()"
|
||||
>
|
||||
Zmapuj ID na dane z pliku
|
||||
</button>
|
||||
<button
|
||||
nbButton
|
||||
hero
|
||||
status="danger"
|
||||
*ngIf="displayNamesMode"
|
||||
(click)="resetDataMapping()"
|
||||
>
|
||||
Usuń zmapowane dane
|
||||
</button>
|
||||
<input id="input-for-id" type="file" (change)="fetchFile($event)" />
|
||||
</div>
|
||||
<div class="discussion-viewer__posts-container">
|
||||
<nb-card *ngFor="let item of discussion$ | async">
|
||||
<nb-card-header>
|
||||
{{ item.author | idToName: displayNamesMode:parsedNames }}
|
||||
</nb-card-header>
|
||||
<nb-card-body>
|
||||
<app-styled-paragraph
|
||||
*ngFor="let paragraph of item.message; let i = index"
|
||||
[message]="paragraph"
|
||||
[loadedLabel]="item.label[i]"
|
||||
[paragraphId]="item.para_id[i]"
|
||||
[discussionId]="id"
|
||||
[userEdited]="item.user_updated[i]"
|
||||
></app-styled-paragraph>
|
||||
</nb-card-body>
|
||||
</nb-card>
|
||||
</div>
|
||||
</div> -->
|
@ -1,27 +0,0 @@
|
||||
.discussion-viewer {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
|
||||
nb-card:first-of-type {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
&__buttons-container {
|
||||
position: fixed;
|
||||
margin: 0 -2.25rem;
|
||||
width: 100%;
|
||||
top: 4.75rem;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
background-color: white;
|
||||
box-shadow: 0px 10px 17px -15px rgba(0, 0, 0, 0.88);
|
||||
z-index: 10;
|
||||
button {
|
||||
margin: 1rem 0rem 1rem 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input[type="file"] {
|
||||
display: none;
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { GetDiscussionService } from '../../services/get-discussion.service';
|
||||
import { PredictedPost } from '../../_interfaces/predictedposts';
|
||||
import { Observable, Subject, Subscription } from 'rxjs';
|
||||
import { concatMap, defaultIfEmpty, map } from 'rxjs/operators';
|
||||
import { ParagraphService } from 'src/app/services/paragraph.service';
|
||||
import {
|
||||
NbToastrService,
|
||||
NbLayoutScrollService,
|
||||
NbScrollPosition,
|
||||
} from '@nebular/theme';
|
||||
import { parse } from 'papaparse';
|
||||
import { selectRouteParam, State } from 'src/app/reducers';
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
@Component({
|
||||
selector: 'app-discussion-viewer',
|
||||
templateUrl: './discussion-viewer.component.html',
|
||||
styleUrls: ['./discussion-viewer.component.scss'],
|
||||
})
|
||||
export class DiscussionViewerComponent {
|
||||
// data: PredictedPost[];
|
||||
// id: number;
|
||||
// subscriptionData: Subscription;
|
||||
// subscriptionId: Subscription;
|
||||
// displayNamesMode: boolean;
|
||||
// parsedNames: { id: number; name: string }[];
|
||||
// scrollPosition: NbScrollPosition;
|
||||
// constructor(
|
||||
// private getDiscussionService: GetDiscussionService,
|
||||
// private paragraphService: ParagraphService,
|
||||
// private router: Router,
|
||||
// private toastService: NbToastrService,
|
||||
// private scrollService: NbLayoutScrollService,
|
||||
// private store: Store<State>
|
||||
// ) {
|
||||
// this.scrollPosition = { x: 0, y: 0 };
|
||||
// }
|
||||
// discussion$: Observable<PredictedPost[]> = this.store.select((state) => {
|
||||
// return state.currentDiscussion;
|
||||
// });
|
||||
// ngOnInit(): void {
|
||||
// this.store.dispatch({
|
||||
// type: '[DiscussionViewer Component] Load Discussion',
|
||||
// });
|
||||
// this.store.select(selectRouteParam('id')).subscribe((id) => {
|
||||
// this.id = parseInt(id!);
|
||||
// });
|
||||
// this.scrollService
|
||||
// .onScroll()
|
||||
// .pipe(concatMap(() => this.scrollService.getPosition()))
|
||||
// .subscribe((result) => {
|
||||
// this.scrollPosition = result;
|
||||
// });
|
||||
// }
|
||||
// onBackButtonClick() {
|
||||
// this.router.navigate(['/view/discussions/']);
|
||||
// }
|
||||
// onSaveChangesButtonClick(id: number) {
|
||||
// this.paragraphService
|
||||
// .patchParagraphs(id)
|
||||
// ?.pipe(defaultIfEmpty())
|
||||
// .subscribe((result: any) => {
|
||||
// if (result === null) {
|
||||
// this.toastService.danger('', 'Brak zmian!', {
|
||||
// preventDuplicates: true,
|
||||
// icon: 'alert-circle',
|
||||
// });
|
||||
// } else {
|
||||
// this.data = result.posts;
|
||||
// this.toastService.success('', 'Zmiany zostały zapisane!', {
|
||||
// icon: 'checkmark-circle-2-outline',
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// onMapIdClick() {
|
||||
// const el: HTMLElement = document.getElementById(
|
||||
// 'input-for-id'
|
||||
// ) as HTMLElement;
|
||||
// el.click();
|
||||
// }
|
||||
// async fetchFile(event: Event) {
|
||||
// let parsedNamesFromArray: Array<{ id: number; name: string }>;
|
||||
// const target = event.target as HTMLInputElement;
|
||||
// const file = target.files![0];
|
||||
// try {
|
||||
// parsedNamesFromArray = await this.parseFile(file);
|
||||
// this.parsedNames = parsedNamesFromArray;
|
||||
// this.displayNamesMode = true;
|
||||
// } catch (e) {
|
||||
// this.toastService.danger('', e, {
|
||||
// icon: 'alert-circle',
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// parseFile(file: File): Promise<{ id: number; name: string }[]> {
|
||||
// return new Promise((resolve, reject) => {
|
||||
// parse(file, {
|
||||
// header: true,
|
||||
// skipEmptyLines: true,
|
||||
// dynamicTyping: true,
|
||||
// complete: (result) => {
|
||||
// if (result.errors.length > 0) {
|
||||
// reject('Błąd przy parsowaniu pliku');
|
||||
// }
|
||||
// resolve(result.data as { id: number; name: string }[]);
|
||||
// },
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
// resetDataMapping() {
|
||||
// this.displayNamesMode = false;
|
||||
// }
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { MainViewComponent } from './main-view.component';
|
||||
import { DiscussionChooserComponent } from './discussion-chooser/discussion-chooser.component';
|
||||
import { DiscussionViewerComponent } from './discussion-viewer/discussion-viewer.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: MainViewComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'discussions',
|
||||
component: DiscussionChooserComponent,
|
||||
},
|
||||
{
|
||||
path: 'forum/:id',
|
||||
component: DiscussionViewerComponent,
|
||||
},
|
||||
{
|
||||
path: 'visualize/:id',
|
||||
loadChildren: () =>
|
||||
import('./visualize-forum/visualize-forum.module').then(
|
||||
(m) => m.VisualizeForumModule
|
||||
),
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'discussions',
|
||||
pathMatch: 'full',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class MainViewRoutingModule {}
|
@ -1,28 +0,0 @@
|
||||
<nb-layout>
|
||||
<nb-layout-header fixed>
|
||||
<div class="actions-container">
|
||||
<nb-actions>
|
||||
<nb-action
|
||||
icon="menu"
|
||||
(click)="toggleSidebar()"
|
||||
nbTooltip="Schowaj/Pokaż panel menu"
|
||||
></nb-action>
|
||||
<nb-action>nkadf</nb-action>
|
||||
</nb-actions>
|
||||
<nb-actions>
|
||||
<nb-action
|
||||
icon="power"
|
||||
(click)="logout()"
|
||||
nbTooltip="Wróć do strony początkowej"
|
||||
>Wyloguj</nb-action
|
||||
>
|
||||
</nb-actions>
|
||||
</div>
|
||||
</nb-layout-header>
|
||||
<nb-sidebar tag="main" responsive>
|
||||
<nb-menu [items]="items"></nb-menu>
|
||||
</nb-sidebar>
|
||||
<nb-layout-column>
|
||||
<router-outlet></router-outlet>
|
||||
</nb-layout-column>
|
||||
</nb-layout>
|
@ -1,6 +0,0 @@
|
||||
.actions-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
justify-content: space-between;
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { NbSidebarService, NbMenuItem } from '@nebular/theme';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { State } from '../reducers';
|
||||
// import { selectDiscussions } from '../selectors/discussion-chooser.selectors';
|
||||
|
||||
@Component({
|
||||
selector: 'app-main-view',
|
||||
templateUrl: './main-view.component.html',
|
||||
styleUrls: ['./main-view.component.scss'],
|
||||
})
|
||||
export class MainViewComponent implements OnInit {
|
||||
items: NbMenuItem[];
|
||||
menuItemsSub: Subscription;
|
||||
discussions$: Observable<{ id: number; title: string }[]>;
|
||||
|
||||
constructor(
|
||||
private sidebarService: NbSidebarService,
|
||||
private router: Router,
|
||||
private store: Store<State>
|
||||
) {}
|
||||
|
||||
toggleSidebar() {
|
||||
this.sidebarService.toggle(true, 'main');
|
||||
}
|
||||
|
||||
logout() {
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
// this.store.select(selectDiscussions).subscribe((discussions) => {
|
||||
// const availableDiscussions = discussions.map(
|
||||
// (discussion): NbMenuItem => ({
|
||||
// title: discussion.title,
|
||||
// link: `/view/forum/${discussion.id}`,
|
||||
// })
|
||||
// );
|
||||
// const availableVisualizations = discussions.map(
|
||||
// (discussion): NbMenuItem => ({
|
||||
// title: discussion.title,
|
||||
// link: `/view/visualize/${discussion.id}`,
|
||||
// })
|
||||
// );
|
||||
// this.items = [
|
||||
// {
|
||||
// title: 'Dyskusje',
|
||||
// link: '/view/discussions',
|
||||
// icon: {
|
||||
// icon: 'message-square',
|
||||
// },
|
||||
// children: availableDiscussions,
|
||||
// },
|
||||
// {
|
||||
// title: 'Wizualizacje',
|
||||
// icon: {
|
||||
// icon: 'trending-up',
|
||||
// },
|
||||
// children: availableVisualizations,
|
||||
// },
|
||||
// ];
|
||||
// });
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { MainViewComponent } from './main-view.component';
|
||||
import { DiscussionChooserComponent } from './discussion-chooser/discussion-chooser.component';
|
||||
import { MainViewRoutingModule } from './main-view-routing.module';
|
||||
|
||||
import { DiscussionViewerComponent } from './discussion-viewer/discussion-viewer.component';
|
||||
import { GetDiscussionService } from '../services/get-discussion.service';
|
||||
import { ParagraphService } from '../services/paragraph.service';
|
||||
import { MapIdService } from '../services/map-id.service';
|
||||
// import { StyledParagraphComponent } from './styled-paragraph/styled-paragraph.component';
|
||||
import { IdToNamePipe } from '../_pipes/id-to-name.pipe';
|
||||
import { DiscussionEffects } from '../effects/discussion.effect';
|
||||
|
||||
import {
|
||||
NbLayoutModule,
|
||||
NbActionsModule,
|
||||
NbSidebarModule,
|
||||
NbTooltipModule,
|
||||
NbCardModule,
|
||||
NbMenuModule,
|
||||
NbButtonModule,
|
||||
NbSelectModule,
|
||||
NbIconModule,
|
||||
} from '@nebular/theme';
|
||||
import { EffectsModule } from '@ngrx/effects';
|
||||
import { GetVisualizationDataService } from '../services/get-visualization-data.service';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
MainViewComponent,
|
||||
DiscussionChooserComponent,
|
||||
DiscussionViewerComponent,
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
MainViewRoutingModule,
|
||||
NbLayoutModule,
|
||||
NbActionsModule,
|
||||
NbSidebarModule,
|
||||
NbTooltipModule,
|
||||
NbCardModule,
|
||||
NbMenuModule,
|
||||
NbButtonModule,
|
||||
NbSelectModule,
|
||||
NbIconModule,
|
||||
EffectsModule.forFeature([DiscussionEffects]),
|
||||
],
|
||||
providers: [GetDiscussionService, ParagraphService, MapIdService],
|
||||
})
|
||||
export class MainViewModule {}
|
@ -1,16 +0,0 @@
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { VisualizeForumComponent } from './visualize-forum.component';
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: VisualizeForumComponent,
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class VisualizeForumRoutingModule {}
|
@ -1 +0,0 @@
|
||||
<div id="tree" #tree></div>
|
@ -1,18 +0,0 @@
|
||||
::ng-deep .link {
|
||||
fill: none;
|
||||
stroke: #000;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
::ng-deep .tooltip {
|
||||
width: 25rem;
|
||||
background-color: #ffffff;
|
||||
border: 0.0625rem solid #e4e9f2;
|
||||
border-radius: 0.25rem;
|
||||
padding: 1rem;
|
||||
max-height: 20rem;
|
||||
overflow: hidden;
|
||||
h6 {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
@ -1,153 +0,0 @@
|
||||
import {
|
||||
Component,
|
||||
OnDestroy,
|
||||
ViewChild,
|
||||
ElementRef,
|
||||
AfterViewInit,
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { GetVisualizationDataService } from '../../services/get-visualization-data.service';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { concatMap } from 'rxjs/operators';
|
||||
import { Post } from 'src/app/_interfaces/post';
|
||||
import * as d3 from 'd3';
|
||||
import maked3hierarchy from '../../_functions/maked3hierarchy';
|
||||
|
||||
@Component({
|
||||
selector: 'visualize-forum',
|
||||
templateUrl: './visualize-forum.component.html',
|
||||
styleUrls: ['./visualize-forum.component.scss'],
|
||||
})
|
||||
export class VisualizeForumComponent implements AfterViewInit, OnDestroy {
|
||||
private subscription: Subscription;
|
||||
private data: Post[];
|
||||
private hierarchizedData: Post[];
|
||||
@ViewChild('tree', { read: ElementRef })
|
||||
private treeContainer: ElementRef;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private getDataService: GetVisualizationDataService
|
||||
) {}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.subscription = this.route.params
|
||||
.pipe(concatMap((params) => this.getDataService.getDiscussion(params.id)))
|
||||
.subscribe((result) => {
|
||||
this.initializeData(result.posts);
|
||||
this.generateGraph();
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.subscription.unsubscribe();
|
||||
}
|
||||
|
||||
private initializeData(data: Post[]): void {
|
||||
this.data = data;
|
||||
this.hierarchizedData = maked3hierarchy(data);
|
||||
}
|
||||
|
||||
private generateGraph(): void {
|
||||
/* ToDo: Add option to change sizes */
|
||||
const margin = { top: 50, right: 90, bottom: 30, left: 90 };
|
||||
const width = 860 - margin.left - margin.right;
|
||||
const height = 500 - margin.top - margin.bottom;
|
||||
|
||||
const hierarchizedNodes = d3.hierarchy<Post>(this.hierarchizedData[0]);
|
||||
d3.tree().size([width, height])(hierarchizedNodes);
|
||||
const element = this.treeContainer.nativeElement;
|
||||
|
||||
/* Clear previous graph */
|
||||
d3.selectAll(`#tree > *`).remove();
|
||||
/* Create SVG */
|
||||
const svg = d3
|
||||
.select(element)
|
||||
.append('svg')
|
||||
.attr('width', width + margin.left + margin.right)
|
||||
.attr('height', height + margin.top + margin.bottom);
|
||||
|
||||
const group = svg
|
||||
.append('g')
|
||||
.attr('transform', `translate(${margin.left}, ${margin.top})`);
|
||||
|
||||
const gLink = group.append('g').attr('class', 'links');
|
||||
const gNode = group.append('g').attr('class', 'nodes');
|
||||
|
||||
/* Custom tooltip */
|
||||
const tooltip = d3
|
||||
.select(element)
|
||||
.append('div')
|
||||
.attr('class', 'tooltip')
|
||||
.style('position', 'absolute')
|
||||
.style('opacity', 0);
|
||||
|
||||
/* Select all nodes and pass data into them */
|
||||
const node = gNode
|
||||
.selectAll('g.nodes')
|
||||
.data(hierarchizedNodes.descendants());
|
||||
|
||||
/* Select all links and pass data into them */
|
||||
const link = gLink.selectAll('g.links').data(hierarchizedNodes.links());
|
||||
|
||||
/* 'Enter' into node, style it properly and create tooltip on hover */
|
||||
const nodeEnter = node.enter().append('g').classed('node', true);
|
||||
nodeEnter
|
||||
.append('circle')
|
||||
.attr('cx', (d: any) => d.x)
|
||||
.attr('cy', (d: any) => d.y)
|
||||
.attr('r', 25)
|
||||
.style('fill', '#fff')
|
||||
.style('stroke', '#ccc');
|
||||
|
||||
nodeEnter
|
||||
.append('text')
|
||||
.attr('x', (d: any) => d.x)
|
||||
.attr('y', (d: any) => d.y + 5)
|
||||
.attr('text-anchor', 'middle')
|
||||
.attr('class', 'h6')
|
||||
.text((d: any) => d.data.id);
|
||||
|
||||
nodeEnter
|
||||
.on('mouseover', (d) => {
|
||||
tooltip.transition().duration(400).style('opacity', 1);
|
||||
tooltip
|
||||
.html(
|
||||
/* HTML */
|
||||
`
|
||||
<h6>Wiadomość:</h6>
|
||||
<p>${d.data.message}</p>
|
||||
`
|
||||
)
|
||||
// .style('width', '15rem')
|
||||
// .style('max-height', '10rem')
|
||||
// .style('overflow', 'hidden')
|
||||
// .style('text-overflow', 'ellipsis')
|
||||
// .style('background-color', '#fff')
|
||||
// .style('border', '1px solid black')
|
||||
.style('left', `${d3.event.pageX}px`)
|
||||
.style('top', `${d3.event.pageY}px`);
|
||||
})
|
||||
.on('mouseout', function (d) {
|
||||
tooltip
|
||||
.transition()
|
||||
.duration(400)
|
||||
.style('opacity', 0)
|
||||
.style('top', '0')
|
||||
.style('left', '0');
|
||||
})
|
||||
.on('mousemove', function (d) {
|
||||
return tooltip
|
||||
.style('top', `${d3.event.pageY - 55}px`)
|
||||
.style('left', `${d3.event.pageX + 30}px`);
|
||||
});
|
||||
|
||||
/* 'Enter' into links and style them properly */
|
||||
const linkEnter = link.enter().append('line').classed('link', true);
|
||||
linkEnter
|
||||
.attr('x1', (d: any) => d.source.x)
|
||||
.attr('y1', (d: any) => d.source.y)
|
||||
.attr('x2', (d: any) => d.target.x)
|
||||
.attr('y2', (d: any) => d.target.y);
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { VisualizeForumComponent } from './visualize-forum.component';
|
||||
import { VisualizeForumRoutingModule } from './visualize-forum-routing.module';
|
||||
import { GetVisualizationDataService } from '../../services/get-visualization-data.service';
|
||||
|
||||
@NgModule({
|
||||
declarations: [VisualizeForumComponent],
|
||||
imports: [CommonModule, VisualizeForumRoutingModule],
|
||||
providers: [GetVisualizationDataService],
|
||||
})
|
||||
export class VisualizeForumModule {}
|
@ -1,6 +1,9 @@
|
||||
.picker-container {
|
||||
&__discussion {
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
}
|
||||
&__disc-title {
|
||||
margin: 1rem;
|
||||
|
@ -5,13 +5,10 @@
|
||||
}
|
||||
|
||||
::ng-deep .tooltip {
|
||||
width: 25rem;
|
||||
background-color: #ffffff;
|
||||
border: 0.0625rem solid #e4e9f2;
|
||||
border-radius: 0.25rem;
|
||||
padding: 1rem;
|
||||
max-height: 20rem;
|
||||
overflow: hidden;
|
||||
h6 {
|
||||
margin: 0;
|
||||
}
|
||||
|
@ -113,7 +113,12 @@ export class GraphComponent implements AfterViewInit, OnDestroy {
|
||||
|
||||
nodeEnter
|
||||
.on('mouseover', (d) => {
|
||||
tooltip.transition().duration(400).style('opacity', 1);
|
||||
tooltip
|
||||
.transition()
|
||||
.duration(400)
|
||||
.style('height', 'auto')
|
||||
.style('opacity', 1)
|
||||
.style('overflow', 'auto');
|
||||
tooltip
|
||||
.html(
|
||||
/* HTML */
|
||||
@ -122,12 +127,6 @@ export class GraphComponent implements AfterViewInit, OnDestroy {
|
||||
<p>${d.data.message}</p>
|
||||
`
|
||||
)
|
||||
// .style('width', '15rem')
|
||||
// .style('max-height', '10rem')
|
||||
// .style('overflow', 'hidden')
|
||||
// .style('text-overflow', 'ellipsis')
|
||||
// .style('background-color', '#fff')
|
||||
// .style('border', '1px solid black')
|
||||
.style('left', `${d3.event.pageX}px`)
|
||||
.style('top', `${d3.event.pageY}px`);
|
||||
})
|
||||
@ -136,12 +135,14 @@ export class GraphComponent implements AfterViewInit, OnDestroy {
|
||||
.transition()
|
||||
.duration(400)
|
||||
.style('opacity', 0)
|
||||
.style('height', '0')
|
||||
.style('top', '0')
|
||||
.style('left', '0');
|
||||
.style('left', '0')
|
||||
.style('overflow', 'hidden');
|
||||
})
|
||||
.on('mousemove', function (d) {
|
||||
return tooltip
|
||||
.style('top', `${d3.event.pageY - 55}px`)
|
||||
.style('top', `90px`)
|
||||
.style('left', `${d3.event.pageX + 30}px`);
|
||||
});
|
||||
|
||||
|
@ -6,8 +6,9 @@
|
||||
<nb-list-item
|
||||
*ngFor="let item of dimensions$ | async; let i = index"
|
||||
(click)="dimension(item.id)"
|
||||
class="list-item"
|
||||
>
|
||||
{{ item.name }}
|
||||
<span class="subtitle">{{ item.name }}</span>
|
||||
</nb-list-item>
|
||||
</nb-list>
|
||||
<nb-card-footer>
|
||||
|
@ -0,0 +1,6 @@
|
||||
.list-item {
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
}
|
@ -1,38 +1,53 @@
|
||||
<nb-layout class="discussion-viewer">
|
||||
<nb-layout-header
|
||||
subheader
|
||||
class="discussion-viewer__buttons-container"
|
||||
withScroll
|
||||
>
|
||||
<button
|
||||
nbButton
|
||||
hero
|
||||
status="success"
|
||||
class="discussion-viewer__back-button"
|
||||
routerLink="../"
|
||||
>
|
||||
Wróć do wyboru dyskusji
|
||||
</button>
|
||||
<button nbButton hero status="info" (click)="mapId()">
|
||||
Zmapuj dane z pliku users.xml
|
||||
</button>
|
||||
<button nbButton hero status="danger" (click)="resetDataMapping()">
|
||||
Usuń zmapowane dane
|
||||
</button>
|
||||
<input
|
||||
id="input-for-id"
|
||||
type="file"
|
||||
(change)="fetchFile($event)"
|
||||
accept=".xml"
|
||||
/>
|
||||
<nb-select
|
||||
[selected]="currentDimension$ | async"
|
||||
(selectedChange)="changeCurrentDimension($event)"
|
||||
>
|
||||
<nb-option *ngFor="let item of dimensions$ | async" [value]="item.id">{{
|
||||
item.name
|
||||
}}</nb-option>
|
||||
</nb-select>
|
||||
<nb-layout-header subheader class="discussion-viewer__header" withScroll>
|
||||
<div class="discussion-viewer__button-container">
|
||||
<div>
|
||||
<button nbButton hero status="info" (click)="mapId()">
|
||||
Zmapuj dane z pliku users.xml
|
||||
</button>
|
||||
<button
|
||||
nbButton
|
||||
hero
|
||||
status="danger"
|
||||
(click)="resetDataMapping()"
|
||||
*ngIf="displayNamesMode"
|
||||
>
|
||||
Usuń zmapowane dane
|
||||
</button>
|
||||
<input
|
||||
id="input-for-id"
|
||||
type="file"
|
||||
(change)="fetchFile($event)"
|
||||
accept=".xml"
|
||||
/>
|
||||
<nb-select
|
||||
[selected]="currentDimension$ | async"
|
||||
(selectedChange)="changeCurrentDimension($event)"
|
||||
class="discussion-viewer__dimension-select"
|
||||
>
|
||||
<nb-option [value]="0"> Brak wymiaru </nb-option>
|
||||
<nb-option
|
||||
*ngFor="let item of dimensions$ | async"
|
||||
[value]="item.id"
|
||||
>{{ item.name }}</nb-option
|
||||
>
|
||||
</nb-select>
|
||||
<button nbButton outline status="primary" (click)="exportTSV()">
|
||||
Eksportuj dyskusję do pliku tsv
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
nbButton
|
||||
hero
|
||||
status="success"
|
||||
class="discussion-viewer__back-button"
|
||||
routerLink="../"
|
||||
>
|
||||
Wróć do wyboru dyskusji
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nb-layout-header>
|
||||
|
||||
<nb-sidebar containerFixed>
|
||||
@ -41,6 +56,7 @@
|
||||
<nb-list-item
|
||||
*ngFor="let item of (items$ | async)!.discussions"
|
||||
(click)="goToDiscussion(item.id)"
|
||||
class="subtitle discussion-item"
|
||||
>
|
||||
{{ item.title }}
|
||||
</nb-list-item>
|
||||
@ -48,6 +64,7 @@
|
||||
<nb-list-item
|
||||
*ngFor="let item of (items$ | async)!.discussions"
|
||||
(click)="goToVisualization(item.id)"
|
||||
class="subtitle discussion-item"
|
||||
>
|
||||
{{ item.title }}
|
||||
</nb-list-item>
|
||||
|
@ -9,17 +9,38 @@
|
||||
}
|
||||
}
|
||||
|
||||
&__buttons-container {
|
||||
&__header {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
width: calc(100% - 250px);
|
||||
top: 4.75rem;
|
||||
background-color: white;
|
||||
box-shadow: 0px 10px 17px -15px rgba(0, 0, 0, 0.88);
|
||||
z-index: 10;
|
||||
button {
|
||||
margin: 1rem 1rem 1rem 0rem;
|
||||
}
|
||||
|
||||
&__button-container {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
> div {
|
||||
display: flex;
|
||||
button {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.discussion-item {
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
}
|
||||
|
||||
&__dimension-select {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
input[type="file"] {
|
||||
|
@ -2,9 +2,9 @@ import { Component } from '@angular/core';
|
||||
|
||||
import { concatMap } from 'rxjs/operators';
|
||||
import {
|
||||
exportFile,
|
||||
getDimensionCategories,
|
||||
setCurrentDimensionId,
|
||||
setCurrentDiscussion,
|
||||
setCurrentDiscussionId,
|
||||
} from 'src/app/actions/discussion.actions';
|
||||
import { NbToastrService, NbLayoutScrollService } from '@nebular/theme';
|
||||
@ -72,7 +72,7 @@ export class ViewComponent {
|
||||
|
||||
goToDiscussion(id: any) {
|
||||
this.store.dispatch(setCurrentDiscussionId({ id }));
|
||||
window.location.reload();
|
||||
this.store.dispatch(getDiscussion());
|
||||
}
|
||||
|
||||
goToVisualization(id: any) {
|
||||
@ -94,6 +94,9 @@ export class ViewComponent {
|
||||
}));
|
||||
this.parsedNames = users;
|
||||
this.displayNamesMode = true;
|
||||
this.toastService.success('', 'Pomyślnie zmapowano dane!', {
|
||||
icon: 'checkmark-circle-2-outline',
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
@ -102,6 +105,10 @@ export class ViewComponent {
|
||||
this.displayNamesMode = false;
|
||||
}
|
||||
|
||||
exportTSV() {
|
||||
this.store.dispatch(exportFile());
|
||||
}
|
||||
|
||||
changeCurrentDimension(event: number) {
|
||||
this.store.dispatch(setCurrentDimensionId({ id: event }));
|
||||
this.store.dispatch(loadDiscussions());
|
||||
|
@ -5,6 +5,7 @@
|
||||
<nb-layout>
|
||||
<nb-layout-column class="editDimension__leftColumn">
|
||||
<h3>Edytuj wymiar</h3>
|
||||
<label class="label editDimension__name-label">Nazwa wymiaru</label>
|
||||
<input
|
||||
fullWidth
|
||||
nbInput
|
||||
@ -12,11 +13,13 @@
|
||||
formControlName="name"
|
||||
class="editDimension__name"
|
||||
/>
|
||||
<label class="label editDimension__description-label">Opis wymiaru</label>
|
||||
<textarea
|
||||
nbInput
|
||||
fullWidth
|
||||
placeholder="Opis wymiaru"
|
||||
formControlName="description"
|
||||
class="editDimension__description"
|
||||
></textarea>
|
||||
</nb-layout-column>
|
||||
<nb-layout-column>
|
||||
@ -35,6 +38,7 @@
|
||||
outline
|
||||
status="danger"
|
||||
class="editDimension__button"
|
||||
(click)="deleteDimension()"
|
||||
>
|
||||
Usuń wymiar
|
||||
</button>
|
||||
|
@ -10,4 +10,11 @@
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
&__name-label,
|
||||
&__description-label {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
&__description-label {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
clearSelectedDimension,
|
||||
getSelectedDimension,
|
||||
removeCategoryFromDimension,
|
||||
removeSelectedDimension,
|
||||
updateSelectedDimension,
|
||||
} from 'src/app/actions/dimension.actions';
|
||||
import {
|
||||
@ -20,6 +21,8 @@ import {
|
||||
} from 'src/app/selectors/dimension.selectors';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Category } from 'src/app/reducers/dimension.reducers';
|
||||
import { NbDialogService } from '@nebular/theme';
|
||||
import { DeleteDialogComponent } from '../delete-dialog/delete-dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'edit-dimension',
|
||||
@ -39,7 +42,8 @@ export class EditDimensionComponent implements OnInit, OnDestroy {
|
||||
private fb: FormBuilder,
|
||||
private store: Store<State>,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute
|
||||
private route: ActivatedRoute,
|
||||
private dialogService: NbDialogService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
@ -107,4 +111,15 @@ export class EditDimensionComponent implements OnInit, OnDestroy {
|
||||
this.store.dispatch(clearSelectedDimension());
|
||||
this.editDimensionForm.reset();
|
||||
}
|
||||
|
||||
deleteDimension() {
|
||||
this.dialogService
|
||||
.open(DeleteDialogComponent, { context: { type: 'wymiar' } })
|
||||
.onClose.subscribe((res: boolean) => {
|
||||
if (res) {
|
||||
this.store.dispatch(removeSelectedDimension());
|
||||
this.router.navigate(['../'], { relativeTo: this.route });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { NbAuthService, NbTokenService } from '@nebular/auth';
|
||||
@ -18,6 +19,7 @@ export class MyProfileComponent implements OnInit {
|
||||
|
||||
logout() {
|
||||
this.tokenService.clear();
|
||||
this.authService.logout('email');
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,10 @@ export const selectCurrentDimension = createSelector(
|
||||
selectFeature,
|
||||
(state) => state.selectedDimension
|
||||
);
|
||||
export const selectCurrentDiscussion = createSelector(
|
||||
selectFeature,
|
||||
(state) => state.selectedDiscussion
|
||||
);
|
||||
export const selectCurrentCategories = createSelector(
|
||||
selectFeature,
|
||||
(state) => state.currentCategories
|
||||
|
@ -2,6 +2,7 @@ import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import url from './url';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@Injectable()
|
||||
export class GetDiscussionService {
|
||||
@ -24,4 +25,17 @@ export class GetDiscussionService {
|
||||
bindClassfier(id: number) {
|
||||
return this.http.get<any>(`${url}/classifier/${id}`);
|
||||
}
|
||||
|
||||
exportFile(discussionId: number, dimensionId: number) {
|
||||
return this.http.post<any>(
|
||||
`${url}/export/`,
|
||||
{
|
||||
discussion: discussionId,
|
||||
dimension: dimensionId,
|
||||
},
|
||||
{
|
||||
responseType: 'arraybuffer' as 'json',
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
268
frontend/src/assets/forum1.xml
Normal file
268
frontend/src/assets/forum1.xml
Normal file
@ -0,0 +1,268 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<activity id="6" moduleid="6" modulename="forum" contextid="76">
|
||||
<forum id="6">
|
||||
<type>general</type>
|
||||
<name>Najnowsze technologie</name>
|
||||
<intro></intro>
|
||||
<introformat>1</introformat>
|
||||
<assessed>0</assessed>
|
||||
<assesstimestart>0</assesstimestart>
|
||||
<assesstimefinish>0</assesstimefinish>
|
||||
<scale>100</scale>
|
||||
<maxbytes>512000</maxbytes>
|
||||
<maxattachments>9</maxattachments>
|
||||
<forcesubscribe>0</forcesubscribe>
|
||||
<trackingtype>1</trackingtype>
|
||||
<rsstype>0</rsstype>
|
||||
<rssarticles>0</rssarticles>
|
||||
<timemodified>1593091872</timemodified>
|
||||
<warnafter>0</warnafter>
|
||||
<blockafter>0</blockafter>
|
||||
<blockperiod>0</blockperiod>
|
||||
<completiondiscussions>0</completiondiscussions>
|
||||
<completionreplies>0</completionreplies>
|
||||
<completionposts>0</completionposts>
|
||||
<displaywordcount>0</displaywordcount>
|
||||
<lockdiscussionafter>0</lockdiscussionafter>
|
||||
<discussions>
|
||||
<discussion id="9">
|
||||
<name>Najnowsze technologie - dyskusja</name>
|
||||
<firstpost>30</firstpost>
|
||||
<userid>2</userid>
|
||||
<groupid>-1</groupid>
|
||||
<assessed>0</assessed>
|
||||
<timemodified>1593093116</timemodified>
|
||||
<usermodified>2</usermodified>
|
||||
<timestart>0</timestart>
|
||||
<timeend>0</timeend>
|
||||
<pinned>0</pinned>
|
||||
<posts>
|
||||
<post id="30">
|
||||
<parent>0</parent>
|
||||
<userid>2</userid>
|
||||
<created>1593092060</created>
|
||||
<modified>1593092060</modified>
|
||||
<mailed>1</mailed>
|
||||
<subject>Najnowsze technologie - dyskusja</subject>
|
||||
<message><p>Czy tworząc nowy system powinniśmy korzystać z najnowszych technologii dostępnych w branży?</p><p>Odpowiedź uzasadnij.<br /></p></message>
|
||||
<messageformat>1</messageformat>
|
||||
<messagetrust>0</messagetrust>
|
||||
<attachment></attachment>
|
||||
<totalscore>0</totalscore>
|
||||
<mailnow>0</mailnow>
|
||||
<ratings>
|
||||
</ratings>
|
||||
</post>
|
||||
<post id="31">
|
||||
<parent>30</parent>
|
||||
<userid>7</userid>
|
||||
<created>1593092371</created>
|
||||
<modified>1593092371</modified>
|
||||
<mailed>1</mailed>
|
||||
<subject>Re: Najnowsze technologie - dyskusja</subject>
|
||||
<message><p>Uważam, że jak najbardziej. Należy zawsze inwestować w nowoczesne rozwiązania. Trzeba za wszelką cenę wyprzedzić konkurencję i promować nowatorskie podejście.<br /></p></message>
|
||||
<messageformat>1</messageformat>
|
||||
<messagetrust>0</messagetrust>
|
||||
<attachment></attachment>
|
||||
<totalscore>0</totalscore>
|
||||
<mailnow>0</mailnow>
|
||||
<ratings>
|
||||
</ratings>
|
||||
</post>
|
||||
<post id="32">
|
||||
<parent>30</parent>
|
||||
<userid>8</userid>
|
||||
<created>1593092625</created>
|
||||
<modified>1593092625</modified>
|
||||
<mailed>1</mailed>
|
||||
<subject>Re: Najnowsze technologie - dyskusja</subject>
|
||||
<message><p>Nie mogę się z tym zgodzić. Uważam, że znacznie rozsądniej jest postawić na sprawdzone rozwiązania. Celem nadrzędnym jest tworzenie stabilnych systemów o niskiej awaryjności, a nie wyścig zbrojeń w tworzeniu nowatorskich rozwiązań. Rozumiem, że w grę wchodzą też umowy i zobowiązania wobec klienta. W ogólnym rozrachunku jednak zdecydowanie nie popieram.<br /></message>
|
||||
<messageformat>1</messageformat>
|
||||
<messagetrust>0</messagetrust>
|
||||
<attachment></attachment>
|
||||
<totalscore>0</totalscore>
|
||||
<mailnow>0</mailnow>
|
||||
<ratings>
|
||||
</ratings>
|
||||
</post>
|
||||
<post id="33">
|
||||
<parent>32</parent>
|
||||
<userid>9</userid>
|
||||
<created>1593092682</created>
|
||||
<modified>1593092682</modified>
|
||||
<mailed>1</mailed>
|
||||
<subject>Re: Najnowsze technologie - dyskusja</subject>
|
||||
<message><p>A co jeśli to klient chce postawić na nowoczesną technologię?<br /></p></message>
|
||||
<messageformat>1</messageformat>
|
||||
<messagetrust>0</messagetrust>
|
||||
<attachment></attachment>
|
||||
<totalscore>0</totalscore>
|
||||
<mailnow>0</mailnow>
|
||||
<ratings>
|
||||
</ratings>
|
||||
</post>
|
||||
<post id="34">
|
||||
<parent>33</parent>
|
||||
<userid>8</userid>
|
||||
<created>1593092794</created>
|
||||
<modified>1593092794</modified>
|
||||
<mailed>1</mailed>
|
||||
<subject>Re: Najnowsze technologie - dyskusja</subject>
|
||||
<message><p>Spotkałem się kiedyś w pracy w z takim przypadkiem. Klient zazwyczaj nie przykłada wagi do tego jakie rozwiązania są stosowane. Ważnym jest, by system działał poprawnie i spełniał oczekiwania.<br /></p></message>
|
||||
<messageformat>1</messageformat>
|
||||
<messagetrust>0</messagetrust>
|
||||
<attachment></attachment>
|
||||
<totalscore>0</totalscore>
|
||||
<mailnow>0</mailnow>
|
||||
<ratings>
|
||||
</ratings>
|
||||
</post>
|
||||
<post id="35">
|
||||
<parent>30</parent>
|
||||
<userid>2</userid>
|
||||
<created>1593093116</created>
|
||||
<modified>1593093116</modified>
|
||||
<mailed>1</mailed>
|
||||
<subject>Re: Najnowsze technologie - dyskusja</subject>
|
||||
<message><p>Sam zgadzam się z tym, że należy postawić na nowe rozwiązania i nowoczesną technologię, która w wielu przypadkach jest równoznaczna z ułatwieniem życia programisty i zapewnieniu wielu komfortowych rozwiązań, które odciążają twórcę oprogramowania i pozwalają skupić się na innych aspektach tworzonego sytemu, lecz nie jestem do końca przekonany. Głównie dlatego, że nowoczesna technologia musi się odpowiednio wdrożyć i osiągnąć pewien poziom stabilności. W ostatecznym rozrachunku uważam, że należy dobierać narzędzia adekwatnie do problemu, który chcemy rozwiązać.<br /></message>
|
||||
<messageformat>1</messageformat>
|
||||
<messagetrust>0</messagetrust>
|
||||
<attachment></attachment>
|
||||
<totalscore>0</totalscore>
|
||||
<mailnow>0</mailnow>
|
||||
<ratings>
|
||||
</ratings>
|
||||
</post>
|
||||
</posts>
|
||||
<discussion_subs>
|
||||
<discussion_sub id="21">
|
||||
<userid>2</userid>
|
||||
<preference>1593092060</preference>
|
||||
</discussion_sub>
|
||||
<discussion_sub id="22">
|
||||
<userid>7</userid>
|
||||
<preference>1593092371</preference>
|
||||
</discussion_sub>
|
||||
<discussion_sub id="23">
|
||||
<userid>8</userid>
|
||||
<preference>1593092625</preference>
|
||||
</discussion_sub>
|
||||
<discussion_sub id="24">
|
||||
<userid>9</userid>
|
||||
<preference>1593092682</preference>
|
||||
</discussion_sub>
|
||||
</discussion_subs>
|
||||
</discussion>
|
||||
<discussion id="10">
|
||||
<name>Czy komputer w lodówce to już współczesność?</name>
|
||||
<firstpost>36</firstpost>
|
||||
<userid>2</userid>
|
||||
<groupid>-1</groupid>
|
||||
<assessed>0</assessed>
|
||||
<timemodified>1593096052</timemodified>
|
||||
<usermodified>9</usermodified>
|
||||
<timestart>0</timestart>
|
||||
<timeend>0</timeend>
|
||||
<pinned>0</pinned>
|
||||
<posts>
|
||||
<post id="36">
|
||||
<parent>0</parent>
|
||||
<userid>2</userid>
|
||||
<created>1593095765</created>
|
||||
<modified>1593095765</modified>
|
||||
<mailed>1</mailed>
|
||||
<subject>Czy komputer w lodówce to już współczesność?</subject>
|
||||
<message><p>Kiedyś żartobliwie mówiono, że niedługo komputer będzie już w każdej
|
||||
lodówce. Czy to "niedługo" jest już "dzisiaj"? Jakie zastosowania
|
||||
informatyki wdarły się do życia codziennego w taki sposób, że tego nie
|
||||
zauważamy?<br /></p></message>
|
||||
<messageformat>1</messageformat>
|
||||
<messagetrust>0</messagetrust>
|
||||
<attachment></attachment>
|
||||
<totalscore>0</totalscore>
|
||||
<mailnow>0</mailnow>
|
||||
<ratings>
|
||||
</ratings>
|
||||
</post>
|
||||
<post id="37">
|
||||
<parent>36</parent>
|
||||
<userid>7</userid>
|
||||
<created>1593095882</created>
|
||||
<modified>1593095882</modified>
|
||||
<mailed>1</mailed>
|
||||
<subject>Re: Czy komputer w lodówce to już współczesność?</subject>
|
||||
<message><p>Komputery w życiu codziennym to już norma. Mamy z nimi do czynienia w kuchni, łazience oraz salonie. Firmy technologiczne dążą do stworzenia inteligentych domów, w zasadzie już takie domy istnieją, ale zwykły śmiertelnik może o nich tylko pomarzyć. <br /></p><p>Zacznę więc może od wspomnianej lodówki. Na targach CES w 2011 roku firma LG zaprezentowała inteligentną lodówkę, która sama przeszukiwała internet w poszukiwaniu ciekawych przepisów, bazując przy tym na produktach, które znajdowały się w jej wnętrzu. Sprawdzanie terminów ważności produktów równeż nie było problemem. Wszystkie niezbędne informacje, dotyczące lodówki i produktów z jej wnętrza, użytkownik mógł odebrać przy pomocy komputera, bądź urządzenia mobilnego, podłączonego do internetu. <br /></p><p>Samsung w tym roku zaprezentowały lodówki z wyświetlaczem dotykowym oraz możliwością dokonywania zakupów z poziomu lodówki.[url]http://www.youtube.com/watch?v=yu3keu48hzY[/url] <br /></p><p>Samsung i LG nie poprzestają tylko na konstruowaniu inteligentych urządzeń AGD, chcą również zapewnić swobodną komunikację pomiędzy urządzeniami bez naszej ingerencji. <br /></p><p>Dwa tygodnie temu miałem okazję obejrzeć film dokumentalny o inteligentych domach. Prezentowane technologie mieściły się w centrum badawczym firmy Samsung, których oglądanie jest dostępne dla zwiedzających. Tak więc system rozpoznający domowników wybiera dla konkretnej osoby poziom oświetlenia w pomieszczeniu, załącza odpowiednią muzykę, itp. Nie będę już wspominał o automatycznym nalewaniu wody do wanny o określonej godzinie, kabinach prysznicowych z telewizorem, łącznością telefoniczną i internetową czy podgrzewanych deskach sedesowych. Część tych rozwiązań jest już dostępna na rynku, a część będzie wdrażana w tym roku. <br /></p><p>Zapewne część z Was słyszała o posiadłości Billa Gatesa, która jest w całości naszpikowana elektroniką. Jeśli nie to polecam poniższy artykuł:[url]http://nt.interia.pl/gadzety/news-jak-mieszka-bill-gates,nId,690078[/url]<br /></p></message>
|
||||
<messageformat>1</messageformat>
|
||||
<messagetrust>0</messagetrust>
|
||||
<attachment></attachment>
|
||||
<totalscore>0</totalscore>
|
||||
<mailnow>0</mailnow>
|
||||
<ratings>
|
||||
</ratings>
|
||||
</post>
|
||||
<post id="38">
|
||||
<parent>36</parent>
|
||||
<userid>8</userid>
|
||||
<created>1593095987</created>
|
||||
<modified>1593157009</modified>
|
||||
<mailed>1</mailed>
|
||||
<subject>Re: Czy komputer w lodówce to już współczesność?</subject>
|
||||
<message><p>Niestety taka komputeryzacja postępuje. Dlaczego niestety? <br /></p><p>Bo boje się iż ludzie przez nią staną się coraz bardziej leniwi i przepraszam za określenie 'zidioceni' <br /></p><p>Dlaczego? Mamy juz inteligentne lodówki, samo czyszczące odkurzacze, samo jeżdzące samochody. To co człowiek ma robić? Jak żyć, skoro nie ma nawet najprostrzych codziennych udręk i wyzwań? Co gorsza w ten sposób ludzie oduczaja się dbać o inne rzeczy. Bo po co skoro komputer zrobi to za nas? <br /></p><p>Wyobraźcie sobie sytuację za powiedzmy 20 lat. Gdzie nie ma już gazet, tylko same e-papiery i tablety. A tu w piwnicy znajdzie stary album ze zdjęciami i próbując go otworzyć nieświadomie go zniszczy. <br /></p><p>Jest to problem teoretycznie wielokrotnie wyśmiewany w naszej kulturze np w filmie animowanym [url=http://www.youtube.com/watch?v=h1BQPV-iCkU][b]WALL-E LINK 1[/b][/url] [url=http://www.youtube.com/watch?v=xoa25BjRP-I][b]WALL-E LINK 2[/b][/url] gdzie mamy wiele scen pokazujących wręcz ludzka degenerację w pełni zautomatyzowanym świecie. Jednak moim zdaniem problem istnieje i sądzę że komputery nie powinny być wpychane gdzie popadnie.<br /></p><p><span class="edited">(Edited by <a href="https://fep.gnomio.com/user/view.php?id=2&amp;course=2">Admin User</a> - original submission Thursday, 25 June 2020, 2:39 PM)</span></p></message>
|
||||
<messageformat>1</messageformat>
|
||||
<messagetrust>0</messagetrust>
|
||||
<attachment></attachment>
|
||||
<totalscore>0</totalscore>
|
||||
<mailnow>0</mailnow>
|
||||
<ratings>
|
||||
</ratings>
|
||||
</post>
|
||||
<post id="39">
|
||||
<parent>36</parent>
|
||||
<userid>9</userid>
|
||||
<created>1593096052</created>
|
||||
<modified>1593096052</modified>
|
||||
<mailed>1</mailed>
|
||||
<subject>Re: Czy komputer w lodówce to już współczesność?</subject>
|
||||
<message><p>Odwołując się do wypowiedzi X 2 i 3 akapit. Co prawda powstaje coraz lepszy sprzęt ale kto z niego korzysta? Nie znam nikogo kto by miał samoczyszczący odkurzacz, czy inteligentną lodówkę. Zwykły szary obywatel woli te pieniądze przeznaczyć na coś innego, a ci co kupują taki sprzęt i tak by sami nie sprzątali. Wydaje mi się, że jeszcze sporo czasu pomęczymy się z odkurzaczem.Jednak postem komputeryzacji w naszym życiu możemy zaobserwować np. siedząc na wykładzie. Kiedyś na nudnych zajęciach uczniowie/studyci grali w kółko i krzyżyk, statki itp., a notowali w zeszycie. Teraz co druga osoba siedzi z laptopem lub innym sprzętem elektronicznym, nieraz też słyszałam w telewizji rozmowy polityków by dzieci zamiast książek i zeszytów chodziły do szkoły z laptopami. Również ściąga pisana na kartce została totalnie wyparta przez elektronikę.
|
||||
<br /><br /></p></message>
|
||||
<messageformat>1</messageformat>
|
||||
<messagetrust>0</messagetrust>
|
||||
<attachment></attachment>
|
||||
<totalscore>0</totalscore>
|
||||
<mailnow>0</mailnow>
|
||||
<ratings>
|
||||
</ratings>
|
||||
</post>
|
||||
</posts>
|
||||
<discussion_subs>
|
||||
<discussion_sub id="25">
|
||||
<userid>2</userid>
|
||||
<preference>1593095765</preference>
|
||||
</discussion_sub>
|
||||
<discussion_sub id="26">
|
||||
<userid>7</userid>
|
||||
<preference>1593095882</preference>
|
||||
</discussion_sub>
|
||||
<discussion_sub id="27">
|
||||
<userid>8</userid>
|
||||
<preference>1593095987</preference>
|
||||
</discussion_sub>
|
||||
<discussion_sub id="28">
|
||||
<userid>9</userid>
|
||||
<preference>1593096052</preference>
|
||||
</discussion_sub>
|
||||
</discussion_subs>
|
||||
</discussion>
|
||||
</discussions>
|
||||
<subscriptions>
|
||||
</subscriptions>
|
||||
<digests>
|
||||
</digests>
|
||||
<readposts>
|
||||
</readposts>
|
||||
<trackedprefs>
|
||||
</trackedprefs>
|
||||
<poststags>
|
||||
</poststags>
|
||||
</forum>
|
||||
</activity>
|
Loading…
Reference in New Issue
Block a user