<field reporter:label="Course Members" name="members" oils_persist:virtual="true" reporter:datatype="link" />
<field reporter:label="Course Materials" name="materials" oils_persist:virtual="true" reporter:datatype="link" />
<field reporter:label="Is Archived?" name="is_archived" reporter:datatype="bool" />
+ <field reporter:label="Terms Taught" name="terms_map" oils_persist:virtual="true" reporter:datatype="link" config_field="true" />
</fields>
<links>
<link field="owning_lib" reltype="has_a" key="id" map="" class="aou" />
<link field="members" reltype="has_many" key="course" map="" class="acmcu" />
<link field="materials" reltype="has_many" key="course" map="" class="acmcm" />
+ <link field="terms_map" reltype="has_many" key="course" map="" class="acmtcm" />
</links>
<permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
<actions>
</actions>
</permacrud>
</class>
+ <class id="acmt" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="asset::course_module_term" oils_persist:tablename="asset.course_module_term" reporter:label="Term" oils_persist:field_safe="true">
+ <fields oils_persist:primary="id" oils_persist:sequence="asset.course_module_term_id_seq">
+ <field reporter:label="Term ID" name="id" reporter:datatype="id" reporter:selector="name"/>
+ <field reporter:label="Name" name="name" reporter:datatype="text" oils_persist:i18n="true" oils_obj:required="true"/>
+ <field reporter:label="Owning Library" name="owning_lib" reporter:datatype="link" oils_obj:required="true" />
+ <field reporter:label="Start Date" name="start_date" reporter:datatype="timestamp"/>
+ <field reporter:label="End Date" name="end_date" reporter:datatype="timestamp"/>
+ <field reporter:label="Courses" name="courses" reporter:datatype="link" oils_persist:virtual="true"/>
+ <field reporter:label="Course Maps" name="maps" reporter:datatype="link" oils_persist:virtual="true"/>
+ </fields>
+ <links>
+ <link field="owning_lib" reltype="has_a" key="id" map="" class="aou" />
+ <link field="courses" reltype="has_many" key="term" map="course" class="acmtcm"/>
+ <link field="maps" reltype="has_many" key="term" map="" class="acmtcm"/>
+ </links>
+ <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+ <actions>
+ <create permission="MANAGE_RESERVES" context_field="owning_lib" />
+ <retrieve/>
+ <update permission="MANAGE_RESERVES" context_field="owning_lib" />
+ <delete permission="MANAGE_RESERVES" context_field="owning_lib" />
+ </actions>
+ </permacrud>
+ </class>
+ <class id="acmtcm" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="asset::course_module_term_course_map" oils_persist:tablename="asset.course_module_term_course_map" reporter:label="Course Term Map" oils_persist:field_safe="true">
+ <fields oils_persist:primary="id" oils_persist:sequence="asset.course_module_term_course_map_id_seq">
+ <field reporter:label="Course Term Map ID" name="id" reporter:datatype="id"/>
+ <field reporter:label="Term" name="term" oils_obj:required="true" reporter:datatype="link"/>
+ <field reporter:label="Course" name="course" reporter:datatype="link" oils_obj:required="true"/>
+ </fields>
+ <links>
+ <link field="term" reltype="has_a" key="id" map="" class="acmt"/>
+ <link field="course" reltype="has_a" key="id" map="" class="acmc"/>
+ </links>
+ <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+ <actions>
+ <create permission="MANAGE_RESERVES">
+ <context link="course" field="owning_lib" />
+ </create>
+ <retrieve/>
+ <update permission="MANAGE_RESERVES">
+ <context link="course" field="owning_lib" />
+ </update>
+ <delete permission="MANAGE_RESERVES">
+ <context link="course" field="owning_lib" />
+ </delete>
+ </actions>
+ </permacrud>
+ </class>
+
<class id="acnc" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="asset::call_number_class" oils_persist:tablename="asset.call_number_class" reporter:label="Call number classification scheme">
<fields oils_persist:primary="id" oils_persist:sequence="asset.call_number_class_id_seq">
<field reporter:label="Call number class ID" name="id" reporter:datatype="id"/>
<eg-string #archiveSuccessString i18n-text text="Archival of {{tableName}} succeeded"></eg-string>
<eg-string #flairTooltip i18n-text text="Limited Editing"></eg-string>
-<div class="w-100 mt-2 mb-2">
- <eg-grid #grid idlClass={{idlClass}}
- [dataSource]="grid_source"
- [sortable]="true">
- <eg-grid-toolbar-button
- label="Create {{tableName}}" (onClick)="createNew()" i18n-label>
- </eg-grid-toolbar-button>
- <eg-grid-toolbar-action label="Edit Selected" i18n-label (onClick)="editSelected($event)">
- </eg-grid-toolbar-action>
- <eg-grid-toolbar-action label="Delete Selected" i18n-label (onClick)="deleteSelected($event)">
- </eg-grid-toolbar-action>
- <eg-grid-toolbar-action label="Archive Selected" i18n-label (onClick)="archiveSelected($event)">
- </eg-grid-toolbar-action>
- <eg-grid-column label="ID" path="id" [index]=true [hidden]="true" i18n-label></eg-grid-column>
- <eg-grid-column label="Title" name="name" i18n-label></eg-grid-column>
- <eg-grid-column label="CourseNumber" name="course_number" i18n-label></eg-grid-column>
- <eg-grid-column label="Section Number" name="section_number" i18n-label></eg-grid-column>
- <eg-grid-column label="Is Archived?" name="is_archived" i18n-label datatype="bool"></eg-grid-column>
- </eg-grid>
-</div>
+<ul ngbNav #courseListNav="ngbNav" class="nav-tabs">
+ <li ngbNavItem>
+ <a ngbNavLink i18n>Course list</a>
+ <ng-template ngbNavContent>
+ <div class="w-100 mt-2 mb-2">
+ <eg-grid #grid idlClass={{idlClass}}
+ [dataSource]="grid_source"
+ [sortable]="true">
+ <eg-grid-toolbar-button
+ label="Create {{tableName}}" (onClick)="createNew()" i18n-label>
+ </eg-grid-toolbar-button>
+ <eg-grid-toolbar-action label="Edit Selected" i18n-label (onClick)="editSelected($event)">
+ </eg-grid-toolbar-action>
+ <eg-grid-toolbar-action label="Delete Selected" i18n-label (onClick)="deleteSelected($event)">
+ </eg-grid-toolbar-action>
+ <eg-grid-toolbar-action label="Archive Selected" i18n-label (onClick)="archiveSelected($event)">
+ </eg-grid-toolbar-action>
+ <eg-grid-column label="ID" path="id" [index]=true [hidden]="true" i18n-label></eg-grid-column>
+ <eg-grid-column label="Terms taught" name="terms_map" i18n-label [cellTemplate]="termMapLink"></eg-grid-column>
+ <eg-grid-column label="Title" name="name" i18n-label></eg-grid-column>
+ <eg-grid-column label="CourseNumber" name="course_number" i18n-label></eg-grid-column>
+ <eg-grid-column label="Section Number" name="section_number" i18n-label></eg-grid-column>
+ <eg-grid-column label="Is Archived?" name="is_archived" i18n-label datatype="bool"></eg-grid-column>
+ </eg-grid>
+ </div>
+ </ng-template>
+ </li>
+ <li ngbNavItem>
+ <a ngbNavLink i18n>Terms</a>
+ <ng-template ngbNavContent>
+ <eg-admin-page idlClass="acmt"></eg-admin-page>
+ </ng-template>
+ </li>
+</ul>
+<div [ngbNavOutlet]="courseListNav"></div>
<eg-fm-record-editor #editDialog
idlClass="acmc"
[preloadLinkedValues]="true"
hiddenFields="id,is_archived">
</eg-fm-record-editor>
+
+<ng-template #termMapLink let-row="row">
+ <a routerLink="/staff/admin/local/asset/course_module_term_course_map" [queryParams]="acmtcmQueryParams(row)" i18n>
+ Terms taught
+ </a>
+</ng-template>
currentMaterials: any[] = [];
search_value = '';
+
constructor(
private courseSvc: CourseService,
private locale: LocaleService,
const idToEdit = course.id();
this.navigateToCoursePage(idToEdit);
});
+
}
+ acmtcmQueryParams (row: any): {gridFilters: string} {
+ return {gridFilters: '{"course":' + row.id() + '}'};
+ }
+
+
/**
* Gets the data, specified by the class, that is available.
*/
</eg-course-associate-users-dialog>
</ng-template>
</li>
+
+ <!-- Terms Tab -->
+ <li [ngbNavItem]="'courseTerms'">
+ <a ngbNavLink i18n>Course terms</a>
+ <ng-template ngbNavContent>
+ <eg-admin-page idlClass="acmtcm" readonlyFields="id"
+ [defaultNewRecord]="defaultNewAcmtcm"
+ hideGridFields="id" [dataSource]="termsDataSource">
+ </eg-admin-page>
+ </ng-template>
+ </li>
</ul>
<div [ngbNavOutlet]="coursePageNav" class="mb-3"></div>
-import {Component, Input, ViewChild, OnInit, TemplateRef} from '@angular/core';
+import {Component, ViewChild, OnInit} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
import {PcrudService} from '@eg/core/pcrud.service';
import {IdlObject, IdlService} from '@eg/core/idl.service';
+import {GridDataSource} from '@eg/share/grid/grid';
import {StringComponent} from '@eg/share/string/string.component';
import {ToastService} from '@eg/share/toast/toast.service';
import {CourseService} from '@eg/staff/share/course.service';
import {CourseAssociateUsersComponent} from './course-associate-users.component';
import {CourseAssociateMaterialComponent} from './course-associate-material.component';
+import {Pager} from '@eg/share/util/pager';
@Component({
selector: 'eg-course-page',
currentCourse: IdlObject;
courseId: any;
+ // Materials Tab
@ViewChild('courseMaterialDialog', {static: true})
private courseMaterialDialog: CourseAssociateMaterialComponent;
@ViewChild('courseUserDialog', {static: true})
@ViewChild('archiveSuccessString', { static: true })
archiveSuccessString: StringComponent;
- // Materials Tab
+ // Course Tab
+ termsDataSource: GridDataSource = new GridDataSource();
+ defaultNewAcmtcm: IdlObject;
constructor(
private course: CourseService,
+ private idl: IdlService,
private pcrud: PcrudService,
private route: ActivatedRoute,
private toast: ToastService
this.course.getCourses([this.courseId]).then(course => {
this.currentCourse = course[0];
});
+
+ this.defaultNewAcmtcm = this.idl.create('acmtcm');
+ this.defaultNewAcmtcm.course(this.courseId);
+
+ this.termsDataSource.getRows = (pager: Pager, sort: any[]) => {
+ const orderBy: any = {};
+ if (sort.length) {
+ orderBy.acmtcm = sort[0].name + ' ' + sort[0].dir;
+ }
+ const searchOps = {
+ offset: pager.offset,
+ limit: pager.limit,
+ order_by: orderBy
+ };
+
+ return this.pcrud.search('acmtcm', {course: this.courseId},
+ searchOps, {fleshSelectors: true});
+ };
}
// Edit Tab
import {CourseReservesRoutingModule} from './routing.module';
import {ItemLocationSelectModule} from '@eg/share/item-location-select/item-location-select.module';
import {MarcSimplifiedEditorModule} from '@eg/staff/share/marc-edit/simplified-editor/simplified-editor.module';
+import {CourseTermMapComponent} from './course-term-map.component';
@NgModule({
declarations: [
CoursePageComponent,
CourseAssociateMaterialComponent,
CourseAssociateUsersComponent,
+ CourseTermMapComponent
],
imports: [
StaffCommonModule,
--- /dev/null
+import {Component} from '@angular/core';
+
+/**
+ * Very basic page for editing course/term map
+ */
+
+@Component({
+ template: `
+ <eg-title i18n-prefix prefix="Course Materials Administration">
+ </eg-title>
+ <eg-staff-banner bannerText="Course Term Configuration" i18n-bannerText>
+ </eg-staff-banner>
+ <div class="row">
+ <div class="col text-right">
+ <a class="btn btn-warning ml-3" routerLink="/staff/admin/local/asset/course_list" i18n>
+ <i class="material-icons align-middle">keyboard_return</i>
+ <span class="align-middle">Return to Course List</span>
+ </a>
+ </div>
+ </div>
+ <eg-admin-page persistKeyPfx="local" idlClass="acmtcm"
+ [disableOrgFilter]="true"></eg-admin-page>
+ `
+})
+
+export class CourseTermMapComponent {
+
+}
\ No newline at end of file
import {AddressAlertComponent} from './address-alert.component';
import {AdminCarouselComponent} from './admin-carousel.component';
import {StandingPenaltyComponent} from './standing-penalty.component';
+import {CourseTermMapComponent} from './course-reserves/course-term-map.component';
const routes: Routes = [{
path: 'splash',
path: 'asset/course_list',
loadChildren: '@eg/staff/admin/local/course-reserves/course-reserves.module#CourseReservesModule'
}, {
+ path: 'asset/course_module_term_course_map',
+ component: CourseTermMapComponent
+}, {
path: 'config/standing_penalty',
component: StandingPenaltyComponent
}, {
unique (course, item, record)
);
+CREATE TABLE asset.course_module_term (
+ id SERIAL PRIMARY KEY,
+ name TEXT UNIQUE NOT NULL,
+ owning_lib INT REFERENCES actor.org_unit (id),
+ start_date TIMESTAMP WITH TIME ZONE,
+ end_date TIMESTAMP WITH TIME ZONE
+);
+
+CREATE TABLE asset.course_module_term_course_map (
+ id BIGSERIAL PRIMARY KEY,
+ term INT NOT NULL REFERENCES asset.course_module_term (id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+ course INT NOT NULL REFERENCES asset.course_module_course (id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED
+);
+
COMMIT;
unique (course, item, record)
);
+CREATE TABLE asset.course_module_term (
+ id SERIAL PRIMARY KEY,
+ name TEXT UNIQUE NOT NULL,
+ owning_lib INT REFERENCES actor.org_unit (id),
+ start_date TIMESTAMP WITH TIME ZONE,
+ end_date TIMESTAMP WITH TIME ZONE
+);
+
+CREATE TABLE asset.course_module_term_course_map (
+ id BIGSERIAL PRIMARY KEY,
+ term INT NOT NULL REFERENCES asset.course_module_term (id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+ course INT NOT NULL REFERENCES asset.course_module_course (id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED
+);
+
INSERT INTO permission.perm_list(id, code, description)
VALUES (
624,