Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
R
ReqV
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
sage
ReqV
Commits
a651f523
Commit
a651f523
authored
Jul 06, 2018
by
Simone Vuotto
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add pattern creation wizard
parent
8b447131
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
301 additions
and
4 deletions
+301
-4
app-routing.module.ts
src/app/app-routing.module.ts
+2
-0
app.component.css
src/app/app.component.css
+1
-4
expression-wizard.component.html
...wizard/expression-wizard/expression-wizard.component.html
+9
-0
expression-wizard.component.ts
...n-wizard/expression-wizard/expression-wizard.component.ts
+44
-0
item.ts
src/app/pattern-wizard/item.ts
+24
-0
pattern-wizard.component.html
src/app/pattern-wizard/pattern-wizard.component.html
+102
-0
pattern-wizard.component.ts
src/app/pattern-wizard/pattern-wizard.component.ts
+111
-0
requirement.service.ts
src/app/services/requirement.service.ts
+4
-0
styles.css
src/styles.css
+4
-0
No files found.
src/app/app-routing.module.ts
View file @
a651f523
...
...
@@ -4,12 +4,14 @@ import {LoginComponent} from './login/login.component';
import
{
ProjectsComponent
}
from
'./projects/projects.component'
;
import
{
AuthGuard
}
from
'./auth.guard'
;
import
{
ProjectDetailsComponent
}
from
'./project-details/project-details.component'
;
import
{
PatternWizardComponent
}
from
'./pattern-wizard/pattern-wizard.component'
;
const
routes
:
Routes
=
[
{
path
:
''
,
component
:
LoginComponent
},
{
path
:
'projects'
,
component
:
ProjectsComponent
,
canActivate
:
[
AuthGuard
]
},
{
path
:
'projects/:projectId'
,
component
:
ProjectDetailsComponent
,
canActivate
:
[
AuthGuard
]},
{
path
:
'projects/:projectId/addReq'
,
component
:
PatternWizardComponent
,
canActivate
:
[
AuthGuard
]},
// otherwise redirect to home
{
path
:
'**'
,
redirectTo
:
''
}
...
...
src/app/app.component.css
View file @
a651f523
...
...
@@ -2,7 +2,4 @@
padding
:
4em
2em
;
}
.hline
{
border-bottom
:
1px
solid
#373a3c
;
margin-bottom
:
0.5em
;
}
src/app/pattern-wizard/expression-wizard/expression-wizard.component.html
0 → 100644
View file @
a651f523
<div
class=
"pl-2"
style=
"border-left: 1px solid #eeeeee; height: 100%;"
>
<p>
{{item.text}}
</p>
<div>
<fieldset
*
ngFor=
"let expr of exprs; let i = index; trackBy: customTrackBy"
>
<label
class=
"form-control-label"
for=
"exprInput"
>
Expr {{i + 1}}
</label>
<input
class=
"form-control"
id=
"exprInput"
[(
ngModel
)]="
exprs
[
i
]"
(
keyup
)="
update
()"
>
</fieldset>
</div>
</div>
src/app/pattern-wizard/expression-wizard/expression-wizard.component.ts
0 → 100644
View file @
a651f523
import
{
Component
,
Input
,
OnInit
,
Output
}
from
'@angular/core'
;
import
{
Item
}
from
'../item'
;
import
{
EventEmitter
}
from
'@angular/core'
;
@
Component
({
selector
:
'app-expression-wizard'
,
templateUrl
:
'./expression-wizard.component.html'
,
styleUrls
:
[
'./expression-wizard.component.css'
]
})
export
class
ExpressionWizardComponent
implements
OnInit
{
_item
:
Item
;
@
Output
()
itemChanged
=
new
EventEmitter
<
Item
>
();
exprs
:
string
[];
constructor
()
{
}
ngOnInit
()
{
}
get
item
():
Item
{
return
this
.
_item
;
}
@
Input
()
set
item
(
item
:
Item
)
{
this
.
exprs
=
new
Array
(
item
.
expressions
).
map
((
value
,
index
)
=>
'exp'
+
index
);
this
.
_item
=
item
;
this
.
update
();
console
.
log
(
this
.
exprs
);
}
update
()
{
// this.exprs[index] = event.target.value;
this
.
item
.
formatText
(
this
.
exprs
);
this
.
itemChanged
.
emit
(
this
.
_item
);
}
customTrackBy
(
index
:
number
,
obj
:
any
):
any
{
return
index
;
}
}
src/app/pattern-wizard/item.ts
0 → 100644
View file @
a651f523
export
class
Item
{
name
:
string
;
expressions
:
number
;
template
:
string
;
description
:
string
;
text
:
string
;
public
constructor
(
name
:
string
,
expressions
:
number
,
template
:
string
,
description
:
string
)
{
this
.
name
=
name
;
this
.
expressions
=
expressions
;
this
.
template
=
template
;
this
.
description
=
description
;
this
.
text
=
template
;
}
formatText
(
expr
:
string
[])
{
this
.
text
=
this
.
template
.
replace
(
/{
(\d
+
)
}/g
,
function
(
match
,
number
)
{
return
typeof
expr
[
number
]
!==
'undefined'
?
expr
[
number
]
:
match
;
});
return
this
.
text
;
}
}
src/app/pattern-wizard/pattern-wizard.component.html
0 → 100644
View file @
a651f523
<h1>
New Requirement
</h1>
<ol
class=
"breadcrumb mb-4"
>
<li
class=
"breadcrumb-item"
><a
href=
"#"
>
Projects
</a></li>
<li
class=
"breadcrumb-item"
><a
routerLink=
"/projects/{{project.id}}"
>
{{ project.name }}
</a></li>
<li
class=
"breadcrumb-item active"
>
New Requirement
</li>
</ol>
<div
class=
""
>
<div
class=
"form-group row pb-2"
>
<label
class=
"col-form-label col-sm-2 text-right"
for=
"reqText"
>
Req ID
</label>
<div
class=
"col-sm-10"
>
<input
class=
"form-control w-auto"
type=
"text"
id=
"reqId"
(
change
)="
updateReqId
($
event
)"
>
</div>
</div>
<div
class=
"form-group row"
>
<label
class=
"col-form-label col-sm-2 text-right"
for=
"reqText"
>
Requirement
</label>
<div
class=
"col-sm-10 pr-5"
>
<input
class=
"form-control w-100"
type=
"text"
id=
"reqText"
readonly=
""
data-cip-id=
"readOnlyInput"
value=
"{{req}}"
>
</div>
</div>
</div>
<div
class=
"row equal"
>
<div
class=
"col-md-6 pl-3 pr-1"
>
<div
class=
"card bg-secondary h-100"
>
<div
class=
"card-body"
>
<h4
class=
"card-title"
>
Scope
<small><i
class=
"fa fa-info-circle"
data-toggle=
"tooltip"
data-placement=
"right"
title=
"The scope defines when the body of the pattern should hold."
></i></small>
</h4>
<div
class=
"row"
>
<div
class=
"col-md-4 pr-0"
>
<div
class=
"dropdown"
>
<button
class=
"btn btn-secondary dropdown-toggle w-100"
type=
"button"
data-toggle=
"dropdown"
aria-haspopup=
"true"
aria-expanded=
"false"
>
{{selectedScope.name}}
</button>
<ul
dropdownMenu
class=
"dropdown-menu"
role=
"menu"
>
<li
*
ngFor=
"let scope of scopes"
(
click
)="
selectScope
(
scope
)"
class=
"dropdown-item"
>
{{scope.name}}
</li>
</ul>
</div>
<div
class=
"mt-2"
>
<small
class=
"text-justify "
><p
class=
"text-muted"
>
{{selectedScope.description}}
</p></small>
</div>
</div>
<div
class=
"col-md-8"
>
<app-expression-wizard
[
item
]="
selectedScope
"
(
itemChanged
)="
updateRequirement
($
event
)"
></app-expression-wizard>
</div>
</div>
</div>
</div>
</div>
<div
class=
"col-md-6 pl-1 pr-3"
>
<div
class=
"card bg-secondary h-100"
>
<div
class=
"card-body"
>
<h4
class=
"card-title"
>
Pattern
<small><i
class=
"fa fa-info-circle"
data-toggle=
"tooltip"
data-placement=
"right"
title=
"The main part of the specification."
></i></small>
</h4>
<div
class=
"row"
>
<div
class=
"col-md-4 pr-0"
>
<div
class=
"dropdown"
>
<button
class=
"btn btn-secondary dropdown-toggle w-100"
type=
"button"
data-toggle=
"dropdown"
aria-haspopup=
"true"
aria-expanded=
"false"
>
{{selectedPattern.name}}
</button>
<ul
dropdownMenu
class=
"dropdown-menu"
role=
"menu"
>
<li
*
ngFor=
"let pattern of patterns"
(
click
)="
selectPattern
(
pattern
)"
class=
"dropdown-item"
>
{{pattern.name}}
</li>
</ul>
</div>
<div
class=
"mt-2"
>
<small
class=
"text-justify"
><p
class=
"text-muted"
>
{{selectedPattern.description}}
</p></small>
</div>
</div>
<div
class=
"col-md-8"
>
<app-expression-wizard
[
item
]="
selectedPattern
"
(
itemChanged
)="
updateRequirement
($
event
)"
></app-expression-wizard>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class=
"pt-3 pr-1"
>
<button
class=
"btn btn-primary float-right"
(
click
)="
createRequirement
()"
>
Create
</button>
</div>
src/app/pattern-wizard/pattern-wizard.component.ts
0 → 100644
View file @
a651f523
import
{
Component
,
OnInit
}
from
'@angular/core'
;
import
{
Item
}
from
'./item'
;
import
{
ProjectService
}
from
'../services/project.service'
;
import
{
ActivatedRoute
,
Router
}
from
'@angular/router'
;
import
{
Project
}
from
'../models/project'
;
import
{
RequirementService
}
from
'../services/requirement.service'
;
import
{
Requirement
}
from
'../models/requirement'
;
@
Component
({
selector
:
'app-pattern-wizard'
,
templateUrl
:
'./pattern-wizard.component.html'
,
styleUrls
:
[
'./pattern-wizard.component.css'
]
})
export
class
PatternWizardComponent
implements
OnInit
{
scopes
:
Array
<
Item
>
=
[
new
Item
(
'Globally'
,
0
,
'Globally'
,
'The pattern must always hold'
),
new
Item
(
'Before R'
,
1
,
'Before {0}'
,
'The pattern must holds before the event R happens'
),
new
Item
(
'After Q'
,
1
,
'After {0}'
,
''
),
new
Item
(
'Between Q and R'
,
2
,
'Between {0} and {1}'
,
'The pattern must holds between events Q and R'
),
new
Item
(
'After Q until R'
,
2
,
'After {0} until {1}'
,
'The patter must holds after event Q and until event R'
)
];
patterns
:
Item
[]
=
[
new
Item
(
'Universality'
,
1
,
'it is always the case that {0} holds'
,
'This pattern describe a portion of a system
\'
s execution which contains only states that have a desired property.'
),
new
Item
(
'Absence'
,
1
,
' it is never the case that {0} holds'
,
'This pattern describes a portion of a system
\'
s execution that is free of certain events or states.'
),
new
Item
(
'Existence'
,
1
,
'{0} eventually holds'
,
'This pattern describes a portion of a system
\'
s execution that contains an instance of certain events or states. '
),
new
Item
(
'Invariance'
,
2
,
'it is always the case that if {0} holds, then {1} holds as well'
,
'This pattern describes an invariance relation between two events or states.'
),
new
Item
(
'Precedence'
,
2
,
'it is always the case that if {0} holds, then {1} previously held'
,
'This pattern describes relationships between a pair of events/states P and S where the occurrence of P'
+
' is a necessary pre-condition for an occurrence of S.'
),
new
Item
(
'PrecedenceChain12'
,
3
,
'it is always the case that if {0} holds and is succeeded by {1}, then {2} previously held'
,
'This pattern describes relationships between an event/state as a necessary pre-condition for an occurrence'
+
' of a chain of events/states'
),
new
Item
(
'PrecedenceChain21'
,
3
,
'it is always the case that if {0} holds, then {1} previously held and was preceded by {2}'
,
'This pattern describes relationships between a chain of events/states as a necessary pre-condition for '
+
'an occurrence of a event/state'
),
new
Item
(
'Response'
,
2
,
'it is always the case that if {0} holds, then {1} eventually holds'
,
'This pattern describes cause-effect relationships between a pair of events/states. An occurrence of the'
+
' first must be followed by an occurrence of the second.'
),
new
Item
(
'ResponseChain12'
,
3
,
'it is always the case that if {0} holds, then {1} eventually holds and is succeeded by {2}'
,
'This pattern describes cause-effect relationships between events/states. An occurrence of the first '
+
'must be followed by a chain of events/states.'
),
new
Item
(
'ResponseChain21'
,
3
,
'it is always the case that if {0} holds and is succeeded by {1}, then {2} eventually holds after {1}'
,
'This pattern describes cause-effect relationships between events/states. An occurrence of a chain of '
+
'events/states must be followed by an occurrence of the latter state/event.'
),
];
selectedScope
:
Item
=
null
;
selectedPattern
:
Item
=
null
;
reqId
:
string
=
null
;
req
=
''
;
project
=
new
Project
(
null
,
null
,
null
,
null
);
constructor
(
private
route
:
ActivatedRoute
,
private
router
:
Router
,
private
projectService
:
ProjectService
,
private
requirementService
:
RequirementService
)
{
}
ngOnInit
()
{
this
.
selectedScope
=
this
.
scopes
[
0
];
this
.
selectedPattern
=
this
.
patterns
[
0
];
this
.
getProject
();
}
getProject
()
{
const
projectId
=
+
this
.
route
.
snapshot
.
paramMap
.
get
(
'projectId'
);
this
.
projectService
.
getProject
(
projectId
).
subscribe
(
project
=>
this
.
project
=
project
);
}
selectScope
(
selected
:
Item
)
{
this
.
selectedScope
=
selected
;
}
selectPattern
(
selected
:
Item
)
{
this
.
selectedPattern
=
selected
;
}
updateReqId
(
event
)
{
this
.
reqId
=
event
.
target
.
value
;
this
.
updateRequirement
(
null
);
}
updateRequirement
(
item
)
{
let
reqIdLabel
=
''
;
if
(
this
.
reqId
!=
null
&&
this
.
reqId
.
length
>
0
)
{
reqIdLabel
=
'[ReqId='
+
this
.
reqId
+
'] '
;
}
this
.
req
=
reqIdLabel
+
this
.
selectedScope
.
text
+
', '
+
this
.
selectedPattern
.
text
+
'.'
;
}
createRequirement
()
{
const
requirement
=
new
Requirement
();
requirement
.
text
=
this
.
req
;
requirement
.
project
=
this
.
project
.
id
;
requirement
.
disabled
=
false
;
this
.
requirementService
.
createRequirement
(
requirement
).
subscribe
(
req
=>
{
this
.
router
.
navigateByUrl
(
'/projects/'
+
this
.
project
.
id
);
});
}
}
src/app/services/requirement.service.ts
View file @
a651f523
...
...
@@ -20,6 +20,10 @@ export class RequirementService {
return
this
.
http
.
get
<
Requirement
[]
>
(
this
.
requirementsUrl
,
{
params
:
params
});
}
createRequirement
(
req
:
Requirement
):
Observable
<
Requirement
>
{
return
this
.
http
.
post
<
Requirement
>
(
this
.
requirementsUrl
,
req
);
}
updateRequirement
(
req
:
Requirement
):
Observable
<
Requirement
>
{
return
this
.
http
.
put
<
Requirement
>
(
this
.
requirementsUrl
,
req
);
}
...
...
src/styles.css
View file @
a651f523
...
...
@@ -8,6 +8,10 @@
opacity
:
.5
;
}
.hline
{
border-bottom
:
1px
solid
#373a3c
;
margin-bottom
:
0.5em
;
}
.row-green
{
...
...
Write
Preview
Markdown
is supported
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