Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
erp5
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
Romain Courteaud
erp5
Commits
f6115654
Commit
f6115654
authored
Nov 17, 2020
by
Romain Courteaud
🐸
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
erp5_forge: WIP action to commit from erp5js
parent
320e734c
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
1345 additions
and
2 deletions
+1345
-2
bt5/erp5_forge/ActionTemplateItem/portal_types/Business%20Template/git_commit.xml
...plateItem/portal_types/Business%20Template/git_commit.xml
+2
-2
bt5/erp5_forge/ActionTemplateItem/portal_types/Business%20Template/git_commit_action.xml
...em/portal_types/Business%20Template/git_commit_action.xml
+96
-0
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/BusinessTemplate_doVcsDiffAsJson.py
...portal_skins/erp5_vcs/BusinessTemplate_doVcsDiffAsJson.py
+30
-0
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/BusinessTemplate_doVcsDiffAsJson.xml
...ortal_skins/erp5_vcs/BusinessTemplate_doVcsDiffAsJson.xml
+62
-0
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/BusinessTemplate_viewVcsStatusDialog.xml
...l_skins/erp5_vcs/BusinessTemplate_viewVcsStatusDialog.xml
+139
-0
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/BusinessTemplate_viewVcsStatusDialog/your_vcs_status_gadget.xml
...ssTemplate_viewVcsStatusDialog/your_vcs_status_gadget.xml
+153
-0
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/gadget_vcs_status.css.css
...plateItem/portal_skins/erp5_vcs/gadget_vcs_status.css.css
+39
-0
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/gadget_vcs_status.css.xml
...plateItem/portal_skins/erp5_vcs/gadget_vcs_status.css.xml
+32
-0
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/gadget_vcs_status.html.html
...ateItem/portal_skins/erp5_vcs/gadget_vcs_status.html.html
+19
-0
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/gadget_vcs_status.html.xml
...lateItem/portal_skins/erp5_vcs/gadget_vcs_status.html.xml
+32
-0
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/gadget_vcs_status.js.js
...emplateItem/portal_skins/erp5_vcs/gadget_vcs_status.js.js
+630
-0
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/gadget_vcs_status.js.xml
...mplateItem/portal_skins/erp5_vcs/gadget_vcs_status.js.xml
+32
-0
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/gadget_vcs_status.less.bin
...lateItem/portal_skins/erp5_vcs/gadget_vcs_status.less.bin
+50
-0
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/gadget_vcs_status.less.xml
...lateItem/portal_skins/erp5_vcs/gadget_vcs_status.less.xml
+28
-0
bt5/erp5_forge/bt/template_action_path_list
bt5/erp5_forge/bt/template_action_path_list
+1
-0
No files found.
bt5/erp5_forge/ActionTemplateItem/portal_types/Business%20Template/git_commit.xml
View file @
f6115654
...
@@ -16,13 +16,13 @@
...
@@ -16,13 +16,13 @@
<key>
<string>
categories
</string>
</key>
<key>
<string>
categories
</string>
</key>
<value>
<value>
<tuple>
<tuple>
<string>
action_type/object_view
</string>
<string>
action_type/object_
onlyxhtml_
view
</string>
</tuple>
</tuple>
</value>
</value>
</item>
</item>
<item>
<item>
<key>
<string>
category
</string>
</key>
<key>
<string>
category
</string>
</key>
<value>
<string>
object_view
</string>
</value>
<value>
<string>
object_
onlyxhtml_
view
</string>
</value>
</item>
</item>
<item>
<item>
<key>
<string>
condition
</string>
</key>
<key>
<string>
condition
</string>
</key>
...
...
bt5/erp5_forge/ActionTemplateItem/portal_types/Business%20Template/git_commit_action.xml
0 → 100644
View file @
f6115654
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"ActionInformation"
module=
"Products.CMFCore.ActionInformation"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
action
</string>
</key>
<value>
<persistent>
<string
encoding=
"base64"
>
AAAAAAAAAAI=
</string>
</persistent>
</value>
</item>
<item>
<key>
<string>
categories
</string>
</key>
<value>
<tuple>
<string>
action_type/object_onlyjio_action
</string>
</tuple>
</value>
</item>
<item>
<key>
<string>
category
</string>
</key>
<value>
<string>
object_onlyjio_action
</string>
</value>
</item>
<item>
<key>
<string>
condition
</string>
</key>
<value>
<persistent>
<string
encoding=
"base64"
>
AAAAAAAAAAM=
</string>
</persistent>
</value>
</item>
<item>
<key>
<string>
description
</string>
</key>
<value>
<none/>
</value>
</item>
<item>
<key>
<string>
icon
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
git_commit_action
</string>
</value>
</item>
<item>
<key>
<string>
permissions
</string>
</key>
<value>
<tuple>
<string>
Manage portal
</string>
</tuple>
</value>
</item>
<item>
<key>
<string>
priority
</string>
</key>
<value>
<float>
4.5
</float>
</value>
</item>
<item>
<key>
<string>
title
</string>
</key>
<value>
<string>
Git
</string>
</value>
</item>
<item>
<key>
<string>
visible
</string>
</key>
<value>
<int>
1
</int>
</value>
</item>
</dictionary>
</pickle>
</record>
<record
id=
"2"
aka=
"AAAAAAAAAAI="
>
<pickle>
<global
name=
"Expression"
module=
"Products.CMFCore.Expression"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
text
</string>
</key>
<value>
<string>
string:${object_url}/BusinessTemplate_viewVcsStatusDialog
</string>
</value>
</item>
</dictionary>
</pickle>
</record>
<record
id=
"3"
aka=
"AAAAAAAAAAM="
>
<pickle>
<global
name=
"Expression"
module=
"Products.CMFCore.Expression"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
text
</string>
</key>
<value>
<string>
python: here.getInstallationState() not in (\'installed\', \'replaced\') and here.isVcsType(\'git\')
</string>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/BusinessTemplate_doVcsDiffAsJson.py
0 → 100644
View file @
f6115654
import
json
vcs_tool
=
context
.
getVcsTool
()
result_dict
=
{
'added_list'
:
[],
'modified_list'
:
[],
'deleted_list'
:
[]
}
for
path
in
modified
:
result_dict
[
'modified_list'
].
append
({
'path'
:
path
,
# 'edit_path': vcs_tool.editPath(path, True),
'diff'
:
vcs_tool
.
diff
(
path
)
})
for
path
in
added
:
result_dict
[
'added_list'
].
append
({
'path'
:
path
})
for
path
in
deleted
:
result_dict
[
'deleted_list'
].
append
({
'path'
:
path
})
if
REQUEST
is
not
None
:
REQUEST
.
RESPONSE
.
setHeader
(
'Content-Type'
,
'application/hal+json'
)
return
json
.
dumps
(
result_dict
,
indent
=
2
)
else
:
return
result_dict
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/BusinessTemplate_doVcsDiffAsJson.xml
0 → 100644
View file @
f6115654
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"PythonScript"
module=
"Products.PythonScripts.PythonScript"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
Script_magic
</string>
</key>
<value>
<int>
3
</int>
</value>
</item>
<item>
<key>
<string>
_bind_names
</string>
</key>
<value>
<object>
<klass>
<global
name=
"NameAssignments"
module=
"Shared.DC.Scripts.Bindings"
/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key>
<string>
_asgns
</string>
</key>
<value>
<dictionary>
<item>
<key>
<string>
name_container
</string>
</key>
<value>
<string>
container
</string>
</value>
</item>
<item>
<key>
<string>
name_context
</string>
</key>
<value>
<string>
context
</string>
</value>
</item>
<item>
<key>
<string>
name_m_self
</string>
</key>
<value>
<string>
script
</string>
</value>
</item>
<item>
<key>
<string>
name_subpath
</string>
</key>
<value>
<string>
traverse_subpath
</string>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key>
<string>
_params
</string>
</key>
<value>
<string>
added=(), modified=(), deleted=(), REQUEST=None
</string>
</value>
</item>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
BusinessTemplate_doVcsDiffAsJson
</string>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/BusinessTemplate_viewVcsStatusDialog.xml
0 → 100644
View file @
f6115654
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"ERP5 Form"
module=
"erp5.portal_type"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
_objects
</string>
</key>
<value>
<tuple/>
</value>
</item>
<item>
<key>
<string>
action
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
action_title
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
description
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
edit_order
</string>
</key>
<value>
<list/>
</value>
</item>
<item>
<key>
<string>
encoding
</string>
</key>
<value>
<string>
UTF-8
</string>
</value>
</item>
<item>
<key>
<string>
enctype
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
group_list
</string>
</key>
<value>
<list>
<string>
left
</string>
<string>
right
</string>
<string>
center
</string>
<string>
bottom
</string>
<string>
hidden
</string>
</list>
</value>
</item>
<item>
<key>
<string>
groups
</string>
</key>
<value>
<dictionary>
<item>
<key>
<string>
bottom
</string>
</key>
<value>
<list/>
</value>
</item>
<item>
<key>
<string>
center
</string>
</key>
<value>
<list>
<string>
your_vcs_status_gadget
</string>
</list>
</value>
</item>
<item>
<key>
<string>
hidden
</string>
</key>
<value>
<list/>
</value>
</item>
<item>
<key>
<string>
left
</string>
</key>
<value>
<list/>
</value>
</item>
<item>
<key>
<string>
right
</string>
</key>
<value>
<list/>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
BusinessTemplate_viewVcsStatusDialog
</string>
</value>
</item>
<item>
<key>
<string>
method
</string>
</key>
<value>
<string>
POST
</string>
</value>
</item>
<item>
<key>
<string>
name
</string>
</key>
<value>
<string>
BusinessTemplate_viewVcsStatusDialog
</string>
</value>
</item>
<item>
<key>
<string>
portal_type
</string>
</key>
<value>
<string>
ERP5 Form
</string>
</value>
</item>
<item>
<key>
<string>
pt
</string>
</key>
<value>
<string>
form_dialog
</string>
</value>
</item>
<item>
<key>
<string>
row_length
</string>
</key>
<value>
<int>
4
</int>
</value>
</item>
<item>
<key>
<string>
stored_encoding
</string>
</key>
<value>
<string>
UTF-8
</string>
</value>
</item>
<item>
<key>
<string>
title
</string>
</key>
<value>
<string>
VCS Status
</string>
</value>
</item>
<item>
<key>
<string>
unicode_mode
</string>
</key>
<value>
<int>
0
</int>
</value>
</item>
<item>
<key>
<string>
update_action
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
update_action_title
</string>
</key>
<value>
<string></string>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/BusinessTemplate_viewVcsStatusDialog/your_vcs_status_gadget.xml
0 → 100644
View file @
f6115654
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"ProxyField"
module=
"Products.ERP5Form.ProxyField"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
delegated_list
</string>
</key>
<value>
<list>
<string>
gadget_url
</string>
<string>
renderjs_extra
</string>
<string>
title
</string>
</list>
</value>
</item>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
your_vcs_status_gadget
</string>
</value>
</item>
<item>
<key>
<string>
message_values
</string>
</key>
<value>
<dictionary>
<item>
<key>
<string>
external_validator_failed
</string>
</key>
<value>
<string>
The input failed the external validator.
</string>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key>
<string>
overrides
</string>
</key>
<value>
<dictionary>
<item>
<key>
<string>
field_id
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
form_id
</string>
</key>
<value>
<string></string>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key>
<string>
tales
</string>
</key>
<value>
<dictionary>
<item>
<key>
<string>
field_id
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
form_id
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
gadget_url
</string>
</key>
<value>
<persistent>
<string
encoding=
"base64"
>
AAAAAAAAAAI=
</string>
</persistent>
</value>
</item>
<item>
<key>
<string>
renderjs_extra
</string>
</key>
<value>
<persistent>
<string
encoding=
"base64"
>
AAAAAAAAAAM=
</string>
</persistent>
</value>
</item>
<item>
<key>
<string>
title
</string>
</key>
<value>
<persistent>
<string
encoding=
"base64"
>
AAAAAAAAAAQ=
</string>
</persistent>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key>
<string>
values
</string>
</key>
<value>
<dictionary>
<item>
<key>
<string>
field_id
</string>
</key>
<value>
<string>
my_gadget_field
</string>
</value>
</item>
<item>
<key>
<string>
form_id
</string>
</key>
<value>
<string>
Base_viewFieldLibrary
</string>
</value>
</item>
<item>
<key>
<string>
gadget_url
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
renderjs_extra
</string>
</key>
<value>
<list/>
</value>
</item>
<item>
<key>
<string>
title
</string>
</key>
<value>
<string>
Gadget
</string>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record
id=
"2"
aka=
"AAAAAAAAAAI="
>
<pickle>
<global
name=
"TALESMethod"
module=
"Products.Formulator.TALESField"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
_text
</string>
</key>
<value>
<string>
string: gadget_vcs_status.html
</string>
</value>
</item>
</dictionary>
</pickle>
</record>
<record
id=
"3"
aka=
"AAAAAAAAAAM="
>
<pickle>
<global
name=
"TALESMethod"
module=
"Products.Formulator.TALESField"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
_text
</string>
</key>
<value>
<string>
python: [(\'diff_url\', \'%s/BusinessTemplate_doVcsDiffAsJson\' % here.absolute_url()), (\'get_tree_url\', \'%s/tree.xml\' % here.absolute_url()), (\'remote_url\', here.getVcsTool().getRemoteUrl()), (\'remote_comment\', here.getVcsTool().getRemoteComment())]
</string>
</value>
</item>
</dictionary>
</pickle>
</record>
<record
id=
"4"
aka=
"AAAAAAAAAAQ="
>
<pickle>
<global
name=
"TALESMethod"
module=
"Products.Formulator.TALESField"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
_text
</string>
</key>
<value>
<string>
string:
</string>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/gadget_vcs_status.css.css
0 → 100644
View file @
f6115654
div
[
data-gadget-url
$
=
"gadget_vcs_status.html"
]
li
li
{
padding-left
:
1em
;
}
div
[
data-gadget-url
$
=
"gadget_vcs_status.html"
]
li
input
.showhide
{
display
:
none
;
}
div
[
data-gadget-url
$
=
"gadget_vcs_status.html"
]
li
input
.showhide
:checked
~
label
.show
{
display
:
none
;
}
div
[
data-gadget-url
$
=
"gadget_vcs_status.html"
]
li
input
.showhide
:checked
~
ul
{
display
:
none
;
}
div
[
data-gadget-url
$
=
"gadget_vcs_status.html"
]
li
input
.showhide
:not
(
:checked
)
~
label
.hide
{
display
:
none
;
}
div
[
data-gadget-url
$
=
"gadget_vcs_status.html"
]
li
label
{
display
:
inline-block
;
}
div
[
data-gadget-url
$
=
"gadget_vcs_status.html"
]
li
label
.showhide
{
width
:
1em
;
}
div
[
data-gadget-url
$
=
"gadget_vcs_status.html"
]
li
label
input
{
margin
:
0
3pt
;
}
div
[
data-gadget-url
$
=
"gadget_vcs_status.html"
]
button
{
color
:
#212529
;
padding
:
3pt
;
border
:
1px
solid
rgba
(
0
,
0
,
0
,
0.14
);
border-radius
:
0.325em
;
display
:
inline-block
;
margin-right
:
6pt
;
}
div
[
data-gadget-url
$
=
"gadget_vcs_status.html"
]
button
:disabled
,
div
[
data-gadget-url
$
=
"gadget_vcs_status.html"
]
button
[
disabled
]
{
color
:
#999999
;
}
div
[
data-gadget-url
$
=
"gadget_vcs_status.html"
]
button
:before
{
padding-right
:
0.2em
;
}
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/gadget_vcs_status.css.xml
0 → 100644
View file @
f6115654
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"File"
module=
"OFS.Image"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
_Cacheable__manager_id
</string>
</key>
<value>
<string>
must_revalidate_http_cache
</string>
</value>
</item>
<item>
<key>
<string>
__name__
</string>
</key>
<value>
<string>
gadget_vcs_status.css
</string>
</value>
</item>
<item>
<key>
<string>
content_type
</string>
</key>
<value>
<string>
text/css
</string>
</value>
</item>
<item>
<key>
<string>
precondition
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
title
</string>
</key>
<value>
<string></string>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/gadget_vcs_status.html.html
0 → 100644
View file @
f6115654
<!DOCTYPE html>
<html>
<head>
<meta
http-equiv=
"Content-type"
content=
"text/html; charset=utf-8"
/>
<meta
name=
"viewport"
content=
"width=device-width,height=device-height,initial-scale=1"
/>
<title>
VCS status gadget
</title>
<link
rel=
stylesheet
href=
"gadget_vcs_status.css"
>
<script
src=
"rsvp.js"
type=
"text/javascript"
></script>
<script
src=
"renderjs.js"
type=
"text/javascript"
></script>
<script
src=
"jio.js"
type=
"text/javascript"
></script>
<script
src=
"domsugar.js"
type=
"text/javascript"
></script>
<script
src=
"gadget_vcs_status.js"
type=
"text/javascript"
></script>
</head>
<body>
<div
class=
"vcsheader"
></div>
<div
class=
"vcsbody"
></div>
</body>
</html>
\ No newline at end of file
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/gadget_vcs_status.html.xml
0 → 100644
View file @
f6115654
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"File"
module=
"OFS.Image"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
_Cacheable__manager_id
</string>
</key>
<value>
<string>
must_revalidate_http_cache
</string>
</value>
</item>
<item>
<key>
<string>
__name__
</string>
</key>
<value>
<string>
gadget_vcs_status.html
</string>
</value>
</item>
<item>
<key>
<string>
content_type
</string>
</key>
<value>
<string>
text/html
</string>
</value>
</item>
<item>
<key>
<string>
precondition
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
title
</string>
</key>
<value>
<string></string>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/gadget_vcs_status.js.js
0 → 100644
View file @
f6115654
/*global window, rJS, RSVP, domsugar, jIO, console, document, NodeFilter,
FormData */
/*jslint nomen: true, maxlen:80, indent:2*/
(
function
(
window
,
rJS
,
RSVP
,
domsugar
,
jIO
,
console
,
document
,
NodeFilter
)
{
"
use strict
"
;
var
whitelist
=
{
node_list
:
{
P
:
true
,
UL
:
true
,
LI
:
true
,
INPUT
:
true
,
LABEL
:
true
},
attribute_list
:
{
type
:
true
,
class
:
true
,
id
:
true
,
for
:
true
,
name
:
true
,
value
:
true
}
},
DISPLAY_TREE
=
'
display_tree
'
,
DISPLAY_DIFF
=
'
display_diff
'
,
DISPLAY_CHANGELOG
=
'
display_changelog
'
;
function
keepOnlyChildren
(
current_node
)
{
var
fragment
=
document
.
createDocumentFragment
();
while
(
current_node
.
firstChild
)
{
fragment
.
appendChild
(
current_node
.
firstChild
);
}
current_node
.
parentNode
.
replaceChild
(
fragment
,
current_node
);
}
function
renderTreeXml
(
gadget
,
tree_xml_element
)
{
var
iterator
,
current_node
,
next_node
,
parent_node
,
value
,
ul_node
,
attribute
,
attribute_list
,
child_list
,
len
,
finished
=
false
,
id
=
-
1
,
name
,
state_value
=
JSON
.
parse
(
gadget
.
state
.
value
);
// Replace the tree element by a fragment
next_node
=
domsugar
(
'
ul
'
);
while
(
tree_xml_element
.
firstChild
)
{
next_node
.
appendChild
(
tree_xml_element
.
firstChild
);
}
tree_xml_element
=
next_node
;
iterator
=
document
.
createNodeIterator
(
tree_xml_element
,
NodeFilter
.
SHOW_ELEMENT
,
function
()
{
return
NodeFilter
.
FILTER_ACCEPT
;
}
);
while
(
!
finished
)
{
current_node
=
iterator
.
nextNode
();
finished
=
(
current_node
===
null
);
if
(
!
finished
)
{
if
(
current_node
.
nodeName
===
'
item
'
)
{
child_list
=
[];
// Open/hide element
if
(
current_node
.
firstChild
)
{
id
+=
1
;
child_list
.
push
(
domsugar
(
'
input
'
,
{
type
:
'
checkbox
'
,
id
:
'
showhide
'
+
id
,
class
:
'
showhide
'
}),
domsugar
(
'
label
'
,
{
for
:
'
showhide
'
+
id
,
class
:
'
showhide show
'
,
text
:
'
-
'
}),
domsugar
(
'
label
'
,
{
for
:
'
showhide
'
+
id
,
class
:
'
showhide hide
'
,
text
:
'
+
'
})
);
}
else
{
child_list
.
push
(
domsugar
(
'
label
'
,
{
class
:
'
showhide
'
,
text
:
'
'
})
);
}
// Select element
parent_node
=
current_node
.
closest
(
'
ul
'
);
if
(
parent_node
!==
null
)
{
parent_node
=
parent_node
.
parentNode
;
}
if
(
parent_node
!==
null
)
{
parent_node
=
parent_node
.
querySelector
(
'
input.vcs_to_commit
'
);
}
value
=
current_node
.
getAttribute
(
'
text
'
);
if
((
parent_node
!==
null
)
&&
(
parent_node
!==
current_node
))
{
if
(
parent_node
.
value
)
{
value
=
parent_node
.
value
+
'
/
'
+
value
;
}
}
else
{
value
=
''
;
}
name
=
{
'
green
'
:
'
added
'
,
'
orange
'
:
'
modified
'
,
'
red
'
:
'
deleted
'
}[
current_node
.
getAttribute
(
'
aCol
'
)];
child_list
.
push
(
domsugar
(
'
label
'
,
[
domsugar
(
'
input
'
,
{
type
:
'
checkbox
'
,
class
:
'
vcs_to_commit
'
,
value
:
value
,
name
:
name
,
checked
:
((
state_value
[
name
]
===
undefined
)
||
(
state_value
[
name
].
indexOf
(
value
)
===
-
1
))
?
''
:
'
checked
'
}),
current_node
.
getAttribute
(
'
text
'
)
]));
// Child items
if
(
current_node
.
firstChild
)
{
ul_node
=
domsugar
(
'
ul
'
);
while
(
current_node
.
firstChild
)
{
ul_node
.
appendChild
(
current_node
.
firstChild
);
}
child_list
.
push
(
ul_node
);
}
current_node
.
parentNode
.
replaceChild
(
domsugar
(
'
li
'
,
child_list
),
current_node
);
}
else
if
(
!
whitelist
.
node_list
[
current_node
.
nodeName
])
{
keepOnlyChildren
(
current_node
);
}
else
{
// Cleanup attributes
attribute_list
=
current_node
.
attributes
;
len
=
attribute_list
.
length
;
while
(
len
!==
0
)
{
len
=
len
-
1
;
attribute
=
attribute_list
[
len
].
name
;
if
(
!
whitelist
.
attribute_list
[
attribute
])
{
current_node
.
removeAttribute
(
attribute
);
}
}
}
}
}
return
tree_xml_element
;
}
function
renderGadgetHeader
(
gadget
,
loading
)
{
var
element_list
=
[
domsugar
(
'
p
'
,
[
'
Repository:
'
,
domsugar
(
'
a
'
,
{
text
:
gadget
.
state
.
remote_url
,
href
:
gadget
.
state
.
remote_url
}),
'
(
'
+
gadget
.
state
.
remote_comment
+
'
)
'
])
],
tree_icon
=
'
ui-icon-check-square
'
,
diff_icon
=
'
ui-icon-search-plus
'
,
changelog_icon
=
'
ui-icon-git
'
;
if
(
loading
)
{
if
(
gadget
.
state
.
display_step
===
DISPLAY_TREE
)
{
tree_icon
=
'
ui-icon-spinner
'
;
}
else
if
(
gadget
.
state
.
display_step
===
DISPLAY_DIFF
)
{
diff_icon
=
'
ui-icon-spinner
'
;
}
else
if
(
gadget
.
state
.
display_step
===
DISPLAY_CHANGELOG
)
{
changelog_icon
=
'
ui-icon-spinner
'
;
}
else
{
throw
new
Error
(
"
Can't render header state
"
+
gadget
.
state
.
display_step
);
}
}
element_list
.
push
(
domsugar
(
'
button
'
,
{
type
:
'
button
'
,
text
:
'
Tree
'
,
disabled
:
(
gadget
.
state
.
display_step
===
DISPLAY_TREE
),
class
:
'
display-tree-btn ui-btn-icon-left
'
+
tree_icon
}),
domsugar
(
'
button
'
,
{
type
:
'
button
'
,
text
:
'
Diff
'
,
disabled
:
(
gadget
.
state
.
display_step
===
DISPLAY_DIFF
),
class
:
'
diff-tree-btn ui-btn-icon-left
'
+
diff_icon
}),
domsugar
(
'
button
'
,
{
type
:
'
button
'
,
text
:
'
Changelog
'
,
disabled
:
(
gadget
.
state
.
display_step
===
DISPLAY_CHANGELOG
),
class
:
'
changelog-btn ui-btn-icon-left
'
+
changelog_icon
})
);
if
((
!
loading
)
&&
(
gadget
.
state
.
display_step
===
DISPLAY_TREE
))
{
element_list
.
push
(
domsugar
(
'
button
'
,
{
type
:
'
button
'
,
text
:
'
Expand
'
,
class
:
'
expand-tree-btn ui-btn-icon-left ui-icon-arrows-v
'
})
);
}
domsugar
(
gadget
.
element
.
querySelector
(
'
div.vcsheader
'
),
element_list
);
}
function
updateFullTreeCheckbox
(
checkbox
)
{
var
i
,
element_list
,
parent_checkbox
,
is_checked
,
is_indeterminate
;
// https://css-tricks.com/indeterminate-checkboxes/
// Check/uncheck all children checkboxes
element_list
=
checkbox
.
parentElement
.
parentElement
.
querySelectorAll
(
'
input.vcs_to_commit
'
);
for
(
i
=
0
;
i
<
element_list
.
length
;
i
+=
1
)
{
element_list
[
i
].
checked
=
checkbox
.
checked
;
element_list
[
i
].
indeterminate
=
false
;
}
// Check/uncheck/undefine all parent checkboxes
while
(
checkbox
!==
null
)
{
parent_checkbox
=
checkbox
.
closest
(
'
ul
'
)
.
parentNode
.
querySelector
(
'
input.vcs_to_commit
'
);
if
(
parent_checkbox
===
checkbox
)
{
// Top checkbox
checkbox
=
null
;
}
else
{
// check the state of all child chexbox
element_list
=
parent_checkbox
.
closest
(
'
li
'
)
.
querySelector
(
'
ul
'
)
.
children
;
is_checked
=
true
;
is_indeterminate
=
false
;
for
(
i
=
0
;
i
<
element_list
.
length
;
i
+=
1
)
{
is_checked
=
is_checked
&&
element_list
[
i
].
querySelector
(
'
input.vcs_to_commit
'
)
.
checked
;
is_indeterminate
=
is_indeterminate
||
element_list
[
i
].
querySelector
(
'
input.vcs_to_commit
'
)
.
checked
||
element_list
[
i
].
querySelector
(
'
input.vcs_to_commit
'
)
.
indeterminate
;
}
parent_checkbox
.
checked
=
is_checked
;
parent_checkbox
.
indeterminate
=
(
!
is_checked
)
&&
is_indeterminate
;
checkbox
=
parent_checkbox
;
}
}
}
function
renderTreeView
(
gadget
,
extract
)
{
return
new
RSVP
.
Queue
()
.
push
(
function
()
{
renderGadgetHeader
(
gadget
,
true
);
var
form_data
=
new
FormData
();
form_data
.
append
(
'
show_unmodified:int
'
,
0
);
// form_data.append('bt_id', 'erp5');
form_data
.
append
(
'
do_extract:int
'
,
extract
?
1
:
0
);
return
jIO
.
util
.
ajax
({
"
type
"
:
"
POST
"
,
"
url
"
:
gadget
.
state
.
get_tree_url
,
"
xhrFields
"
:
{
withCredentials
:
true
},
"
dataType
"
:
"
document
"
,
"
data
"
:
form_data
});
})
.
push
(
function
(
evt
)
{
renderGadgetHeader
(
gadget
,
false
);
domsugar
(
gadget
.
element
.
querySelector
(
'
div.vcsbody
'
),
[
renderTreeXml
(
gadget
,
evt
.
target
.
response
.
querySelector
(
'
tree
'
))
]);
// Update the tree parent
var
element_list
=
gadget
.
element
.
querySelectorAll
(
'
input.vcs_to_commit
'
),
i
;
for
(
i
=
0
;
i
<
element_list
.
length
;
i
+=
1
)
{
if
(
element_list
[
i
].
checked
)
{
updateFullTreeCheckbox
(
element_list
[
i
]);
}
}
});
}
function
getContentFromTreeView
(
gadget
)
{
var
result
=
JSON
.
parse
(
gadget
.
state
.
value
),
checkbox_list
=
gadget
.
element
.
querySelectorAll
(
'
input.vcs_to_commit
'
),
i
,
name
;
result
.
added
=
[];
result
.
modified
=
[];
result
.
deleted
=
[];
for
(
i
=
0
;
i
<
checkbox_list
.
length
;
i
+=
1
)
{
name
=
checkbox_list
[
i
].
name
;
if
(
name
&&
checkbox_list
[
i
].
checked
)
{
result
[
name
].
push
(
checkbox_list
[
i
].
value
);
}
}
gadget
.
state
.
value
=
JSON
.
stringify
(
result
);
}
function
expandTreeView
(
gadget
)
{
var
element_list
=
gadget
.
element
.
querySelectorAll
(
'
input.showhide
'
),
// Do not crash if no checkbox is displayed
is_checked
=
(
element_list
.
length
!==
0
)
&&
(
!
element_list
[
0
].
checked
),
i
;
for
(
i
=
0
;
i
<
element_list
.
length
;
i
+=
1
)
{
element_list
[
0
].
checked
=
is_checked
;
}
}
function
declareAndRenderDiff
(
gadget
,
path
,
diff
)
{
return
gadget
.
declareGadget
(
'
gadget_erp5_side_by_side_diff.html
'
)
.
push
(
function
(
diff_gadget
)
{
return
RSVP
.
all
([
diff_gadget
.
element
,
path
,
diff_gadget
.
render
({
value
:
diff
})
]);
});
}
function
renderDiffView
(
gadget
)
{
var
result
=
JSON
.
parse
(
gadget
.
state
.
value
),
ajax_result
,
diff_count
=
result
.
modified
.
length
;
return
new
RSVP
.
Queue
()
.
push
(
function
()
{
renderGadgetHeader
(
gadget
,
true
);
var
form_data
=
new
FormData
(),
key_list
=
[
'
modified
'
,
'
added
'
,
'
deleted
'
],
key
,
i
,
j
;
for
(
i
=
0
;
i
<
key_list
.
length
;
i
+=
1
)
{
key
=
key_list
[
i
];
for
(
j
=
0
;
j
<
result
[
key
].
length
;
j
+=
1
)
{
form_data
.
append
(
key
+
'
:list
'
,
result
[
key
][
j
]);
}
}
return
jIO
.
util
.
ajax
({
"
type
"
:
"
POST
"
,
"
url
"
:
gadget
.
state
.
diff_url
,
"
xhrFields
"
:
{
withCredentials
:
true
},
"
dataType
"
:
"
json
"
,
"
data
"
:
form_data
});
})
.
push
(
function
(
evt
)
{
ajax_result
=
evt
.
target
.
response
;
var
promise_list
=
[],
i
;
for
(
i
=
0
;
i
<
diff_count
;
i
+=
1
)
{
promise_list
.
push
(
declareAndRenderDiff
(
gadget
,
ajax_result
.
modified_list
[
i
].
path
,
ajax_result
.
modified_list
[
i
].
diff
)
);
}
return
RSVP
.
all
(
promise_list
);
})
.
push
(
function
(
result_list
)
{
var
i
,
element_list
=
[];
for
(
i
=
0
;
i
<
result_list
.
length
;
i
+=
1
)
{
element_list
.
push
(
domsugar
(
'
label
'
,
[
domsugar
(
'
input
'
,
{
type
:
'
checkbox
'
,
class
:
'
vcs_to_commit
'
,
value
:
result_list
[
i
][
1
],
name
:
'
modified
'
,
checked
:
'
checked
'
}),
result_list
[
i
][
1
]
]),
result_list
[
i
][
0
]
);
}
for
(
i
=
0
;
i
<
ajax_result
.
added_list
.
length
;
i
+=
1
)
{
element_list
.
push
(
domsugar
(
'
label
'
,
[
domsugar
(
'
input
'
,
{
type
:
'
checkbox
'
,
class
:
'
vcs_to_commit
'
,
value
:
ajax_result
.
added_list
[
i
].
path
,
name
:
'
added
'
,
checked
:
'
checked
'
}),
ajax_result
.
added_list
[
i
].
path
])
);
}
for
(
i
=
0
;
i
<
ajax_result
.
deleted_list
.
length
;
i
+=
1
)
{
element_list
.
push
(
domsugar
(
'
label
'
,
[
domsugar
(
'
input
'
,
{
type
:
'
checkbox
'
,
class
:
'
vcs_to_commit
'
,
value
:
ajax_result
.
deleted_list
[
i
].
path
,
name
:
'
deleted
'
,
checked
:
'
checked
'
}),
ajax_result
.
deleted_list
[
i
].
path
])
);
}
renderGadgetHeader
(
gadget
,
false
);
domsugar
(
gadget
.
element
.
querySelector
(
'
div.vcsbody
'
),
element_list
);
});
}
function
renderChangelogView
(
gadget
)
{
var
result
=
JSON
.
parse
(
gadget
.
state
.
value
);
renderGadgetHeader
(
gadget
,
false
);
domsugar
(
gadget
.
element
.
querySelector
(
'
div.vcsbody
'
),
[
domsugar
(
'
textarea
'
,
{
value
:
result
.
changelog
}),
domsugar
(
'
h3
'
,
{
text
:
'
Added Files
'
}),
domsugar
(
'
pre
'
,
{
text
:
result
.
added
.
join
(
'
\n
'
)}),
domsugar
(
'
h3
'
,
{
text
:
'
Modified Files
'
}),
domsugar
(
'
pre
'
,
{
text
:
result
.
modified
.
join
(
'
\n
'
)}),
domsugar
(
'
h3
'
,
{
text
:
'
Deleted Files
'
}),
domsugar
(
'
pre
'
,
{
text
:
result
.
deleted
.
join
(
'
\n
'
)})
]);
}
function
getContentFromChangelogView
(
gadget
)
{
var
result
=
JSON
.
parse
(
gadget
.
state
.
value
);
result
.
changelog
=
gadget
.
element
.
querySelector
(
'
textarea
'
).
value
;
gadget
.
state
.
value
=
JSON
.
stringify
(
result
);
}
rJS
(
window
)
.
declareMethod
(
'
render
'
,
function
(
options
)
{
return
this
.
changeState
({
display_step
:
DISPLAY_TREE
,
// Only build the bt5 during the first query
extract
:
1
,
diff_url
:
options
.
diff_url
,
get_tree_url
:
options
.
get_tree_url
,
remote_comment
:
options
.
remote_comment
,
remote_url
:
options
.
remote_url
,
// key: options.key,
// value: options.value || "",
value
:
JSON
.
stringify
({
added
:
[],
modified
:
[],
deleted
:
[],
changelog
:
''
}),
editable
:
(
options
.
editable
===
undefined
)
?
true
:
options
.
editable
});
})
.
onStateChange
(
function
(
modification_dict
)
{
var
gadget
=
this
;
if
(
gadget
.
state
.
display_step
===
DISPLAY_TREE
)
{
console
.
log
(
modification_dict
);
if
(
modification_dict
.
hasOwnProperty
(
'
display_step
'
))
{
return
renderTreeView
(
gadget
,
modification_dict
.
hasOwnProperty
(
'
extract
'
));
}
if
(
modification_dict
.
hasOwnProperty
(
'
expand_tree
'
))
{
return
expandTreeView
(
gadget
);
}
}
if
(
modification_dict
.
display_step
===
DISPLAY_DIFF
)
{
return
renderDiffView
(
gadget
);
}
if
(
modification_dict
.
display_step
===
DISPLAY_CHANGELOG
)
{
return
renderChangelogView
(
gadget
);
}
throw
new
Error
(
'
Unhandled display step:
'
+
gadget
.
state
.
display_step
);
})
.
onEvent
(
"
change
"
,
function
(
evt
)
{
var
gadget
=
this
,
tag_name
=
evt
.
target
.
tagName
;
// Only handle vcs_to_commit checkbox
if
((
tag_name
!==
'
INPUT
'
)
||
(
evt
.
target
.
className
!==
'
vcs_to_commit
'
))
{
return
;
}
if
(
gadget
.
state
.
display_step
!==
DISPLAY_TREE
)
{
return
;
}
updateFullTreeCheckbox
(
evt
.
target
);
},
false
,
false
)
.
onEvent
(
"
click
"
,
function
(
evt
)
{
// Only handle click on BUTTON and IMG element
var
gadget
=
this
,
tag_name
=
evt
.
target
.
tagName
,
queue
;
if
(
tag_name
!==
'
BUTTON
'
)
{
return
;
}
// Disable any button. It must be managed by this gadget
evt
.
preventDefault
();
// Always get content to ensure the possible displayed form
// is checked and content propagated to the gadget state value
queue
=
gadget
.
getContent
();
if
(
evt
.
target
.
className
.
indexOf
(
"
expand-tree-btn
"
)
!==
-
1
)
{
return
queue
.
push
(
function
()
{
return
gadget
.
changeState
({
display_step
:
DISPLAY_TREE
,
expand_tree
:
new
Date
()
});
});
}
if
(
evt
.
target
.
className
.
indexOf
(
"
display-tree-btn
"
)
!==
-
1
)
{
return
queue
.
push
(
function
()
{
return
gadget
.
changeState
({
display_step
:
DISPLAY_TREE
});
});
}
if
(
evt
.
target
.
className
.
indexOf
(
"
diff-tree-btn
"
)
!==
-
1
)
{
return
queue
.
push
(
function
()
{
return
gadget
.
changeState
({
display_step
:
DISPLAY_DIFF
});
});
}
if
(
evt
.
target
.
className
.
indexOf
(
"
changelog-btn
"
)
!==
-
1
)
{
return
queue
.
push
(
function
()
{
return
gadget
.
changeState
({
display_step
:
DISPLAY_CHANGELOG
});
});
}
throw
new
Error
(
'
Unhandled button:
'
+
evt
.
target
.
textContent
);
},
false
,
false
)
//////////////////////////////////////////////////
// Used when submitting the form
//////////////////////////////////////////////////
.
declareMethod
(
'
getContent
'
,
function
()
{
var
gadget
=
this
,
display_step
=
gadget
.
state
.
display_step
,
queue
;
if
(
gadget
.
state
.
display_step
===
DISPLAY_TREE
)
{
queue
=
new
RSVP
.
Queue
(
getContentFromTreeView
(
gadget
));
}
else
if
(
gadget
.
state
.
display_step
===
DISPLAY_DIFF
)
{
queue
=
new
RSVP
.
Queue
(
getContentFromTreeView
(
gadget
));
}
else
if
(
gadget
.
state
.
display_step
===
DISPLAY_CHANGELOG
)
{
queue
=
new
RSVP
.
Queue
(
getContentFromChangelogView
(
gadget
));
}
else
{
throw
new
Error
(
'
getContent form not handled:
'
+
display_step
);
}
return
queue
.
push
(
function
()
{
var
result
=
{};
if
(
gadget
.
state
.
editable
)
{
result
[
gadget
.
state
.
key
]
=
gadget
.
state
.
value
;
}
return
result
;
});
},
{
mutex
:
'
changestate
'
})
.
declareMethod
(
'
checkValidity
'
,
function
()
{
throw
new
Error
(
'
checkValidity not implemented
'
);
},
{
mutex
:
'
changestate
'
});
}(
window
,
rJS
,
RSVP
,
domsugar
,
jIO
,
console
,
document
,
NodeFilter
));
\ No newline at end of file
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/gadget_vcs_status.js.xml
0 → 100644
View file @
f6115654
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"File"
module=
"OFS.Image"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
_Cacheable__manager_id
</string>
</key>
<value>
<string>
must_revalidate_http_cache
</string>
</value>
</item>
<item>
<key>
<string>
__name__
</string>
</key>
<value>
<string>
gadget_vcs_status.js
</string>
</value>
</item>
<item>
<key>
<string>
content_type
</string>
</key>
<value>
<string>
application/javascript
</string>
</value>
</item>
<item>
<key>
<string>
precondition
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
title
</string>
</key>
<value>
<string></string>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/gadget_vcs_status.less.bin
0 → 100644
View file @
f6115654
div[data-gadget-url$="gadget_vcs_status.html"] {
li {
li {
padding-left: 1em;
}
input.showhide {
display: none;
&:checked ~ label.show {
display: none;
}
&:checked ~ ul {
display: none;
}
&:not(:checked) ~ label.hide {
display: none;
}
}
label {
&.showhide {
width: 1em;
}
display: inline-block;
input {
margin: 0 3pt;
}
}
}
button {
color: #212529;
padding: 3pt;
border: 1px solid rgba(0, 0, 0, 0.14);
border-radius: 0.325em;
display: inline-block;
margin-right: 6pt;
&:disabled, &[disabled] {
color: #999999;
}
&:before {
padding-right: 0.2em;
}
}
}
bt5/erp5_forge/SkinTemplateItem/portal_skins/erp5_vcs/gadget_vcs_status.less.xml
0 → 100644
View file @
f6115654
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"File"
module=
"OFS.Image"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
__name__
</string>
</key>
<value>
<string>
gadget_vcs_status.less
</string>
</value>
</item>
<item>
<key>
<string>
content_type
</string>
</key>
<value>
<string>
text/less
</string>
</value>
</item>
<item>
<key>
<string>
precondition
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
title
</string>
</key>
<value>
<string></string>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
bt5/erp5_forge/bt/template_action_path_list
View file @
f6115654
...
@@ -15,6 +15,7 @@ Business Template | create_report
...
@@ -15,6 +15,7 @@ Business Template | create_report
Business Template | create_skin_folder
Business Template | create_skin_folder
Business Template | create_working_copy
Business Template | create_working_copy
Business Template | git_commit
Business Template | git_commit
Business Template | git_commit_action
Business Template | manage_field_library
Business Template | manage_field_library
Business Template | rename_proxy_field
Business Template | rename_proxy_field
Business Template | svn_cleanup_locks
Business Template | svn_cleanup_locks
...
...
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