diff --git a/SAS/TMSS/frontend/tmss_webapp/src/components/ViewTable.js b/SAS/TMSS/frontend/tmss_webapp/src/components/ViewTable.js index 8f91d1af24340e33563606c455036335d8a25def..c134771ba94f98aca6b1b3dae8ec713ca0f9555b 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/components/ViewTable.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/components/ViewTable.js @@ -229,7 +229,7 @@ const IndeterminateCheckbox = React.forwardRef( ) // Our table component -function Table({ columns, data, defaultheader, optionalheader, defaultSortColumn }) { +function Table({ columns, data, defaultheader, optionalheader, defaultSortColumn, tablename }) { const filterTypes = React.useMemo( () => ({ // Add a new fuzzyTextFilterFn filter type. @@ -257,7 +257,7 @@ function Table({ columns, data, defaultheader, optionalheader, defaultSortColumn }), [] ) - + const { getTableProps, getTableBodyProps, @@ -273,7 +273,6 @@ function Table({ columns, data, defaultheader, optionalheader, defaultSortColumn setHiddenColumns, gotoPage, setPageSize, - } = useTable( { columns, @@ -288,7 +287,6 @@ function Table({ columns, data, defaultheader, optionalheader, defaultSortColumn useSortBy, usePagination ) - React.useEffect(() => { setHiddenColumns( columns.filter(column => !column.isVisible).map(column => column.accessor) @@ -307,6 +305,17 @@ function Table({ columns, data, defaultheader, optionalheader, defaultSortColumn setPageSize(e.rows) }; + const onToggleChange = (e) =>{ + let lsToggleColumns = []; + allColumns.forEach( acolumn =>{ + let jsonobj = {}; + let visible = (acolumn.Header === e.target.id) ? ((acolumn.isVisible)?false:true) :acolumn.isVisible + jsonobj['Header'] = acolumn.Header; + jsonobj['isVisible'] = visible; + lsToggleColumns.push(jsonobj) + }) + localStorage.setItem(tablename,JSON.stringify(lsToggleColumns)) + } return ( <> <div id="block_container"> @@ -325,7 +334,10 @@ function Table({ columns, data, defaultheader, optionalheader, defaultSortColumn </div> {allColumns.map(column => ( <div key={column.id} style={{'display':column.id !== 'actionpath'?'block':'none'}}> - <input type="checkbox" {...column.getToggleHiddenProps()} /> { + <input type="checkbox" {...column.getToggleHiddenProps()} + id={(defaultheader[column.id])?defaultheader[column.id]:(optionalheader[column.id]?optionalheader[column.id]:column.id)} + onClick={onToggleChange} + /> { (defaultheader[column.id]) ? defaultheader[column.id] : (optionalheader[column.id] ? optionalheader[column.id] : column.id)} </div> ))} @@ -346,7 +358,7 @@ function Table({ columns, data, defaultheader, optionalheader, defaultSortColumn /> } </div> -</div> + </div> <div className="table_container"> <table {...getTableProps()} data-testid="viewtable" className="viewtable" > @@ -367,7 +379,6 @@ function Table({ columns, data, defaultheader, optionalheader, defaultSortColumn {column.Header !== 'actionpath' && <div className={columnclassname[0][column.Header]} > {column.canFilter && column.Header !== 'Action' ? column.render('Filter') : null} - </div> } </th> @@ -382,7 +393,10 @@ function Table({ columns, data, defaultheader, optionalheader, defaultSortColumn return ( <tr {...row.getRowProps()}> {row.cells.map(cell => { - return <td {...cell.getCellProps()}>{cell.render('Cell')}</td> + if(cell.column.id !== 'actionpath') + return <td {...cell.getCellProps()}>{cell.render('Cell')}</td> + else + return; })} </tr> ) @@ -396,7 +410,6 @@ function Table({ columns, data, defaultheader, optionalheader, defaultSortColumn </> ) } - // Define a custom filter filter function! function filterGreaterThan(rows, id, filterValue) { @@ -423,6 +436,8 @@ function ViewTable(props) { let defaultheader = props.defaultcolumns; let optionalheader = props.optionalcolumns; let defaultSortColumn = props.defaultSortColumn; + let tablename = (props.tablename)?props.tablename:window.location.pathname; + if(!defaultSortColumn){ defaultSortColumn =[{}]; } @@ -455,34 +470,45 @@ function ViewTable(props) { // Object.entries(props.paths[0]).map(([key,value]) =>{}) } - //Default Columns - defaultdataheader.forEach(header => { - const isString = typeof defaultheader[0][header] === 'string'; - columns.push({ - Header: isString ? defaultheader[0][header] : defaultheader[0][header].name, - id: isString ? defaultheader[0][header] : defaultheader[0][header].name, - accessor: header, - filter: (!isString && defaultheader[0][header].filter=== 'date') ? 'includes' : 'fuzzyText', - Filter: isString ? DefaultColumnFilter : (filterTypes[defaultheader[0][header].filter] ? filterTypes[defaultheader[0][header].filter] : DefaultColumnFilter), - isVisible: true, - Cell: props => <div> {updatedCellvalue(header, props.value)} </div>, - }) - }) - - //Optional Columns - optionaldataheader.forEach(header => { - const isString = typeof optionalheader[0][header] === 'string'; - columns.push({ - Header: isString ? optionalheader[0][header] : optionalheader[0][header].name, - id: isString ? optionalheader[0][header] : optionalheader[0][header].name, + //Default Columns + defaultdataheader.forEach(header =>{ + const isString = typeof defaultheader[0][header] === 'string'; + columns.push({ + Header: isString ? defaultheader[0][header] : defaultheader[0][header].name, + id: header, + accessor: header, + filter: (!isString && defaultheader[0][header].filter=== 'date') ? 'includes' : 'fuzzyText', + Filter: isString ? DefaultColumnFilter : (filterTypes[defaultheader[0][header].filter] ? filterTypes[defaultheader[0][header].filter] : DefaultColumnFilter), + isVisible: true, + Cell: props => <div> {updatedCellvalue(header, props.value)} </div>, + }) +}) + +//Optional Columns + +optionaldataheader.forEach(header => { + const isString = typeof optionalheader[0][header] === 'string'; + columns.push({ + Header: isString ? optionalheader[0][header] : optionalheader[0][header].name, + id: isString ? header : optionalheader[0][header].name, accessor: header, filter: (!isString && optionalheader[0][header].filter=== 'date') ? 'includes' : 'fuzzyText', Filter: isString ? DefaultColumnFilter : (filterTypes[optionalheader[0][header].filter] ? filterTypes[optionalheader[0][header].filter] : DefaultColumnFilter), isVisible: false, Cell: props => <div> {updatedCellvalue(header, props.value)} </div>, - }) - }); - + }) +}); + + let togglecolumns = localStorage.getItem(tablename); + if(togglecolumns){ + togglecolumns = JSON.parse(togglecolumns) + columns.forEach(column =>{ + togglecolumns.filter(tcol => { + column.isVisible = (tcol.Header === column.Header)?tcol.isVisible:column.isVisible; + }) + }) + } + function updatedCellvalue(key, value){ try{ if(key === 'blueprint_draft' && _.includes(value,'/task_draft/')){ @@ -514,7 +540,7 @@ function ViewTable(props) { return ( <div> <Table columns={columns} data={tbldata} defaultheader={defaultheader[0]} optionalheader={optionalheader[0]} - defaultSortColumn={defaultSortColumn} /> + defaultSortColumn={defaultSortColumn} tablename={tablename}/> </div> ) } diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Cycle/list.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Cycle/list.js index a6707597c01b944beb07fe04fb5bf9ed211c53d3..8ef0b80b71ff458e74b46ea862067edcdae6054c 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Cycle/list.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Cycle/list.js @@ -148,6 +148,7 @@ class CycleList extends Component{ defaultSortColumn= {this.defaultSortColumn} showaction="true" paths={this.state.paths} + tablename="cycle_list" /> : <></> } diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/list.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/list.js index 54bb34377ab8c14b87ae04412c491555dd673907..2d64cfce1891e9da59223f0c45832cd087ca5b49 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/list.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/list.js @@ -118,6 +118,7 @@ export class ProjectList extends Component{ paths={this.state.paths} keyaccessor="name" unittest={this.state.unittest} + tablename="project_list" /> : <div>No project found </div> } diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/SchedulingUnitList.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/SchedulingUnitList.js index fbf29d646003764f7db67b62a8015b00a868b8c7..229aae4c091a8d2943b1780c2ad0b01090f58652 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/SchedulingUnitList.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/SchedulingUnitList.js @@ -108,6 +108,7 @@ class SchedulingUnitList extends Component{ keyaccessor="id" paths={this.state.paths} unittest={this.state.unittest} + tablename="scheduleunit_list" /> :<div>No scheduling unit found </div> } diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js index 096a7c62e9530967a72d32fd558a38d549c9af75..3a443824d92d79c5ca8433a461fe12ef4efaebaa 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js @@ -184,6 +184,7 @@ class ViewSchedulingUnit extends Component{ keyaccessor="id" paths={this.state.paths} unittest={this.state.unittest} + tablename="scheduleunit_task_list" /> } </> diff --git a/SAS/TMSS/src/tmss/tmssapp/migrations/0001_initial.py b/SAS/TMSS/src/tmss/tmssapp/migrations/0001_initial.py index 1b122a91b85da11e7c974ce4aeb2fa88fd86669b..f327b9bb689bf9c622289872d7ffb9688182a768 100644 --- a/SAS/TMSS/src/tmss/tmssapp/migrations/0001_initial.py +++ b/SAS/TMSS/src/tmss/tmssapp/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.0.8 on 2020-09-02 16:52 +# Generated by Django 3.0.8 on 2020-09-09 09:23 from django.conf import settings import django.contrib.postgres.fields @@ -52,6 +52,7 @@ class Migration(migrations.Migration): ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)), ('description', models.CharField(help_text='A longer description of this object.', max_length=255)), ('location', models.CharField(help_text='Human-readable location of the cluster.', max_length=128)), + ('archive_site', models.BooleanField(help_text='TRUE if this cluster is an archive site, FALSE if not (f.e. a local cluster, or user-owned cluster).')), ], options={ 'abstract': False, diff --git a/SAS/TMSS/src/tmss/tmssapp/models/scheduling.py b/SAS/TMSS/src/tmss/tmssapp/models/scheduling.py index 9981cc0c58324cd0e5def205ac3decf9715e9655..d658ff43c17c43157e6e149c2a24bfc8024393da 100644 --- a/SAS/TMSS/src/tmss/tmssapp/models/scheduling.py +++ b/SAS/TMSS/src/tmss/tmssapp/models/scheduling.py @@ -320,6 +320,7 @@ class Filesystem(NamedCommon): class Cluster(NamedCommon): location = CharField(max_length=128, help_text='Human-readable location of the cluster.') + archive_site = BooleanField(help_text='TRUE if this cluster is an archive site, FALSE if not (f.e. a local cluster, or user-owned cluster).') class DataproductArchiveInfo(BasicCommon): diff --git a/SAS/TMSS/src/tmss/tmssapp/populate.py b/SAS/TMSS/src/tmss/tmssapp/populate.py index 67d8048759c79fc06e7d748627d57463e8e41439..9331a7264e4d97839d16ae9d989e01cfddf54de4 100644 --- a/SAS/TMSS/src/tmss/tmssapp/populate.py +++ b/SAS/TMSS/src/tmss/tmssapp/populate.py @@ -179,7 +179,7 @@ def populate_resources(apps, schema_editor): def populate_misc(apps, schema_editor): - cluster = Cluster.objects.create(name="CEP4", location="CIT") + cluster = Cluster.objects.create(name="CEP4", location="CIT", archive_site=False) fs = Filesystem.objects.create(name="LustreFS", cluster=cluster, capacity=3.6e15) diff --git a/SAS/TMSS/test/tmss_test_data_django_models.py b/SAS/TMSS/test/tmss_test_data_django_models.py index f3c6d8664c49fb4b09e05324c36982cdd0d23d8e..dd47feef976db59124e5a732d65038a5074543ab 100644 --- a/SAS/TMSS/test/tmss_test_data_django_models.py +++ b/SAS/TMSS/test/tmss_test_data_django_models.py @@ -369,7 +369,7 @@ def Subtask_test_data(task_blueprint: models.TaskBlueprint=None, subtask_templat stop_time = datetime.utcnow() + timedelta(minutes=10) if cluster is None: - cluster = models.Cluster.objects.create(name="dummy cluster", location="downstairs", tags=[]) + cluster = models.Cluster.objects.create(name="dummy cluster", location="downstairs", archive_site=True, tags=[]) if state is None: state = models.SubtaskState.objects.get(value='defining') @@ -445,6 +445,7 @@ def Filesystem_test_data(directory="/") -> dict: def Cluster_test_data(name="default cluster") -> dict: return {"name": name, "location": "upstairs", + "archive_site": True, "tags": ['tmss', 'testing']} def DataproductArchiveInfo_test_data() -> dict: diff --git a/SAS/TMSS/test/tmss_test_data_rest.py b/SAS/TMSS/test/tmss_test_data_rest.py index 12efcc9bb893093bbdbb817ce69409d0033f8692..fb60b94907ac79e5f2f00696c08c39de6249de38 100644 --- a/SAS/TMSS/test/tmss_test_data_rest.py +++ b/SAS/TMSS/test/tmss_test_data_rest.py @@ -445,6 +445,7 @@ class TMSSRESTTestDataCreator(): return {"name": name if name else "Cluster %s" % uuid.uuid4(), "description": 'My one cluster', "location": "upstairs", + "archive_site": False, "tags": ['tmss', 'testing']} def Subtask(self, cluster_url=None, task_blueprint_url=None, specifications_template_url=None, specifications_doc=None, state:str="defining"):