zupit / beagle Goto Github PK
View Code? Open in Web Editor NEWA framework to help implement Server-Driven UI in your apps natively.
Home Page: https://docs.usebeagle.io
License: Apache License 2.0
A framework to help implement Server-Driven UI in your apps natively.
Home Page: https://docs.usebeagle.io
License: Apache License 2.0
Currently, Beagle's declarative module is composed of the models and contracts that the server-driven elements and actions must abide by.
This is the "common
" module and is only directly importable by the backend and Android modules since it is Kotlin code. Other languages need to manually translate these contracts, which can result in discrepancies.
Synchronize the contracts among all our platforms, using code generation. Provide a toolkit for Beagle to use internally and that projects using Beagle may use.
NavigateAction
structure and maybe others that will come.When the activity rotates, it buggy the current fragment and toolbar.
Describe the problem
Actual the class Image
has a field called name
, but is difficult to know what this variable do without open the documentation
Expected behavior
Change this field to localPath
it is more suggestive to understand what the field do.
Currently all types that extends from Widget have to define all variables that a Widget
expects, and if one day we would add some new property to Widget
, they would all need to change. Take Text
as an example:
public struct Text: Widget {
public let text: String
public let alignment: Alignment?
public let textColor: String?
/// All these properties are from Widget
public let style: String?
public var id: String?
public let appearance: Appearance?
public let flex: Flex?
public let accessibility: Accessibility?
And when that type needs to implement its own decoding function, you will need to initialise all of those variables. E.g:
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
...
self.style = try container.decodeIfPresent(String.self, forKey: .style)
self.id = try container.decodeIfPresent(String.self, forKey: .id)
self.appearance = try container.decodeIfPresent(Appearance.self, forKey: .appearance)
self.accessibility = try container.decodeIfPresent(Accessibility.self, forKey: .accessibility)
self.flex = try container.decodeIfPresent(Flex.self, forKey: .flex)
}
One possible solution could be to use Classes and Inheritance everywhere.
Problem description
Beagle does not support the user to pass the height and width of the Button
through its style
attribute.
Expected behavior
When the height and width of the Button
are defined by the application's design system, it is necessary to assign these attributes through the component's style.
Android checklist
iOS checklist
Backend checklist
Beagle currently supports no direct means of expressing an operation that needs to be done by the BFF which will result in a change, commonly small, in the current view. Using the current actions, this would need to be expressed as a navigation to the operation's endpoint which will return the entire modified view.
Suppose a list view whose elements need to be removed when its trash button is clicked on.
Currently, the trash button will have a navigation action to the endpoint of the removal operation and this operation will remove it and return basically the same screen, except without the element.
The desired change would be an Action that allows the server to send the operation's endpoint and this endpoint will respond with another element, likely an Action, that causes the list view to remove said element.
All server driven elements are sent from the server mixing both structure and data. However, the data is often subject to change and specific for each user, while the structure is often static. Furthermore, the data can require the BFF to have to perform integrations with micro services, meaning the data often takes longer to be available then the structure.
Suppose a user profile screen, which has the user's nickname, their picture, a text containing their description and a follow button. The structure is the same for every user and static, but the data is specific and likely will require a lookup in some user micro service.
Currently, the server only sends the screen after it completes the lookup and it populates the structure with the data.
The change would allow the server to instantly send the structure and then look up and send the data, which the app will populate.
Describe the problem
For the user to integrate the Beagle with his application he needs to create an Activity
that provides the necessary components for the initialization of the framework, and as a consequence this increases the difficulty of its integration.
Expected behavior
In order to simplify the use of Beagle, it would be ideal to have a default BeagleActivity
and only when the user wanted to change any specific component he would need to create his own.
When the user creates a Form
with a Validator
and the InputWidget
responsible for being validated comes with a valid standard, FormSubmit
remains disabled.
Change the form's validation controller to perform the validations with the current state of the FormInput
that has a Validator
at the time of initializing the Form
.
Describe the problem
It is difficult to understand the classes and the fields because they don't have a documentation when click to see detail of the class
Expected behavior
Add documentation to all the classes and fields
Actual | Expected |
---|---|
Recomendation
Use the dokka to generate your documentation.
Android checklist
iOS checklist
Backend checklist
All server driven elements are sent from the server mixing both structure and data. However, the data is often subject to change and specific for each user, while the structure is often static. Furthermore, the data can require the BFF to have to perform integrations with microservices, meaning the data often takes longer to be available then the structure.
Suppose a user profile screen, which has the user's nickname, their picture, a text containing their description and a follow button. The structure is the same for every user and static, but the data is specific and likely will require a lookup in some user microservice.
Currently, the server only sends the screen after it completes the lookup and it populates the structure with the data.
The change would allow the server to instantly send the structure and then look up and send the data, which the app will populate.
Problem description
Some specific attributes of Yoga
are erroneously present in the Beagle's style object.
Expected behavior
Place the Flex
inside the Style
and remove from the Flex
what should be in the Style
(margin, position, padding, size, display, direction)
Android checklist
iOS checklist
Backend checklist
Describe the problem
Today Beagle's navigation is more focused on the mobile context and with that the integration with the web is more complex. And for Android, navigation is controlled by a Navigate
action and the types are represented by a type
field that receives the following enums:
Expected behavior
To unify the platforms, in addition to changing the names of the navigation types, these will be represented by sealed classes with different attributes.
Steps
shouldResetApplication
parameter is enabled, all other screens opened in the application will be removed.When we release a new version on iOS, we need to automatically (via CI) bump CocoaPods version (on .podspec
), so people that have access to our repo can integrate beagle into their project using pods versioning.
Maybe change the method name on ViewConvertable to buildView.
Problem
When we use Button
in the view hierarchy, pre-fetch is not being used.
Solution
Use pre-fetch logic on Button
as well.
Add fastlane to run all workflow in the project.
The goal is remove the bitrise and use fastlane
I can't implement an async custom action handler. The following code won't compile:
let actionHandler = CustomActionHandling()
actionHandler["my-custom-action"] = { context, action, listener in
listener(.start)
handleAsync(data: action.data) { screen in
listener(.success(action: Navigate.addScreen(screen)))
}
}
func handleAsync(data: [String: String], completion: @escaping (Screen) -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
let text = data.map({ "\($0.key): \($0.value)" }).joined(separator: "\n")
completion(Screen(child: Text(text)))
}
}
Currently, the only notification that we receive upon releasing a new version is from GitHub, but since most of ours GitHub accounts are subscribed to a lot of unwanted stuff, we (and others that use beagle) need another way of communicating a release (like Slack, Discord, and stuff like that).
For the user to centralize the title in a NavigationBar
in the Beagle, today it is necessary that he creates a customized Toolbar
, given that the style customization attributes do not have this option.
A solution would be the mapping by the Beagle of a new styling attribute of the Toolbar
,
called the centerTitle
receiving the values of true or false.
According to meeting we had in 04/22/2020. We should implement a new feature to facilitate the development of interactive interfaces with Beagle.
Today it can get very hard very easily when front-end developers try to implement any feature where a Beagle component must interact with another Beagle component. All this logic must be predicted by us and delivered through a base component or be implemented entirely by the end-developer. Generally, our libs get way too dependent in the components we offer and, since we can't predict every use case, the end-developer will have to implement very complex components which will most of the time also be coupled with the Beagle libraries.
To eliminate this problem, in the aforementioned meeting it was proposed a new feature that allows for state sharing between components and its manipulation. Four new concepts were proposed: events, actions, contexts and bindings.
The four new concepts (events, actions, contexts and bindings) must be implemented in all of the Beagle Projects (schema, bff, ios, android and web). To implement these, the specification hosted here must be followed. All of the examples showed during the meeting are hosted online and a link to each of them can be found at the end of specification document.
Any proposition to change anything in the specification must be done through a Pull Request in this repository.
Url Builder have inconsistent behaviour across platforms, and so we need a way to try to sincronize the same behaviour.
The expected behaviour of our url build mechanism can be described by these test cases on this json:
And now we can use this same json to try to run our tests on the same inputs and outputs across platforms.
Android checklist
iOS checklist
Backend checklist
Describe the problem
Users expect a documentation to help understanding and using the Analytics features
Expected behavior
As a user I expect a description of the purpose of the feature and the steps to add this to my app
Problem description
When Beagle performs screen change navigation, the same animation is always performed without the user being able to customize it.
Expected behavior
Enable the user a way to customize Beagle's navigation animations through the passage of an object that maps inbound and outbound animation.
Android checklist
iOS checklist
Backend checklist
Describe the problem
We are obfuscating exceptions thrown by third-party calls.
Expected behaviour
Thrown the coming exception.
Describe the problem
I have a menu with a bottom to close the application when I click in the button to close and open the app again the menu is gone.
Code
BFF:
@Service
class HomeService {
fun createScreenBuilder(): ScreenBuilder = HomeScreenBuilder()
}
private class HomeScreenBuilder(
) : ScreenBuilder {
override fun build() = Screen(child = Container(children = listOf(Text("Text"))), navigationBar = NavigationBar(title = "Hi, Jordan!",
navigationBarItems = listOf(NavigationBarItem(text = "",
image = "https://image.freepik.com/free-photo/beautiful-girl-stands-near-walll-with-leaves_8353-5377.jpg",
action = Navigate(type = NavigationType.FINISH_VIEW))
)
)
)
}
@RestController
class HomeController(private val homeService: HomeService) {
@GetMapping("/home")
fun getHome() = homeService.createScreenBuilder()
}
Android:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val intent = BeagleActivity.newIntent(this, ScreenRequest("/home"))
startActivity(intent)
finish()
}
}
Expected behavior
Show the menu always when open the app.
Describe the problem
Actual the class NetworkImage
has a field called path
, but is difficult to know what this variable do without open the documentation
Expected behavior
Change this field to url
it is more suggestive to understand what the field do.
Describe the problem
When implementing DesignSystem
in the application, the user is obliged to inform at least one default resource for image
, theme
, textAppearance
, buttonStyle
and toolbarStyle
.
Below is an image of the Design System declaration:
Expected behavior
The only mandatory attribute that the user must inform the Beagle should only be the application theme
. And also change the name of the tabBarStyle
method to tabViewStyle
, since the component it refers to is TabView
.
Problem description
The names style
and appearance
in the Beagle do not match your responsibilities.
Expected behavior
Change Style
to StyleId
and change Appearance
to Style
.
Android checklist
iOS checklist
Backend checklist
Align Items, Align Self and Align Content contain an enum for all aligns, thus having attributes that are not part of the specific property
A possible solution is to create a specific enum for these properties
Android checklist
iOS checklist
Backend checklist
Problem description
Currently Beagle supports colors with or without sending #, which configures a lack of standardization.
Expected behavior
Color values (backgroundColor and textColor) must have the #
in front of the hexadecimal and the Alpha component must be at the end. Valid formats: #RGB
, #RGBA
, #RRGGBB
, #RRGGBBAA
.
Android checklist
iOS checklist
Backend checklist
Appearance: In iOS ScrollView is AppearanceComponent
and in android it is not.
Add appearance to android ScrollView or remove it from iOS?
Flex: iOS ScrollView has flex.grow = 1
.
Remove from iOS or add it Android?
ScrollView is not FlexComponent
, maybe it should be?
Android checklist
iOS checklist
Schema checklist
When the user downloads an image from a remote source, in the application it is interesting to have a placeholder while the image does not load.
Today the beagle does not provide an option for the user to use a placeholder while the image completes loading.
Provide a placeholder
field which receives an ServerDrivenComponent
component within the NetworkImage
component.
Describe the problem
Currently Beagle has a usage context that is more focused on mobile and several points do not make sense for the web.
Expected behavior
For the use of a single BFF serving mobile and web, standardization of names, construction of components and separation between flex and style must be standardized.
Steps
Style
to Theme
and change Appearance
to Style
AndroidStyle
to Theme
and change Appearance
to Style
iOSFlex
inside the Style
and remove from the Flex
what should be in the Style
(margin, position, padding, size, display, direction) AndroidFlex
inside the Style
and remove from the Flex
what should be in the Style
(margin, position, padding, size, display, direction) iOSStyle
(color, backgroundColor, marginStart, marginEnd, paddingStart, paddingEnd) AndroidStyle
(color, backgroundColor, marginStart, marginEnd, paddingStart, paddingEnd) iOSapplyFlex
external today without having to instantiate Style
AndroidapplyFlex
external today without having to instantiate Style
iOSchildren
for the purpose of semantic coherence or whatever is more than one child
should be called children
Androidchildren
for the purpose of semantic coherence or whatever is more than one child
should be called children
iOSToday for the Beagle user to use Form
with some validation, in addition to creating a Validator
he has to create a custom InputWidget
and implement the StateChangeable
interface. With that, it is necessary to create an Observable<WidgetState>
variable and
every time the component changes state, call the notifyObservers
method.
In order to improve the developer experience, it would be ideal for all InputWidget
to already implement StateChangeable
and thus it would be responsible only for informing when the component's state changes.
Problem
I need to add header to HTTP request to call circles in Charles. And this is not easy to implement.
Example code:
class BeagleConfig {
static let dependencies = BeagleDependencies()
static let client = NetworkClientDefault(dependencies: dependencies)
static func config() {
client.httpRequestBuilder.additionalHeaders = ["x-circle-id":"578640d5-50af-41d4-817c-4639f80c207d"]
dependencies.networkClient = client
Beagle.dependencies = dependencies
}
}
Solution
A possible solution is adding an interception on network layer to abstract this problem.
To avoid creating a different issue for each item, I will aggregate here various improvements that can be made on the iOS workflow (listed by priority)
.codeowners
properly).Obs: This is just a brainstorm, maybe some items would be too hard to implement, and so it doesn't really pay off to do them.
As a beagle developer, I wanted to create a complex form flow with multiple steps/screens, and submit inputs only on the last step, so that I will minimize the payloads on each step.
Similarly, as a beagle developer, I should be able to, when submitting a form, access some local values stored in the app, so that my microservices do not need to request simple data to other microservices (like tokens) that my app already has.
Form
to define which inputs should be saved locallyForm
to read locally stored values that will be submitted as well1- Entregar um handler para aplicação fazer store dos dados de modo que o beagle possa solicitar para gravar/ler dados que a aplicação pode salvar como quiser.
Além disso ter uma implementação default para isso.
Abaixo esboço do Handler:
interface BeagleStoreHandler {
fun save(storeType: StoreType, key: String, value: String)
fun read(storeType: StoreType, key: String)
enum StoreType {
SCREEN,
FORM
}
}
//Custom Handler da aplicação
@BeagleComponent
class AppStoreHandler : BeagleStoreHandler {
}
//Definido dentro do beagle e será usado caso a aplicação não fornecer uma implementação.
//Se for Screen vai salvar com banco de dados
//Se for FORM salvar em memória
class DefaultStoreHandler : BeagleStoreHandler {
}
2- Mudar a api do Form para receber esses novos parâmetros
data class Form (
val action: Action, // Pode ser uma action de navigate quando o cara só quer fazer store dos campos e transicionar para outra tela ou fazer qualquer coisa.
val storedParameters: List<String>,// aqui pega do BeagleStoreHandler
val additionalParameters: Map<String, String>,// com esse parâmetro, não precisamos mas do FormInputHidden
val shouldStoreFields: Boolean = false, //determina se vai salvar os campos Input, input hidden
val child: ServerDrivenComponent
) : ServerDrivenComponent, LayoutComponent
data class FormInput(
val name: String,
val required: Boolean? = null,
val validator: String? = null,
val errorMessage: String? = null,
val overrideStoredName: String? = null,
override val child: InputWidget
) : ServerDrivenComponent, GhostComponent
// Regra para armazenamento dos inputs:
// A- Se shouldStoreFields true salva tudo, usando name
// B- Se shouldStoreFields false salva apenas os que tiverem overrideStoredName
// C- Se shouldStoreFields true salva tudo, e tiver overrideStoredName preenchido sobrescreve o name a ser salvo
3- Em que momento o beagle irá ler os dados pra submeter?
No momento do submit do Form o FormViewRenderer vai avaliar isso
**public** **func** toView(context: BeagleContext, dependencies: RenderableDependencies) -> UIView
located on Screen Component
Problem description
When the Form
has an optional and a required field it never enables FormSubmit
.
Expected behavior
When the Form
has an optional field it is expected that it will not be validated.
Widget.applyFlex(
Flex(
margin = EdgeValue(top = 10.unitReal()),
size = Size(height = 100.unitPercent()),
padding = EdgeValue(horizontal = 15.unitReal())
)
)
Widget.buildAndApplyFlex(
FlexBuilder()
.margin(top = 10.unitReal())
.size(height = 100.unitPercent())
.pagging(horizontal = 15.unitReal())
)
Android checklist
iOS checklist
Backend checklist
Problem description
The FormValidation
action takes care of displaying the errors returned by the api for a Form
. However, her name does not match her function.
Expected behavior
A more intuitive name for this action would be FormValidationError
, as it deals exclusively with errors.
Development
As this change has an impact for all Beagle projects, opening PR from the #74 and point to himself.
Wait until #54, as it will likely already refactor all of form.
Right now, for people that don't have access to our github repository, we are using a bitrise link to share our compiled ios framework. This is not working correctly because it's an expiring link due to a limitation on sharing zip files via bitrise.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.