Skip to content

Commit

Permalink
Merge pull request #93 from scholarsportal/nana-dev
Browse files Browse the repository at this point in the history
Last big updates
  • Loading branch information
nana-boateng authored Aug 26, 2024
2 parents 75d7d33 + e5f5e6f commit 3227fa3
Show file tree
Hide file tree
Showing 58 changed files with 1,390 additions and 2,707 deletions.
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,32 @@ A demo of the tool is available here; note that this Github pages demo is **not

```npm install -g @angular/cli```

Integrating Data Explorer in your institution? See [the Dataverse guide for more information about installing external tools](http://guides.dataverse.org/en/latest/installation/external-tools.html).

Now to start development.

```sh
npm install
ng serve
```

### Variable Selection Context
## Customization

### Dataverse Instance Name

You can customize the dataverse instance name in the en.json.

## Building

### Into Dataverse Instance

Integrating Data Explorer in your institution? See [the Dataverse guide for more information about installing external tools](http://guides.dataverse.org/en/latest/installation/external-tools.html).

### Serve as web app

You can serve the Data Explorer app like you would any other website.
Use ```ng build``` to get the `dist` directory, and serve the dist directly using Apache, Nginx, or whatever server you use.

When a user selects a variables, navigates to another group, and makes another selection, the app holds the selection information for both contexts in which the selection in made. In simple terms the user does not have to worry about losing their selection when they change groups.
> [!NOTE]
> You can also deploy this via docker.
## App State

Expand Down
2 changes: 1 addition & 1 deletion src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export class AppComponent implements OnInit {
);
} else if (siteURL && fileID) {
return this.store.dispatch(
DataverseFetchActions.startDDIFetch({
DataverseFetchActions.fetchDDIStart({
fileID,
siteURL,
apiKey,
Expand Down
2 changes: 2 additions & 0 deletions src/app/components/body/body.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
}
<dct-data
class="data md:grid"
[hasApiKey]="hasApiKey()"
[variablesWithCrossTabMetadata]="variablesWithCrossTabMetadata()"
[isFetching]="crossTabIsFetching()"
[variables]="filteredByGroupID()"
[variablesInCrossTabSelection]="variablesInCrossTab()"
Expand Down
32 changes: 22 additions & 10 deletions src/app/components/body/body.component.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';
import { Component, computed, inject } from '@angular/core';
import { Store } from '@ngrx/store';
import { selectDatasetProcessedGroups, selectDatasetProcessedVariables } from '../../new.state/xml/xml.selectors';
import {
selectDatasetHasApiKey,
selectDatasetProcessedGroups,
selectDatasetProcessedVariables,
} from '../../new.state/xml/xml.selectors';
import {
selectBodyToggleState,
selectCrossTabSelection,
selectCurrentGroupID,
selectImportComponentState,
selectOpenVariableCategoriesMissing,
selectOpenVariableID,
selectVariableSelectionContext
selectVariableSelectionContext,
} from '../../new.state/ui/ui.selectors';
import { Variable } from '../../new.state/xml/xml.interface';
import { SidebarComponent } from './variables/sidebar/sidebar.component';
Expand All @@ -18,7 +22,7 @@ import { ImportComponent } from '../import/import.component';
import {
selectDatasetVariableCrossTabValues,
selectDatasetWeights,
selectVariableCrossTabIsFetching
selectVariableCrossTabIsFetching,
} from '../../new.state/dataset/dataset.selectors';
import { TableComponent } from './variables/data/table/table.component';

Expand All @@ -30,7 +34,7 @@ import { TableComponent } from './variables/data/table/table.component';
DataComponent,
CrossTabulationComponent,
ImportComponent,
TableComponent
TableComponent,
],
templateUrl: './body.component.html',
styleUrl: './body.component.css',
Expand All @@ -39,11 +43,14 @@ import { TableComponent } from './variables/data/table/table.component';
export class BodyComponent {
store = inject(Store);

hasApiKey = this.store.selectSignal(selectDatasetHasApiKey);
variablesInCrossTab = this.store.selectSignal(selectCrossTabSelection);
crossTabValuesFetched = this.store.selectSignal(
selectDatasetVariableCrossTabValues
selectDatasetVariableCrossTabValues,
);
crossTabIsFetching = this.store.selectSignal(
selectVariableCrossTabIsFetching,
);
crossTabIsFetching = this.store.selectSignal(selectVariableCrossTabIsFetching);
bodyToggleState = this.store.selectSignal(selectBodyToggleState);
crossTabulationTabOpen = computed(() => {
return this.bodyToggleState() === 'cross-tab';
Expand All @@ -52,6 +59,10 @@ export class BodyComponent {
return this.bodyToggleState() === 'variables';
});

variablesWithCrossTabMetadata = this.store.selectSignal(
selectDatasetVariableCrossTabValues,
);

groups = this.store.selectSignal(selectDatasetProcessedGroups);
allWeights = this.store.selectSignal(selectDatasetWeights);
variables = this.store.selectSignal(selectDatasetProcessedVariables);
Expand All @@ -60,13 +71,13 @@ export class BodyComponent {
return this.selectedGroupID();
});
selectedVariableContext = this.store.selectSignal(
selectVariableSelectionContext
selectVariableSelectionContext,
);
selectedVariables = computed(() => {
return this.selectedVariableContext()[this.selectedGroupID()] || [];
});
categoriesMissing = this.store.selectSignal(
selectOpenVariableCategoriesMissing
selectOpenVariableCategoriesMissing,
);
openVariable = this.store.selectSignal(selectOpenVariableID);
importComponentState = this.store.selectSignal(selectImportComponentState);
Expand All @@ -79,7 +90,8 @@ export class BodyComponent {
const filteredVariables: { [variableID: string]: Variable } = {};
if (this.groups()[this.selectedGroupID()]) {
if (!!this.groups()[this.selectedGroupID()]['@_var']) {
const selectedGroupVariableArray = this.groups()[this.selectedGroupID()]['@_var']?.split(' ') || [];
const selectedGroupVariableArray =
this.groups()[this.selectedGroupID()]['@_var']?.split(' ') || [];
selectedGroupVariableArray.map((variableID) => {
filteredVariables[variableID] = this.variables()[variableID];
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ th {
}

.pvtRowLabel {
@apply font-semibold bg-primary-content border;
@apply font-semibold bg-primary-content border border-base-300;
}

.pvtColLabel {
@apply font-semibold bg-secondary-content border;
@apply font-semibold bg-secondary-content border-base-300;
}

.pvtAxisLabel {
Expand Down Expand Up @@ -48,4 +48,4 @@ th {

.pvtRendererArea {
@apply px-0;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { Component, computed, effect, ElementRef, inject, input, ViewChild, ViewEncapsulation } from '@angular/core';
import {
Component,
computed,
effect,
ElementRef,
inject,
input,
ViewChild,
ViewEncapsulation,
} from '@angular/core';
import { CommonModule } from '@angular/common';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand All @@ -11,7 +20,7 @@ declare const jQuery: any; // Declare jQuery
imports: [CommonModule],
encapsulation: ViewEncapsulation.None,
templateUrl: './cross-table.component.html',
styleUrl: './cross-table.component.css'
styleUrl: './cross-table.component.css',
})
export class CrossTableComponent {
@ViewChild('output') outputElement?: ElementRef;
Expand Down Expand Up @@ -68,9 +77,36 @@ export class CrossTableComponent {
cols: this.cols(),
aggregatorName: this.selectedViewOption(),
showUI: false,
rendererName: 'Horizontal Stacked Bar Chart'
rendererName: 'Horizontal Stacked Bar Chart',
},
true
true,
);
}

downloadDivAsCSV() {
const div = this.outputElement?.nativeElement;
const table = div.querySelector('table');
let csvContent = '';

// Skip the first two rows by iterating from index 2
for (let i = 2; i < table.rows.length; i++) {
let row = table.rows[i];
let rowData = [];
if (i === 2) {
rowData.push(''); // Add an empty cell at the beginning
}
for (let cell of row.cells) {
rowData.push(cell.innerText.replace(/,/g, ''));
}
csvContent += rowData.join(',') + '\n';
}

const blob = new Blob([csvContent], { type: 'text/csv' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.setAttribute('href', url);
a.setAttribute('download', 'table.csv');
a.click();
window.URL.revokeObjectURL(url);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,14 @@
</ng-template>
</p-dropdown>
<button
(click)="exportTable()"
(click)="crossTableComponent.downloadDivAsCSV()"
class="text-primary mb-2.5 mt-5 mr-5 md:mr-0 hover:underline float-right"
>
<span>Export table as CSV</span>
</button>
</div>
<dct-cross-table
#crossTableComponent
[data]="table()"
[cols]="cols()"
[rows]="rows()"
Expand All @@ -87,25 +88,25 @@
<h3 class="mx-auto text-base">
No Data! Start adding variables to generate your table.
</h3>

} @else if (hasData() && !hasRowOrColumn()) {
<h3 class="mx-auto text-base">
One more step. Set your rows and/or columns.
</h3>

}
} @else if (isFetching()) {
@if (loadingStatus === 'init') {
<h3 class="preload-text">
Loading dataset ...
</h3>

} @else if (loadingStatus === 'delayed') {
<h3 class="preload-text">
Still loading ...
</h3>
<h4 class="text-base mx-auto">One moment please</h4>

}
}
</div>
Expand Down
3 changes: 3 additions & 0 deletions src/app/components/body/variables/data/data.component.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
<dct-table
[allVariables]="variables()"
[categoriesInvalid]="categoriesInvalid()"
[crossTabValuesFetched]="crossTabValuesFetched()"
[groupChanged]="groupChanged()"
[groups]="groups()"
[hasApiKey]="hasApiKey()"
[isFetching]="isFetching()"
[openVariable]="openVariable()"
[selectedVariables]="selectedVariables()"
[variablesInCrossTab]="variablesInCrossTabSelection()"
[variablesWithCrossTabMetadata]="variablesWithCrossTabMetadata()"
[variables]="variablesSimplified()"
[weights]="weights()"
class="md:flex flex-col w-full table"
Expand Down
16 changes: 12 additions & 4 deletions src/app/components/body/variables/data/data.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';
import { Variable, VariableGroup, VariablesSimplified } from 'src/app/new.state/xml/xml.interface';
import { Component, computed, input } from '@angular/core';
import {
Variable,
VariableGroup,
VariablesSimplified,
} from 'src/app/new.state/xml/xml.interface';
import { KeyValuePipe } from '@angular/common';
import { TableNavComponent } from './table-nav/table-nav.component';
import { TableMenuComponent } from './table-menu/table-menu.component';
Expand All @@ -12,7 +16,7 @@ import { TableComponent } from './table/table.component';
KeyValuePipe,
TableComponent,
TableNavComponent,
TableMenuComponent
TableMenuComponent,
],
templateUrl: './data.component.html',
styleUrl: './data.component.css',
Expand All @@ -21,9 +25,13 @@ import { TableComponent } from './table/table.component';
export class DataComponent {
groups = input.required<{ [variableID: string]: VariableGroup }>();
variables = input.required<{ [variableID: string]: Variable }>();
hasApiKey = input.required<boolean>();
openVariable = input.required<string>();
selectedVariables = input.required<string[]>();
categoriesInvalid = input.required<string[]>();
variablesWithCrossTabMetadata = input.required<{
[variableID: string]: string[];
}>();
variablesInCrossTabSelection = input.required<
{
variableID: string;
Expand All @@ -43,7 +51,7 @@ export class DataComponent {
label: value.labl?.['#text'] || '',
weight: value['@_wgt-var'] || '',
isWeight: !!value['@_wgt'],
selected: this.selectedVariables().includes(value['@_ID'])
selected: this.selectedVariables().includes(value['@_ID']),
};
simplified.push(newObj);
}
Expand Down
Loading

0 comments on commit 3227fa3

Please sign in to comment.