mirror of
https://github.com/holos-run/holos.git
synced 2026-03-20 09:15:02 +00:00
This patch refactors the API following the [API Best Practices][api] documentation. The UpdatePlatform method is modeled after a mutating operation described [by Netflix][nflx] instead of using a REST resource representation. This makes it much easier to iterate over the fields that need to be updated as the PlatformUpdateOperation is a flat data structure while a Platform resource may have nested fields. Nested fields are more complicated and less clear to handle with a FieldMask. This patch also adds a snapckbar message on save. Previously, the save button didn't give any indication of success or failure. This patch fixes the problem by adding a snackbar message that pop up at the bottom of the screen nicely. When the snackbar message is dismissed or times out the save button is re-enabled. [api]: https://protobuf.dev/programming-guides/api/ [nflx]: https://netflixtechblog.com/practical-api-design-at-netflix-part-2-protobuf-fieldmask-for-mutation-operations-2e75e1d230e4 Examples: FieldMask for ListPlatforms ``` grpcurl -H "x-oidc-id-token: $(holos token)" -d @ ${HOLOS_SERVER##*/} holos.platform.v1alpha1.PlatformService.ListPlatforms <<EOF { "org_id": "018f36fb-e3f7-7f7f-a1c5-c85fb735d215", "field_mask": { "paths": ["id","name"] } } EOF ``` ```json { "platforms": [ { "id": "018f36fb-e3ff-7f7f-a5d1-7ca2bf499e94", "name": "bare" }, { "id": "018f6b06-9e57-7223-91a9-784e145d998c", "name": "gary" }, { "id": "018f6b06-9e53-7223-8ae1-1ad53d46b158", "name": "jeff" }, { "id": "018f6b06-9e5b-7223-8b8b-ea62618e8200", "name": "nate" } ] } ``` Closes: #171
74 lines
2.7 KiB
Go
74 lines
2.7 KiB
Go
// Copyright 2010 The Go Authors. All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// - Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
//
|
|
// - Redistributions in binary form must reproduce the above
|
|
// copyright notice, this list of conditions and the following disclaimer
|
|
// in the documentation and/or other materials provided with the
|
|
// distribution.
|
|
//
|
|
// - Neither the name of Google Inc. nor the names of its
|
|
// contributors may be used to endorse or promote products derived from
|
|
// this software without specific prior written permission.
|
|
//
|
|
// Original license: https://github.com/golang/protobuf/blob/master/LICENSE
|
|
// Original CamelCase func: https://github.com/golang/protobuf/blob/master/protoc-gen-go/generator/generator.go#L2648
|
|
|
|
package strings
|
|
|
|
// PascalCase returns the PascalCased name.
|
|
// If there is an interior underscore followed by a lower case letter,
|
|
// drop the underscore and convert the letter to upper case.
|
|
// There is a remote possibility of this rewrite causing a name collision,
|
|
// but it's so remote we're prepared to pretend it's nonexistent - since the
|
|
// C++ generator lowercases names, it's extremely unlikely to have two fields
|
|
// with different capitalizations.
|
|
// In short, _my_field_name_2 becomes XMyFieldName_2.
|
|
func PascalCase(s string) string {
|
|
if s == "" {
|
|
return ""
|
|
}
|
|
t := make([]byte, 0, 32)
|
|
i := 0
|
|
if s[0] == '_' {
|
|
// Need a capital letter; drop the '_'.
|
|
t = append(t, 'X')
|
|
i++
|
|
}
|
|
return string(append(t, lookupAndReplacePascalCaseWords(s, i)...))
|
|
}
|
|
|
|
// lookupAndReplacePascalCaseWords lookups for words in the string starting in position i
|
|
// and replaces the snake case format to PascalCase.
|
|
// Invariant: if the next letter is lower case, it must be converted
|
|
// to upper case.
|
|
// That is, we process a word at a time, where words are marked by _ or
|
|
// upper case letter. Digits are treated as words.
|
|
func lookupAndReplacePascalCaseWords(s string, i int) []byte {
|
|
t := make([]byte, 0, 32)
|
|
for ; i < len(s); i++ {
|
|
c := s[i]
|
|
if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) {
|
|
continue // Skip the underscore in s.
|
|
}
|
|
if isASCIIDigit(c) {
|
|
t = append(t, c)
|
|
continue
|
|
}
|
|
// Assume we have a letter now - if not, it's a bogus identifier.
|
|
// The next word is a sequence of characters that must start upper case.
|
|
if isASCIILower(c) {
|
|
c ^= ' ' // Make it a capital letter.
|
|
}
|
|
t = append(t, c) // Guaranteed not lower case.
|
|
// Accept lower case sequence that follows.
|
|
t, i = appendLowercaseSequence(s, i, t)
|
|
}
|
|
return t
|
|
}
|