Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
anis
anis-client
Commits
54b4aa34
Commit
54b4aa34
authored
Aug 22, 2019
by
François Agneray
Browse files
#52
=> done
parent
959a83ae
Changes
30
Hide whitespace changes
Inline
Side-by-side
src/app/app.module.ts
View file @
54b4aa34
...
...
@@ -14,6 +14,7 @@ import { CoreModule } from './core/core.module';
import
{
StaticModule
}
from
'
./static/static.module
'
;
import
{
LoginModule
}
from
'
./login/login.module
'
;
import
{
SearchModule
}
from
'
./search/search.module
'
;
import
{
DetailModule
}
from
'
./detail/detail.module
'
;
import
{
AppRoutingModule
}
from
'
./app.routing
'
;
import
{
AppComponent
}
from
'
./core/containers/app.component
'
;
import
{
environment
}
from
'
../environments/environment
'
;
...
...
@@ -31,6 +32,7 @@ import { environment } from '../environments/environment';
StaticModule
,
LoginModule
,
SearchModule
,
DetailModule
,
AppRoutingModule
],
providers
:
[
{
provide
:
RouterStateSerializer
,
useClass
:
CustomRouterStateSerializer
}
],
...
...
src/app/detail/components/index.ts
0 → 100644
View file @
54b4aa34
import
{
ObjectDisplayComponent
}
from
'
./object-display.component
'
;
export
const
dummiesComponents
=
[
ObjectDisplayComponent
];
\ No newline at end of file
src/app/
search
/components/
result/detail
.component.css
→
src/app/
detail
/components/
object-display
.component.css
View file @
54b4aa34
File moved
src/app/detail/components/object-display.component.html
0 → 100644
View file @
54b4aa34
<div
class=
"row text-center mb-5"
>
<div
class=
"col"
>
<h1>
Object detail
</h1>
</div>
</div>
<div
class=
"row"
>
<table
class=
"table table-striped table-bordered"
>
<tr
*ngFor=
"let attribute of getAttributesVisible()"
>
<th>
{{ attribute.form_label }}
</th>
<td>
{{ object[attribute.label] }}
</td>
</tr>
</table>
</div>
\ No newline at end of file
src/app/detail/components/object-display.component.ts
0 → 100644
View file @
54b4aa34
import
{
Component
,
Input
,
ChangeDetectionStrategy
}
from
'
@angular/core
'
;
import
{
Attribute
}
from
'
../../metamodel/model
'
;
@
Component
({
selector
:
'
app-object-display
'
,
templateUrl
:
'
object-display.component.html
'
,
styleUrls
:
[
'
object-display.component.css
'
],
changeDetection
:
ChangeDetectionStrategy
.
OnPush
})
export
class
ObjectDisplayComponent
{
@
Input
()
attributeList
:
Attribute
[];
@
Input
()
object
:
any
;
getAttributesVisible
()
{
return
this
.
attributeList
.
filter
(
a
=>
a
.
detail
)
.
sort
((
a
,
b
)
=>
a
.
display_detail
-
b
.
display_detail
);;
}
}
src/app/
search
/containers/detail.component.css
→
src/app/
detail
/containers/detail.component.css
View file @
54b4aa34
File moved
src/app/detail/containers/detail.component.html
0 → 100644
View file @
54b4aa34
<div
*ngIf=
"objectIsLoading | async"
class=
"row justify-content-center mt-5"
>
<i
class=
"fas fa-circle-notch fa-spin fa-3x"
></i>
<span
class=
"sr-only"
>
Loading...
</span>
</div>
<div
*ngIf=
"objectIsLoaded | async"
>
<app-object-display
[attributeList]=
"attributeList | async"
[object]=
"object | async"
></app-object-display>
</div>
<div
*ngIf=
"!(pristine | async)"
class=
"row mt-5 justify-content-between"
>
<div
class=
"col"
>
<button
(click)=
"goBackToResult()"
class=
"btn btn-outline-secondary"
>
<i
class=
"fa fa-backward"
></i>
Back to search results
</button>
</div>
</div>
\ No newline at end of file
src/app/detail/containers/detail.component.ts
0 → 100644
View file @
54b4aa34
import
{
Component
,
OnInit
}
from
'
@angular/core
'
;
import
{
Location
}
from
'
@angular/common
'
;
import
{
Observable
}
from
'
rxjs
'
;
import
{
Store
}
from
'
@ngrx/store
'
;
import
*
as
detailActions
from
'
../store/detail.action
'
;
import
*
as
fromDetail
from
'
../store/detail.reducer
'
;
import
*
as
detailSelector
from
'
../store/detail.selector
'
;
import
*
as
searchSelector
from
'
../../search/store/search.selector
'
;
import
{
Attribute
}
from
'
../../metamodel/model
'
;
interface
StoreState
{
detail
:
fromDetail
.
State
;
}
@
Component
({
selector
:
'
app-detail-page
'
,
templateUrl
:
'
detail.component.html
'
,
styleUrls
:
[
'
detail.component.css
'
]
})
export
class
DetailComponent
implements
OnInit
{
public
pristine
:
Observable
<
boolean
>
;
public
attributeList
:
Observable
<
Attribute
[]
>
;
public
objectIsLoading
:
Observable
<
boolean
>
;
public
objectIsLoaded
:
Observable
<
boolean
>
;
public
object
:
Observable
<
any
>
;
constructor
(
private
location
:
Location
,
private
store
:
Store
<
StoreState
>
)
{
this
.
pristine
=
this
.
store
.
select
(
searchSelector
.
getPristine
);
this
.
attributeList
=
this
.
store
.
select
(
detailSelector
.
getAttributeList
);
this
.
objectIsLoading
=
this
.
store
.
select
(
detailSelector
.
getObjectIsLoading
);
this
.
objectIsLoaded
=
this
.
store
.
select
(
detailSelector
.
getObjectIsLoaded
);
this
.
object
=
this
.
store
.
select
(
detailSelector
.
getObject
);
}
ngOnInit
()
{
// Create a micro task that is processed after the current synchronous code
// This micro task prevent the expression has changed after view init error
Promise
.
resolve
(
null
).
then
(()
=>
this
.
store
.
dispatch
(
new
detailActions
.
InitDetailAction
()));
}
goBackToResult
()
{
this
.
location
.
back
();
}
}
src/app/detail/detail.module.ts
0 → 100644
View file @
54b4aa34
import
{
NgModule
}
from
'
@angular/core
'
;
import
{
StoreModule
}
from
'
@ngrx/store
'
;
import
{
EffectsModule
}
from
'
@ngrx/effects
'
;
import
{
SharedModule
}
from
'
../shared/shared.module
'
;
import
{
MetamodelModule
}
from
'
../metamodel/metamodel.module
'
;
import
{
DetailEffects
}
from
'
./store/detail.effects
'
;
import
{
DetailService
}
from
'
./store/detail.service
'
;
import
{
DetailRoutingModule
,
routedComponents
}
from
'
./detail.routing
'
;
import
{
dummiesComponents
}
from
'
./components
'
;
import
{
reducer
}
from
'
./store/detail.reducer
'
;
@
NgModule
({
imports
:
[
SharedModule
,
MetamodelModule
,
DetailRoutingModule
,
StoreModule
.
forFeature
(
'
detail
'
,
reducer
),
EffectsModule
.
forFeature
([
DetailEffects
])
],
declarations
:
[
routedComponents
,
dummiesComponents
],
providers
:
[
DetailService
]
})
export
class
DetailModule
{
}
src/app/detail/detail.routing.ts
0 → 100644
View file @
54b4aa34
import
{
NgModule
}
from
'
@angular/core
'
;
import
{
Routes
,
RouterModule
}
from
'
@angular/router
'
;
import
{
DetailComponent
}
from
'
./containers/detail.component
'
;
const
routes
:
Routes
=
[
{
path
:
'
detail/:dname/:objectSelected
'
,
component
:
DetailComponent
}
];
@
NgModule
({
imports
:
[
RouterModule
.
forChild
(
routes
)],
exports
:
[
RouterModule
]
})
export
class
DetailRoutingModule
{
}
export
const
routedComponents
=
[
DetailComponent
];
src/app/detail/store/detail.action.ts
0 → 100644
View file @
54b4aa34
import
{
Action
}
from
'
@ngrx/store
'
;
import
{
Attribute
}
from
'
../../metamodel/model
'
export
const
INIT_DETAIL
=
'
[Detail] Init Detail
'
;
export
const
LOAD_ATTRIBUTE_LIST
=
'
[Detail] Load Attribute List
'
;
export
const
LOAD_ATTRIBUTE_LIST_SUCCESS
=
'
[Detail] Load Attribute List Success
'
;
export
const
LOAD_ATTRIBUTE_LIST_FAIL
=
'
[Detail] Load Attribute List Fail
'
;
export
const
COPY_ATTRIBUTE_LIST
=
'
[Detail] Copy Attribute List
'
;
export
const
RETRIEVE_OBJECT
=
'
[Detail] Retrieve Object
'
;
export
const
RETRIEVE_OBJECT_SUCCESS
=
'
[Detail] Retrieve Object Success
'
;
export
const
RETRIEVE_OBJECT_FAIL
=
'
[Detail] Retrieve Object Fail
'
;
export
class
InitDetailAction
implements
Action
{
type
=
INIT_DETAIL
;
constructor
(
public
payload
:
{}
=
null
)
{
}
}
export
class
LoadAttributeListAction
implements
Action
{
type
=
LOAD_ATTRIBUTE_LIST
;
constructor
(
public
payload
:
{}
=
null
)
{
}
}
export
class
LoadAttributeListSuccessAction
implements
Action
{
type
=
LOAD_ATTRIBUTE_LIST_SUCCESS
;
constructor
(
public
payload
:
Attribute
[])
{
}
}
export
class
LoadAttributeListFailAction
implements
Action
{
type
=
LOAD_ATTRIBUTE_LIST_FAIL
;
constructor
(
public
payload
:
{}
=
null
)
{
}
}
export
class
CopyAttributeListAction
implements
Action
{
type
=
COPY_ATTRIBUTE_LIST
;
constructor
(
public
payload
:
{}
=
null
)
{
}
}
export
class
RetrieveObjectAction
implements
Action
{
type
=
RETRIEVE_OBJECT
;
constructor
(
public
payload
:
{
datasetName
:
string
,
idAttribute
:
number
,
id
:
string
}
=
null
)
{
}
}
export
class
RetrieveObjectSuccessAction
implements
Action
{
type
=
RETRIEVE_OBJECT_SUCCESS
;
constructor
(
public
payload
:
any
)
{
}
}
export
class
RetrieveObjectFailAction
implements
Action
{
type
=
RETRIEVE_OBJECT_FAIL
;
constructor
(
public
payload
:
{}
=
null
)
{
}
}
export
type
Actions
=
InitDetailAction
|
LoadAttributeListAction
|
LoadAttributeListSuccessAction
|
LoadAttributeListFailAction
|
CopyAttributeListAction
|
RetrieveObjectAction
|
RetrieveObjectSuccessAction
|
RetrieveObjectFailAction
;
\ No newline at end of file
src/app/detail/store/detail.effects.ts
0 → 100644
View file @
54b4aa34
import
{
Injectable
}
from
'
@angular/core
'
;
import
{
ToastrService
}
from
'
ngx-toastr
'
;
import
{
Effect
,
Actions
,
ofType
}
from
'
@ngrx/effects
'
;
import
{
Store
}
from
'
@ngrx/store
'
;
import
{
of
}
from
'
rxjs
'
;
import
{
switchMap
,
map
,
catchError
,
tap
,
withLatestFrom
}
from
'
rxjs/operators
'
;
import
*
as
detailActions
from
'
./detail.action
'
;
import
*
as
fromRouter
from
'
@ngrx/router-store
'
;
import
*
as
fromMetamodel
from
'
../../metamodel/reducers
'
;
import
*
as
fromSearch
from
'
../../search/store/search.reducer
'
;
import
*
as
fromDetail
from
'
./detail.reducer
'
;
import
*
as
utils
from
'
../../shared/utils
'
;
import
{
Attribute
}
from
'
../../metamodel/model
'
;
import
{
DetailService
}
from
'
./detail.service
'
;
import
{
AttributeService
}
from
'
src/app/metamodel/services/attribute.service
'
;
interface
State
{
router
:
fromRouter
.
RouterReducerState
<
utils
.
RouterStateUrl
>
,
metamodel
:
fromMetamodel
.
State
,
search
:
fromSearch
.
State
,
detail
:
fromDetail
.
State
}
@
Injectable
()
export
class
DetailEffects
{
constructor
(
private
actions$
:
Actions
,
private
detailService
:
DetailService
,
private
attributeService
:
AttributeService
,
private
toastr
:
ToastrService
,
private
store$
:
Store
<
State
>
)
{
}
@
Effect
()
initDetailAction$
=
this
.
actions$
.
pipe
(
ofType
(
detailActions
.
INIT_DETAIL
),
withLatestFrom
(
this
.
store$
),
map
(([
action
,
state
])
=>
{
if
(
state
.
search
.
pristine
)
{
return
new
detailActions
.
LoadAttributeListAction
();
}
else
{
return
new
detailActions
.
CopyAttributeListAction
();
}
})
);
@
Effect
()
loadAttributeAction$
=
this
.
actions$
.
pipe
(
ofType
(
detailActions
.
LOAD_ATTRIBUTE_LIST
),
withLatestFrom
(
this
.
store$
),
switchMap
(([
action
,
state
])
=>
{
const
datasetName
=
state
.
router
.
state
.
params
.
dname
;
return
this
.
attributeService
.
retrieveAttributeList
(
datasetName
).
pipe
(
map
((
attributeList
:
Attribute
[])
=>
new
detailActions
.
LoadAttributeListSuccessAction
(
attributeList
)),
catchError
(()
=>
of
(
new
detailActions
.
LoadAttributeListFailAction
()))
);
})
);
@
Effect
()
loadAttributeSuccessAction$
=
this
.
actions$
.
pipe
(
ofType
(
detailActions
.
LOAD_ATTRIBUTE_LIST_SUCCESS
),
switchMap
(
_
=>
of
(
new
detailActions
.
RetrieveObjectAction
()))
);
@
Effect
({
dispatch
:
false
})
loadAttributeFailAction$
=
this
.
actions$
.
pipe
(
ofType
(
detailActions
.
LOAD_ATTRIBUTE_LIST_FAIL
),
tap
(
_
=>
this
.
toastr
.
error
(
'
Loading Failed!
'
,
'
The attribute list loading failed
'
))
);
@
Effect
()
copyAttributeAction$
=
this
.
actions$
.
pipe
(
ofType
(
detailActions
.
COPY_ATTRIBUTE_LIST
),
withLatestFrom
(
this
.
store$
),
switchMap
(([
action
,
state
])
=>
{
const
attributeList
=
state
.
metamodel
.
attribute
.
datasetAttributeList
;
return
of
(
new
detailActions
.
LoadAttributeListSuccessAction
(
attributeList
));
})
);
@
Effect
()
retrieveObjectAction$
=
this
.
actions$
.
pipe
(
ofType
(
detailActions
.
RETRIEVE_OBJECT
),
withLatestFrom
(
this
.
store$
),
switchMap
(([
action
,
state
])
=>
{
const
datasetName
=
state
.
router
.
state
.
params
.
dname
;
const
objectSelected
=
state
.
router
.
state
.
params
.
objectSelected
;
const
attributes
=
state
.
detail
.
attributeList
;
const
attributeCriterionId
=
attributes
.
find
(
a
=>
a
.
search_flag
===
'
ID
'
);
const
attributesOutputList
=
attributes
.
filter
(
a
=>
a
.
detail
).
map
(
a
=>
a
.
id
);
return
this
.
detailService
.
retrieveObject
(
datasetName
,
attributeCriterionId
.
id
,
objectSelected
,
attributesOutputList
).
pipe
(
map
((
object
:
any
[])
=>
new
detailActions
.
RetrieveObjectSuccessAction
(
object
[
0
])),
catchError
(()
=>
of
(
new
detailActions
.
RetrieveObjectFailAction
()))
);
})
);
@
Effect
({
dispatch
:
false
})
retrieveObjectFailAction$
=
this
.
actions$
.
pipe
(
ofType
(
detailActions
.
RETRIEVE_OBJECT_FAIL
),
tap
(
_
=>
this
.
toastr
.
error
(
'
Loading Failed!
'
,
'
The object loading failed
'
))
);
}
\ No newline at end of file
src/app/detail/store/detail.reducer.ts
0 → 100644
View file @
54b4aa34
import
*
as
actions
from
'
./detail.action
'
;
import
{
Attribute
}
from
'
../../metamodel/model
'
;
export
interface
State
{
attributeList
:
Attribute
[];
objectIsLoading
:
boolean
;
objectIsLoaded
:
boolean
;
object
:
any
;
}
const
initialState
:
State
=
{
attributeList
:
null
,
objectIsLoading
:
false
,
objectIsLoaded
:
false
,
object
:
null
};
export
function
reducer
(
state
:
State
=
initialState
,
action
:
actions
.
Actions
):
State
{
switch
(
action
.
type
)
{
case
actions
.
INIT_DETAIL
:
return
{
...
state
,
objectIsLoading
:
true
};
case
actions
.
LOAD_ATTRIBUTE_LIST_SUCCESS
:
const
attributeList
=
action
.
payload
as
Attribute
[];
return
{
...
state
,
attributeList
}
case
actions
.
RETRIEVE_OBJECT_SUCCESS
:
const
object
=
action
.
payload
as
any
;
return
{
...
state
,
objectIsLoading
:
false
,
objectIsLoaded
:
true
,
object
};
case
actions
.
LOAD_ATTRIBUTE_LIST_FAIL
:
case
actions
.
RETRIEVE_OBJECT_FAIL
:
return
{
...
state
,
objectIsLoading
:
false
,
objectIsLoaded
:
false
};
default
:
return
state
;
}
}
export
const
getAttributeList
=
(
state
:
State
)
=>
state
.
attributeList
;
export
const
getObjectIsLoading
=
(
state
:
State
)
=>
state
.
objectIsLoading
;
export
const
getObjectIsLoaded
=
(
state
:
State
)
=>
state
.
objectIsLoaded
;
export
const
getObject
=
(
state
:
State
)
=>
state
.
object
;
\ No newline at end of file
src/app/detail/store/detail.selector.ts
0 → 100644
View file @
54b4aa34
import
{
createSelector
,
createFeatureSelector
}
from
'
@ngrx/store
'
;
import
*
as
detail
from
'
./detail.reducer
'
;
export
const
getDetailState
=
createFeatureSelector
<
detail
.
State
>
(
'
detail
'
);
export
const
getAttributeList
=
createSelector
(
getDetailState
,
detail
.
getAttributeList
);
export
const
getObjectIsLoading
=
createSelector
(
getDetailState
,
detail
.
getObjectIsLoading
);
export
const
getObjectIsLoaded
=
createSelector
(
getDetailState
,
detail
.
getObjectIsLoaded
);
export
const
getObject
=
createSelector
(
getDetailState
,
detail
.
getObject
);
\ No newline at end of file
src/app/detail/store/detail.service.ts
0 → 100644
View file @
54b4aa34
import
{
Injectable
}
from
'
@angular/core
'
;
import
{
HttpClient
}
from
'
@angular/common/http
'
;
import
{
environment
}
from
'
../../../environments/environment
'
;
@
Injectable
()
export
class
DetailService
{
private
API_PATH
:
string
=
environment
.
apiUrl
+
'
/search
'
;
constructor
(
private
http
:
HttpClient
)
{
}
retrieveObject
(
datasetName
:
string
,
attributeCriterionId
:
number
,
objectSelected
:
string
,
attributesOutputList
:
number
[])
{
const
query
=
datasetName
+
'
?c=
'
+
attributeCriterionId
+
"
::eq::
"
+
objectSelected
+
"
&a=
"
+
attributesOutputList
.
join
(
'
;
'
);
return
this
.
http
.
get
<
any
[]
>
(
this
.
API_PATH
+
'
/data/
'
+
query
);
}
}
src/app/metamodel/effects/attribute.effects.ts
View file @
54b4aa34
...
...
@@ -2,13 +2,11 @@ import { Injectable } from '@angular/core';
import
{
ToastrService
}
from
'
ngx-toastr
'
;
import
{
Effect
,
Actions
,
ofType
}
from
'
@ngrx/effects
'
;
import
{
Store
}
from
'
@ngrx/store
'
;
import
{
of
}
from
'
rxjs
'
;
import
{
withLatestFrom
,
switchMap
,
map
,
catchError
,
tap
}
from
'
rxjs/operators
'
;
import
{
switchMap
,
map
,
catchError
,
tap
}
from
'
rxjs/operators
'
;
import
{
Attribute
}
from
'
../model
'
;
import
*
as
attributeActions
from
'
../action/attribute.action
'
;
import
*
as
fromMetamodel
from
'
../reducers
'
;
import
{
AttributeService
}
from
'
../services/attribute.service
'
;
@
Injectable
()
...
...
@@ -16,8 +14,7 @@ export class AttributeEffects {
constructor
(
private
actions$
:
Actions
,
private
attributeService
:
AttributeService
,
private
toastr
:
ToastrService
,
private
store$
:
Store
<
{
metamodel
:
fromMetamodel
.
State
}
>
private
toastr
:
ToastrService
)
{
}
@
Effect
()
...
...
src/app/search/components/index.ts
View file @
54b4aa34
...
...
@@ -9,7 +9,6 @@ import { SummaryComponent } from './summary.component';
import
{
criteriaComponents
}
from
'
./criteria/search-type
'
;
import
{
UrlDisplayComponent
}
from
'
./result/url-display.component
'
;
import
{
DatatableComponent
}
from
'
./result/datatable.component
'
;
import
{
DetailComponent
}
from
'
./result/detail.component
'
;
import
{
ModalComponent
}
from
'
./result/modal.component
'
;
export
const
dummiesComponents
=
[
...
...
@@ -24,6 +23,5 @@ export const dummiesComponents = [
SummaryComponent
,
UrlDisplayComponent
,
DatatableComponent
,
DetailComponent
,
ModalComponent
];
src/app/search/components/result/datatable.component.html
View file @
54b4aa34
...
...
@@ -41,10 +41,7 @@
{{ datum[attribute.name] }}
</a>
</div>
<div
*ngSwitchCase=
"'int-link'"
>
<!-- <a [routerLink]="getAttributeUriAction(attribute.name, datum[attribute.label])">
{{ datum[attribute.name] }}</a> -->
<a
routerLink=
"/search/result/{{ datasetName }}/{{ datum[attribute.label] }}"
[queryParams]=
"queryParams"
>
<a
routerLink=
"/detail/{{ datasetName }}/{{ datum[attribute.label] }}"
>
{{ datum[attribute.label] }}
</a>
</div>
...
...
@@ -54,8 +51,8 @@
{{ datum[attribute.label] }}
</a>
</div>
<div
*ngSwitchCase=
"'int-btn'"
>
<a
routerLink=
"/
search/result
/{{ datasetName }}/{{ datum[attribute.label] }}"
[queryParams]=
"queryParams"
class=
"btn btn-outline-primary btn-sm"
>
<a
routerLink=
"/
detail
/{{ datasetName }}/{{ datum[attribute.label] }}"
class=
"btn btn-outline-primary btn-sm"
>
{{ datum[attribute.label] }}
</a>
</div>
...
...
src/app/search/components/result/datatable.component.ts
View file @
54b4aa34
...
...
@@ -38,6 +38,11 @@ export class DatatableComponent {
this
.
getSearchData
.
emit
(
1
);
}
getAttributeId
(
attributeName
:
string
):
number
{
const
attribute
=
this
.
datasetAttributeList
.
find
(
a
=>
a
.
name
===
attributeName
);
return
attribute
.
id
;
}
getAttributeRenderer
(
attributeName
:
string
):
string
{
const
attribute
=
this
.
datasetAttributeList
.
find
(
a
=>
a
.
name
===
attributeName
);
return
attribute
.
renderer
;
...
...
src/app/search/components/result/detail.component.html
deleted
100644 → 0
View file @
959a83ae
<p>
dataset: {{ datasetName }}
</p>
<p
*ngFor=
"let attribute of searchMeta.attributes_selected"
>
{{ attribute.label }}: {{ getData(attribute.name) }}
</p>
\ No newline at end of file
Prev
1
2
Next
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment