7 Commits
0.7.2 ... 0.7.3

Author SHA1 Message Date
Roman Vynar
7a3bc551b3 Show the root namespace "library" in the dropdown even when there are no repos in it 2018-08-14 15:39:21 +03:00
Roman Vynar
7a752d3f8d Add version to UI 2018-08-14 15:37:21 +03:00
Roman Vynar
80bdad8c91 Switch to alpine:3.8 2018-08-14 15:36:54 +03:00
Roman Vynar
734afe56b5 Improve no data UI messages on empty tables. 2018-08-14 15:16:21 +03:00
Roman Vynar
0f6bf65015 Trim \n from password file. 2018-08-14 14:40:32 +03:00
Roman Vynar
7525e87c1a Merge pull request #13 from Area128/master
Allow reading password from file so that docker secrets can be used
2018-08-14 14:29:02 +03:00
Antonios Vamporakis
1b8c502a60 Allow reading password from file so that docker secrets can be used 2018-07-07 11:05:14 +02:00
13 changed files with 68 additions and 9 deletions

View File

@@ -1,5 +1,12 @@
## Changelog
### 0.7.3 (2018-08-14)
* Add `registry_password_file` option to the config file.
* Improve no data message on empty tables on UI.
* Show the root namespace "library" in the dropdown even when there are no repos in it.
* Switch alpine Docker image to 3.8.
### 0.7.2 (2018-07-30)
* Make web root accessible w/o trailing slash when base_path is configured.

View File

@@ -18,7 +18,7 @@ RUN cd /opt/src/github.com/quiq/docker-registry-ui && \
go build -o /opt/docker-registry-ui github.com/quiq/docker-registry-ui
FROM alpine:3.7
FROM alpine:3.8
WORKDIR /opt
RUN apk add --no-cache ca-certificates && \

View File

@@ -12,8 +12,11 @@ verify_tls: true
# They need to have a full access to the registry.
# If token authentication service is enabled, it will be auto-discovered and those credentials
# will be used to obtain access tokens.
# When the registry_password_file entry is used, the password can be passed as a docker secret
# and read from file. This overides the registry_password entry.
registry_username: user
registry_password: pass
# registry_password_file: /run/secrets/registry_password_file
# Event listener token.
# The same one should be configured on Docker registry as Authorization Bearer token.

12
main.go
View File

@@ -26,6 +26,7 @@ type configData struct {
VerifyTLS bool `yaml:"verify_tls"`
Username string `yaml:"registry_username"`
Password string `yaml:"registry_password"`
PasswordFile string `yaml:"registry_password_file"`
EventListenerToken string `yaml:"event_listener_token"`
EventRetentionDays int `yaml:"event_retention_days"`
EventDatabaseDriver string `yaml:"event_database_driver"`
@@ -86,6 +87,17 @@ func main() {
a.config.BasePath = a.config.BasePath[0 : len(a.config.BasePath)-1]
}
}
// Read password from file.
if a.config.PasswordFile != "" {
if _, err := os.Stat(a.config.PasswordFile); os.IsNotExist(err) {
panic(err)
}
passwordBytes, err := ioutil.ReadFile(a.config.PasswordFile)
if err != nil {
panic(err)
}
a.config.Password = strings.TrimSuffix(string(passwordBytes[:]), "\n")
}
// Init registry API client.
a.client = registry.NewClient(a.config.RegistryURL, a.config.VerifyTLS, a.config.Username, a.config.Password)

View File

@@ -148,6 +148,9 @@ func (c *Client) Namespaces() []string {
for k := range c.repos {
namespaces = append(namespaces, k)
}
if !ItemInSlice("library", namespaces) {
namespaces = append(namespaces, "library")
}
sort.Strings(namespaces)
return namespaces
}

View File

@@ -42,3 +42,13 @@ func PrettySize(size float64) string {
}
return fmt.Sprintf("%.*f %s", 0, size, units[i])
}
// ItemInSlice check if item is an element of slice
func ItemInSlice(item string, slice []string) bool {
for _, i := range slice {
if i == item {
return true
}
}
return false
}

View File

@@ -45,3 +45,13 @@ func TestPrettySize(t *testing.T) {
}
})
}
func TestItemInSlice(t *testing.T) {
a := []string{"abc", "def", "ghi"}
convey.Convey("Check whether element is in slice", t, func() {
convey.So(ItemInSlice("abc", a), convey.ShouldBeTrue)
convey.So(ItemInSlice("ghi", a), convey.ShouldBeTrue)
convey.So(ItemInSlice("abc1", a), convey.ShouldBeFalse)
convey.So(ItemInSlice("gh", a), convey.ShouldBeFalse)
})
}

View File

@@ -39,6 +39,7 @@ func setupRenderer(debug bool, registryHost, basePath string) *Template {
view := jet.NewHTMLSet("templates")
view.SetDevelopmentMode(debug)
view.AddGlobal("version", version)
view.AddGlobal("basePath", basePath)
view.AddGlobal("registryHost", registryHost)
view.AddGlobal("pretty_size", func(size interface{}) string {

View File

@@ -22,8 +22,8 @@
{{yield body()}}
<div style="padding: 10px 0; margin-bottom: 20px">
<div style="float: left">
&copy; 2017-2018 <a href="https://goquiq.com">Quiq Inc.</a>
<div style="text-align: center; color:darkgrey">
Docker Registry UI v{{version}} &copy; 2017-2018 <a href="https://goquiq.com">Quiq Inc.</a>
</div>
</div>
</div>

View File

@@ -6,7 +6,10 @@
$('#datatable').DataTable({
"pageLength": 10,
"order": [[ 4, 'desc' ]],
"stateSave": true
"stateSave": true,
"language": {
"emptyTable": "No events."
}
});
});
</script>

View File

@@ -3,10 +3,6 @@
{{block head()}}
<script type="text/javascript">
$(document).ready(function() {
$('#datatable').DataTable({
"pageLength": 25,
"stateSave": true
});
$('#namespace').on('change', function (e) {
window.location = '{{ basePath }}/' + this.value;
});
@@ -18,6 +14,14 @@
namespace = namespace.split('/')[1]
}
$('#namespace').val(namespace);
$('#datatable').DataTable({
"pageLength": 25,
"stateSave": true,
"language": {
"emptyTable": "No repositories in \"" + namespace + "\" namespace."
}
});
});
</script>
{{end}}

View File

@@ -11,7 +11,10 @@
"stateSave": true,
columnDefs: [
{ type: 'natural', targets: 0 }
]
],
"language": {
"emptyTable": "No tags in this repository."
}
})
function populateConfirmation() {
$('[data-toggle=confirmation]').confirmation({

3
version.go Normal file
View File

@@ -0,0 +1,3 @@
package main
const version = "0.7.3"