Compare commits

...

6 Commits

Author SHA1 Message Date
Andrey Pokhilko
7a823e89f1 Add option to limit example len (#1145)
Do not save OAS example response if it is over the limit.
SpecGen.MaxExampleLen is measured in bytes.
Limit=0 means "don't record any examples", while limit=-1 means "record all".

Limit is configured via the config file / --set: --set oas.max-example-len=100.
The default is 10KB.

This PR breaks the previous config. Moved oas bool (enable/disable OAS) to oas.enable.
Users who wish to disable OAS (or to explicitly enable it) should now to so with --set oas.enable=false instead of --set oas=false.

Co-authored-by: Nimrod Gilboa Markevich <nimrod@up9.com>
Co-authored-by: Nimrod Gilboa Markevich <59927337+nimrod-up9@users.noreply.github.com>
2022-06-16 14:18:42 +03:00
gadotroee
be98d85cb8 Recreate package-lock to remove "old" packages (#1152) 2022-06-16 13:04:38 +03:00
AmitUp9
e743ab7f7a TRA_4579 - fix acceptance test of right panel body checkboxes (#1150)
* #run_acceptance_tests

* added data-cy to checkboxes in body section, removed unnecessary tests and fix decoded text testing

* #run_acceptance_tests
2022-06-16 10:27:31 +03:00
AmitUp9
78081a4a16 Node sass npm package migrate to sass npm package (#1143)
* remove node-sass from project and install sass instead

* fix ui-common path
2022-06-14 16:53:34 +03:00
lirazyehezkel
0ef6a7d2c4 Fix images imports (#1139)
* Fix images imports

* fix image name
2022-06-13 16:19:50 +03:00
Igor Gov
ba361df7e7 Mizu install should be namespace aware (#1141) 2022-06-13 15:26:00 +03:00
50 changed files with 8266 additions and 8144 deletions

View File

@@ -269,7 +269,7 @@ function checkRightSideResponseBody() {
const responseBody = JSON.parse(decodedBody); const responseBody = JSON.parse(decodedBody);
const expectdJsonBody = { const expectedJsonBody = {
args: RegExp({}), args: RegExp({}),
url: RegExp('http://.*/get'), url: RegExp('http://.*/get'),
headers: { headers: {
@@ -279,27 +279,24 @@ function checkRightSideResponseBody() {
} }
}; };
expect(responseBody.args).to.match(expectdJsonBody.args); const expectedStringInJsonBody = RegExp('/api/v1/namespaces/.*/services/.*/proxy/get');
expect(responseBody.url).to.match(expectdJsonBody.url);
expect(responseBody.headers['User-Agent']).to.match(expectdJsonBody.headers['User-Agent']);
expect(responseBody.headers['Accept-Encoding']).to.match(expectdJsonBody.headers['Accept-Encoding']); expect(responseBody.args).to.match(expectedJsonBody.args);
expect(responseBody.headers['X-Forwarded-Uri']).to.match(expectdJsonBody.headers['X-Forwarded-Uri']); expect(responseBody.url).to.match(expectedJsonBody.url);
expect(responseBody.headers['User-Agent']).to.match(expectedJsonBody.headers['User-Agent']);
expect(responseBody.headers['Accept-Encoding']).to.match(expectedJsonBody.headers['Accept-Encoding']);
expect(responseBody.headers['X-Forwarded-Uri']).to.match(expectedJsonBody.headers['X-Forwarded-Uri']);
cy.get(`${Cypress.env('bodyJsonClass')}`).should('have.text', encodedBody); cy.get(`${Cypress.env('bodyJsonClass')}`).should('have.text', encodedBody);
cy.get(`[data-cy="lineNumbersCheckBoxInput"]`).should('be.disabled');
clickCheckbox('Decode Base64'); clickCheckbox('Decode Base64');
cy.get(`[data-cy="lineNumbersCheckBoxInput"]`).should('not.be.disabled');
cy.get(`${Cypress.env('bodyJsonClass')} > `).its('length').should('be.gt', 1).then(linesNum => { cy.get(`${Cypress.env('bodyJsonClass')} > `).its('length').should('be.gt', 1).then(linesNum => {
cy.get(`${Cypress.env('bodyJsonClass')} > >`).its('length').should('be.gt', linesNum).then(jsonItemsNum => { cy.get(`${Cypress.env('bodyJsonClass')} > >`).its('length').should('be.gt', linesNum).then(jsonItemsNum => {
// checkPrettyAndLineNums(decodedBody); checkOnlyLineNumberes(jsonItemsNum, expectedStringInJsonBody);
//clickCheckbox('Line numbers');
//checkPrettyOrNothing(jsonItemsNum, decodedBody);
// clickCheckbox('Pretty');
// checkPrettyOrNothing(jsonItemsNum, decodedBody);
//
// clickCheckbox('Line numbers');
// checkOnlyLineNumberes(jsonItemsNum, decodedBody);
}); });
}); });
}); });
@@ -309,37 +306,9 @@ function clickCheckbox(type) {
cy.contains(`${type}`).prev().children().click(); cy.contains(`${type}`).prev().children().click();
} }
function checkPrettyAndLineNums(decodedBody) {
decodedBody = decodedBody.replaceAll(' ', '');
cy.get(`${Cypress.env('bodyJsonClass')} >`).then(elements => {
const lines = Object.values(elements);
lines.forEach((line, index) => {
if (line.getAttribute) {
const cleanLine = getCleanLine(line);
const currentLineFromDecodedText = decodedBody.substring(0, cleanLine.length);
expect(cleanLine).to.equal(currentLineFromDecodedText, `expected the text in line number ${index + 1} to match the text that generated by the base64 decoding`)
decodedBody = decodedBody.substring(cleanLine.length);
}
});
});
}
function getCleanLine(lineElement) {
return (lineElement.innerText.substring(0, lineElement.innerText.length - 1)).replaceAll(' ', '');
}
function checkPrettyOrNothing(jsonItems, decodedBody) {
cy.get(`${Cypress.env('bodyJsonClass')} > `).should('have.length', jsonItems).then(text => {
const json = text.text();
expect(json).to.equal(decodedBody);
});
}
function checkOnlyLineNumberes(jsonItems, decodedText) { function checkOnlyLineNumberes(jsonItems, decodedText) {
cy.get(`${Cypress.env('bodyJsonClass')} >`).should('have.length', 1).and('have.text', decodedText); cy.get(`${Cypress.env('bodyJsonClass')} > >`).should('have.length', jsonItems);
cy.get(`${Cypress.env('bodyJsonClass')} > >`).should('have.length', jsonItems) cy.get(`${Cypress.env('bodyJsonClass')} >`).contains(decodedText);
} }
function serviceMapCheck() { function serviceMapCheck() {

View File

@@ -109,6 +109,9 @@ func TestRedis(t *testing.T) {
} }
func TestAmqp(t *testing.T) { func TestAmqp(t *testing.T) {
t.Skip("ignoredd for now because those tests are not stable")
if testing.Short() { if testing.Short() {
t.Skip("ignored acceptance test") t.Skip("ignored acceptance test")
} }

View File

@@ -118,7 +118,7 @@ func hostApi(socketHarOutputChannel chan<- *tapApi.OutputChannelItem) *gin.Engin
api.WebSocketRoutes(ginApp, &eventHandlers) api.WebSocketRoutes(ginApp, &eventHandlers)
if config.Config.OAS { if config.Config.OAS.Enable {
routes.OASRoutes(ginApp) routes.OASRoutes(ginApp)
} }
@@ -200,7 +200,7 @@ func runInHarReaderMode() {
} }
func enableExpFeatureIfNeeded() { func enableExpFeatureIfNeeded() {
if config.Config.OAS { if config.Config.OAS.Enable {
oasGenerator := dependency.GetInstance(dependency.OasGeneratorDependency).(oas.OasGenerator) oasGenerator := dependency.GetInstance(dependency.OasGeneratorDependency).(oas.OasGenerator)
oasGenerator.Start() oasGenerator.Start()
} }
@@ -227,7 +227,7 @@ func setUIFlags(uiIndexPath string) error {
return err return err
} }
replacedContent := strings.Replace(string(read), "__IS_OAS_ENABLED__", strconv.FormatBool(config.Config.OAS), 1) replacedContent := strings.Replace(string(read), "__IS_OAS_ENABLED__", strconv.FormatBool(config.Config.OAS.Enable), 1)
replacedContent = strings.Replace(replacedContent, "__IS_SERVICE_MAP_ENABLED__", strconv.FormatBool(config.Config.ServiceMap), 1) replacedContent = strings.Replace(replacedContent, "__IS_SERVICE_MAP_ENABLED__", strconv.FormatBool(config.Config.ServiceMap), 1)
err = ioutil.WriteFile(uiIndexPath, []byte(replacedContent), 0) err = ioutil.WriteFile(uiIndexPath, []byte(replacedContent), 0)
@@ -363,7 +363,7 @@ func handleIncomingMessageAsTapper(socketConnection *websocket.Conn) {
func initializeDependencies() { func initializeDependencies() {
dependency.RegisterGenerator(dependency.ServiceMapGeneratorDependency, func() interface{} { return servicemap.GetDefaultServiceMapInstance() }) dependency.RegisterGenerator(dependency.ServiceMapGeneratorDependency, func() interface{} { return servicemap.GetDefaultServiceMapInstance() })
dependency.RegisterGenerator(dependency.OasGeneratorDependency, func() interface{} { return oas.GetDefaultOasGeneratorInstance() }) dependency.RegisterGenerator(dependency.OasGeneratorDependency, func() interface{} { return oas.GetDefaultOasGeneratorInstance(config.Config.OAS.MaxExampleLen) })
dependency.RegisterGenerator(dependency.EntriesInserter, func() interface{} { return api.GetBasenineEntryInserterInstance() }) dependency.RegisterGenerator(dependency.EntriesInserter, func() interface{} { return api.GetBasenineEntryInserterInstance() })
dependency.RegisterGenerator(dependency.EntriesProvider, func() interface{} { return &entries.BasenineEntriesProvider{} }) dependency.RegisterGenerator(dependency.EntriesProvider, func() interface{} { return &entries.BasenineEntriesProvider{} })
dependency.RegisterGenerator(dependency.EntriesSocketStreamer, func() interface{} { return &api.BasenineEntryStreamer{} }) dependency.RegisterGenerator(dependency.EntriesSocketStreamer, func() interface{} { return &api.BasenineEntryStreamer{} })

View File

@@ -34,12 +34,12 @@ func TestGetOASSpec(t *testing.T) {
func getRecorderAndContext() (*httptest.ResponseRecorder, *gin.Context) { func getRecorderAndContext() (*httptest.ResponseRecorder, *gin.Context) {
dependency.RegisterGenerator(dependency.OasGeneratorDependency, func() interface{} { dependency.RegisterGenerator(dependency.OasGeneratorDependency, func() interface{} {
return oas.GetDefaultOasGeneratorInstance() return oas.GetDefaultOasGeneratorInstance(-1)
}) })
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
c, _ := gin.CreateTestContext(recorder) c, _ := gin.CreateTestContext(recorder)
oas.GetDefaultOasGeneratorInstance().Start() oas.GetDefaultOasGeneratorInstance(-1).Start()
oas.GetDefaultOasGeneratorInstance().GetServiceSpecs().Store("some", oas.NewGen("some")) oas.GetDefaultOasGeneratorInstance(-1).GetServiceSpecs().Store("some", oas.NewGen("some"))
return recorder, c return recorder, c
} }

View File

@@ -9,7 +9,7 @@ var ignoredCtypes = []string{"application/javascript", "application/x-javascript
var ignoredHeaders = []string{ var ignoredHeaders = []string{
"a-im", "accept", "a-im", "accept",
"authorization", "cache-control", "connection", "content-encoding", "content-length", "content-type", "cookie", "authorization", "cache-control", "connection", "content-encoding", "content-length", "content-range", "content-type", "cookie",
"date", "dnt", "expect", "forwarded", "from", "front-end-https", "host", "http2-settings", "date", "dnt", "expect", "forwarded", "from", "front-end-https", "host", "http2-settings",
"max-forwards", "origin", "pragma", "proxy-authorization", "proxy-connection", "range", "referer", "max-forwards", "origin", "pragma", "proxy-authorization", "proxy-connection", "range", "referer",
"save-data", "te", "trailer", "transfer-encoding", "upgrade", "upgrade-insecure-requests", "x-download-options", "save-data", "te", "trailer", "transfer-encoding", "upgrade", "upgrade-insecure-requests", "x-download-options",

View File

@@ -28,13 +28,14 @@ type OasGenerator interface {
} }
type defaultOasGenerator struct { type defaultOasGenerator struct {
started bool started bool
serviceSpecs *sync.Map serviceSpecs *sync.Map
maxExampleLen int
} }
func GetDefaultOasGeneratorInstance() *defaultOasGenerator { func GetDefaultOasGeneratorInstance(maxExampleLen int) *defaultOasGenerator {
syncOnce.Do(func() { syncOnce.Do(func() {
instance = NewDefaultOasGenerator() instance = NewDefaultOasGenerator(maxExampleLen)
logger.Log.Debug("OAS Generator Initialized") logger.Log.Debug("OAS Generator Initialized")
}) })
return instance return instance
@@ -117,6 +118,7 @@ func (g *defaultOasGenerator) getGen(dest string, urlStr string) *SpecGen {
var gen *SpecGen var gen *SpecGen
if !found { if !found {
gen = NewGen(u.Scheme + "://" + dest) gen = NewGen(u.Scheme + "://" + dest)
gen.MaxExampleLen = g.maxExampleLen
g.serviceSpecs.Store(dest, gen) g.serviceSpecs.Store(dest, gen)
} else { } else {
gen = val.(*SpecGen) gen = val.(*SpecGen)
@@ -132,9 +134,10 @@ func (g *defaultOasGenerator) GetServiceSpecs() *sync.Map {
return g.serviceSpecs return g.serviceSpecs
} }
func NewDefaultOasGenerator() *defaultOasGenerator { func NewDefaultOasGenerator(maxExampleLen int) *defaultOasGenerator {
return &defaultOasGenerator{ return &defaultOasGenerator{
started: false, started: false,
serviceSpecs: &sync.Map{}, serviceSpecs: &sync.Map{},
maxExampleLen: maxExampleLen,
} }
} }

View File

@@ -8,7 +8,7 @@ import (
) )
func TestOASGen(t *testing.T) { func TestOASGen(t *testing.T) {
gen := GetDefaultOasGeneratorInstance() gen := GetDefaultOasGeneratorInstance(-1)
e := new(har.Entry) e := new(har.Entry)
err := json.Unmarshal([]byte(`{"startedDateTime": "20000101","request": {"url": "https://host/path", "method": "GET"}, "response": {"status": 200}}`), e) err := json.Unmarshal([]byte(`{"startedDateTime": "20000101","request": {"url": "https://host/path", "method": "GET"}, "response": {"status": 200}}`), e)

View File

@@ -42,6 +42,8 @@ type reqResp struct { // hello, generics in Go
} }
type SpecGen struct { type SpecGen struct {
MaxExampleLen int // -1 unlimited, 0 and above sets limit
oas *openapi.OpenAPI oas *openapi.OpenAPI
tree *Node tree *Node
lock sync.Mutex lock sync.Mutex
@@ -59,7 +61,11 @@ func NewGen(server string) *SpecGen {
spec.Servers = make([]*openapi.Server, 0) spec.Servers = make([]*openapi.Server, 0)
spec.Servers = append(spec.Servers, &openapi.Server{URL: server}) spec.Servers = append(spec.Servers, &openapi.Server{URL: server})
gen := SpecGen{oas: spec, tree: new(Node)} gen := SpecGen{
oas: spec,
tree: new(Node),
MaxExampleLen: -1,
}
return &gen return &gen
} }
@@ -228,7 +234,7 @@ func (g *SpecGen) handlePathObj(entryWithSource *EntryWithSource) (string, error
split = strings.Split(urlParsed.Path, "/") split = strings.Split(urlParsed.Path, "/")
} }
node := g.tree.getOrSet(split, new(openapi.PathObj), entryWithSource.Id) node := g.tree.getOrSet(split, new(openapi.PathObj), entryWithSource.Id)
opObj, err := handleOpObj(entryWithSource, node.pathObj) opObj, err := handleOpObj(entryWithSource, node.pathObj, g.MaxExampleLen)
if opObj != nil { if opObj != nil {
return opObj.OperationID, err return opObj.OperationID, err
@@ -237,7 +243,7 @@ func (g *SpecGen) handlePathObj(entryWithSource *EntryWithSource) (string, error
return "", err return "", err
} }
func handleOpObj(entryWithSource *EntryWithSource, pathObj *openapi.PathObj) (*openapi.Operation, error) { func handleOpObj(entryWithSource *EntryWithSource, pathObj *openapi.PathObj, limit int) (*openapi.Operation, error) {
entry := entryWithSource.Entry entry := entryWithSource.Entry
isSuccess := 100 <= entry.Response.Status && entry.Response.Status < 400 isSuccess := 100 <= entry.Response.Status && entry.Response.Status < 400
opObj, wasMissing, err := getOpObj(pathObj, entry.Request.Method, isSuccess) opObj, wasMissing, err := getOpObj(pathObj, entry.Request.Method, isSuccess)
@@ -250,12 +256,12 @@ func handleOpObj(entryWithSource *EntryWithSource, pathObj *openapi.PathObj) (*o
return nil, nil return nil, nil
} }
err = handleRequest(&entry.Request, opObj, isSuccess, entryWithSource.Id) err = handleRequest(&entry.Request, opObj, isSuccess, entryWithSource.Id, limit)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = handleResponse(&entry.Response, opObj, isSuccess, entryWithSource.Id) err = handleResponse(&entry.Response, opObj, isSuccess, entryWithSource.Id, limit)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -342,7 +348,7 @@ func handleCounters(opObj *openapi.Operation, success bool, entryWithSource *Ent
return nil return nil
} }
func handleRequest(req *har.Request, opObj *openapi.Operation, isSuccess bool, sampleId string) error { func handleRequest(req *har.Request, opObj *openapi.Operation, isSuccess bool, sampleId string, limit int) error {
// TODO: we don't handle the situation when header/qstr param can be defined on pathObj level. Also the path param defined on opObj // TODO: we don't handle the situation when header/qstr param can be defined on pathObj level. Also the path param defined on opObj
urlParsed, err := url.Parse(req.URL) urlParsed, err := url.Parse(req.URL)
if err != nil { if err != nil {
@@ -390,7 +396,7 @@ func handleRequest(req *har.Request, opObj *openapi.Operation, isSuccess bool, s
} else { } else {
reqCtype, _ := getReqCtype(req) reqCtype, _ := getReqCtype(req)
reqMedia, err := fillContent(reqResp{Req: req}, reqBody.Content, reqCtype, sampleId) reqMedia, err := fillContent(reqResp{Req: req}, reqBody.Content, reqCtype, sampleId, limit)
if err != nil { if err != nil {
return err return err
} }
@@ -402,7 +408,7 @@ func handleRequest(req *har.Request, opObj *openapi.Operation, isSuccess bool, s
return nil return nil
} }
func handleResponse(resp *har.Response, opObj *openapi.Operation, isSuccess bool, sampleId string) error { func handleResponse(resp *har.Response, opObj *openapi.Operation, isSuccess bool, sampleId string, limit int) error {
// TODO: we don't support "default" response // TODO: we don't support "default" response
respObj, err := getResponseObj(resp, opObj, isSuccess) respObj, err := getResponseObj(resp, opObj, isSuccess)
if err != nil { if err != nil {
@@ -415,7 +421,7 @@ func handleResponse(resp *har.Response, opObj *openapi.Operation, isSuccess bool
respCtype := getRespCtype(resp) respCtype := getRespCtype(resp)
respContent := respObj.Content respContent := respObj.Content
respMedia, err := fillContent(reqResp{Resp: resp}, respContent, respCtype, sampleId) respMedia, err := fillContent(reqResp{Resp: resp}, respContent, respCtype, sampleId, limit)
if err != nil { if err != nil {
return err return err
} }
@@ -467,7 +473,7 @@ func handleRespHeaders(reqHeaders []har.Header, respObj *openapi.ResponseObj, sa
} }
} }
func fillContent(reqResp reqResp, respContent openapi.Content, ctype string, sampleId string) (*openapi.MediaType, error) { func fillContent(reqResp reqResp, respContent openapi.Content, ctype string, sampleId string, limit int) (*openapi.MediaType, error) {
content, found := respContent[ctype] content, found := respContent[ctype]
if !found { if !found {
respContent[ctype] = &openapi.MediaType{} respContent[ctype] = &openapi.MediaType{}
@@ -510,7 +516,7 @@ func fillContent(reqResp reqResp, respContent openapi.Content, ctype string, sam
handleFormDataMultipart(text, content, params) handleFormDataMultipart(text, content, params)
} }
if content.Example == nil && len(exampleMsg) > len(content.Example) { if len(exampleMsg) > len(content.Example) && (limit < 0 || len(exampleMsg) <= limit) {
content.Example = exampleMsg content.Example = exampleMsg
} }
} }

View File

@@ -48,7 +48,7 @@ func TestEntries(t *testing.T) {
t.FailNow() t.FailNow()
} }
gen := NewDefaultOasGenerator() gen := NewDefaultOasGenerator(-1)
gen.serviceSpecs = new(sync.Map) gen.serviceSpecs = new(sync.Map)
loadStartingOAS("test_artifacts/catalogue.json", "catalogue", gen.serviceSpecs) loadStartingOAS("test_artifacts/catalogue.json", "catalogue", gen.serviceSpecs)
loadStartingOAS("test_artifacts/trcc.json", "trcc-api-service", gen.serviceSpecs) loadStartingOAS("test_artifacts/trcc.json", "trcc-api-service", gen.serviceSpecs)
@@ -122,7 +122,7 @@ func TestEntries(t *testing.T) {
} }
func TestFileSingle(t *testing.T) { func TestFileSingle(t *testing.T) {
gen := NewDefaultOasGenerator() gen := NewDefaultOasGenerator(-1)
gen.serviceSpecs = new(sync.Map) gen.serviceSpecs = new(sync.Map)
// loadStartingOAS() // loadStartingOAS()
file := "test_artifacts/params.har" file := "test_artifacts/params.har"
@@ -212,7 +212,7 @@ func loadStartingOAS(file string, label string, specs *sync.Map) {
} }
func TestEntriesNegative(t *testing.T) { func TestEntriesNegative(t *testing.T) {
gen := NewDefaultOasGenerator() gen := NewDefaultOasGenerator(-1)
gen.serviceSpecs = new(sync.Map) gen.serviceSpecs = new(sync.Map)
files := []string{"invalid"} files := []string{"invalid"}
_, err := feedEntries(files, false, gen) _, err := feedEntries(files, false, gen)
@@ -223,7 +223,7 @@ func TestEntriesNegative(t *testing.T) {
} }
func TestEntriesPositive(t *testing.T) { func TestEntriesPositive(t *testing.T) {
gen := NewDefaultOasGenerator() gen := NewDefaultOasGenerator(-1)
gen.serviceSpecs = new(sync.Map) gen.serviceSpecs = new(sync.Map)
files := []string{"test_artifacts/params.har"} files := []string{"test_artifacts/params.har"}
_, err := feedEntries(files, false, gen) _, err := feedEntries(files, false, gen)

View File

@@ -333,7 +333,7 @@
} }
} }
}, },
"example": "agent-id=ade\u0026callback-url=\u0026token=sometoken", "example": "agent-id=ade\u0026callback-url=\u0026token=sometoken-second-val\u0026optional=another",
"x-sample-entry": "000000000000000000000008" "x-sample-entry": "000000000000000000000008"
} }
}, },

View File

@@ -25,7 +25,7 @@ func runMizuInstall() {
var sb strings.Builder var sb strings.Builder
sb.WriteString("Hello! This command can be used to install Mizu Pro edition on your Kubernetes cluster.") sb.WriteString("Hello! This command can be used to install Mizu Pro edition on your Kubernetes cluster.")
sb.WriteString("\nPlease run:") sb.WriteString("\nPlease run:")
sb.WriteString("\n\tmizu install -o | kubectl apply -f -") sb.WriteString("\n\tmizu install -o | kubectl apply -n mizu -f -")
sb.WriteString("\n\nor use helm chart as described in https://getmizu.io/docs/installing-mizu/centralized-installation\n") sb.WriteString("\n\nor use helm chart as described in https://getmizu.io/docs/installing-mizu/centralized-installation\n")
fmt.Print(sb.String()) fmt.Print(sb.String())

View File

@@ -39,7 +39,7 @@ type ConfigStruct struct {
HeadlessMode bool `yaml:"headless" default:"false"` HeadlessMode bool `yaml:"headless" default:"false"`
LogLevelStr string `yaml:"log-level,omitempty" default:"INFO" readonly:""` LogLevelStr string `yaml:"log-level,omitempty" default:"INFO" readonly:""`
ServiceMap bool `yaml:"service-map" default:"true"` ServiceMap bool `yaml:"service-map" default:"true"`
OAS bool `yaml:"oas" default:"true"` OAS shared.OASConfig `yaml:"oas"`
} }
func (config *ConfigStruct) validate() error { func (config *ConfigStruct) validate() error {

View File

@@ -32,6 +32,11 @@ type Resources struct {
MemoryRequests string `yaml:"memory-requests" default:"50Mi"` MemoryRequests string `yaml:"memory-requests" default:"50Mi"`
} }
type OASConfig struct {
Enable bool `yaml:"enabled" default:"true"`
MaxExampleLen int `yaml:"max-example-len" default:"10240"`
}
type MizuAgentConfig struct { type MizuAgentConfig struct {
MaxDBSizeBytes int64 `json:"maxDBSizeBytes"` MaxDBSizeBytes int64 `json:"maxDBSizeBytes"`
InsertionFilter string `json:"insertionFilter"` InsertionFilter string `json:"insertionFilter"`
@@ -42,7 +47,7 @@ type MizuAgentConfig struct {
MizuResourcesNamespace string `json:"mizuResourceNamespace"` MizuResourcesNamespace string `json:"mizuResourceNamespace"`
AgentDatabasePath string `json:"agentDatabasePath"` AgentDatabasePath string `json:"agentDatabasePath"`
ServiceMap bool `json:"serviceMap"` ServiceMap bool `json:"serviceMap"`
OAS bool `json:"oas"` OAS OASConfig `json:"oas"`
Telemetry bool `json:"telemetry"` Telemetry bool `json:"telemetry"`
} }

File diff suppressed because it is too large Load Diff

View File

@@ -26,7 +26,7 @@
"@craco/craco": "^6.4.3", "@craco/craco": "^6.4.3",
"@types/jest": "^26.0.24", "@types/jest": "^26.0.24",
"@types/node": "^12.20.54", "@types/node": "^12.20.54",
"node-sass": "^6.0.1", "sass": "^1.52.3",
"react": "^17.0.2", "react": "^17.0.2",
"react-copy-to-clipboard": "^5.1.0", "react-copy-to-clipboard": "^5.1.0",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",

View File

@@ -3,8 +3,8 @@ import styles from './EntriesList.module.sass';
import ScrollableFeedVirtualized from "react-scrollable-feed-virtualized"; import ScrollableFeedVirtualized from "react-scrollable-feed-virtualized";
import Moment from 'moment'; import Moment from 'moment';
import {EntryItem} from "../EntryListItem/EntryListItem"; import {EntryItem} from "../EntryListItem/EntryListItem";
import down from "../assets/downImg.svg"; import down from "assets/downImg.svg";
import spinner from '../assets/spinner.svg'; import spinner from 'assets/spinner.svg';
import {RecoilState, useRecoilState, useRecoilValue, useSetRecoilState} from "recoil"; import {RecoilState, useRecoilState, useRecoilValue, useSetRecoilState} from "recoil";
import entriesAtom from "../../recoil/entries"; import entriesAtom from "../../recoil/entries";
import queryAtom from "../../recoil/query"; import queryAtom from "../../recoil/query";

View File

Before

Width:  |  Height:  |  Size: 301 B

After

Width:  |  Height:  |  Size: 301 B

View File

Before

Width:  |  Height:  |  Size: 673 B

After

Width:  |  Height:  |  Size: 673 B

View File

@@ -12,7 +12,7 @@ import TrafficViewerApiAtom from "../../recoil/TrafficViewerApi/atom";
import queryAtom from "../../recoil/query/atom"; import queryAtom from "../../recoil/query/atom";
import useWindowDimensions, { useRequestTextByWidth } from "../../hooks/WindowDimensionsHook"; import useWindowDimensions, { useRequestTextByWidth } from "../../hooks/WindowDimensionsHook";
import { TOAST_CONTAINER_ID } from "../../configs/Consts"; import { TOAST_CONTAINER_ID } from "../../configs/Consts";
import spinner from "../assets/spinner.svg"; import spinner from "assets/spinner.svg";
const useStyles = makeStyles(() => ({ const useStyles = makeStyles(() => ({
entryTitle: { entryTitle: {

View File

@@ -192,17 +192,17 @@ export const EntryBodySection: React.FC<EntryBodySectionProps> = ({
> >
<div style={{ display: 'flex', alignItems: 'center', alignContent: 'center', margin: "5px 0" }}> <div style={{ display: 'flex', alignItems: 'center', alignContent: 'center', margin: "5px 0" }}>
{supportsPrettying && <div style={{ paddingTop: 3 }}> {supportsPrettying && <div style={{ paddingTop: 3 }}>
<Checkbox checked={isPretty} onToggle={() => { setIsPretty(!isPretty) }} /> <Checkbox checked={isPretty} onToggle={() => { setIsPretty(!isPretty) }} data-cy="prettyCheckBoxInput"/>
</div>} </div>}
{supportsPrettying && <span style={{ marginLeft: '.2rem' }}>Pretty</span>} {supportsPrettying && <span style={{ marginLeft: '.2rem' }}>Pretty</span>}
<div style={{ paddingTop: 3, paddingLeft: supportsPrettying ? 20 : 0 }}> <div style={{ paddingTop: 3, paddingLeft: supportsPrettying ? 20 : 0 }}>
<Checkbox checked={showLineNumbers} onToggle={() => { setShowLineNumbers(!showLineNumbers) }} disabled={!isLineNumbersGreaterThenOne || !decodeBase64} /> <Checkbox checked={showLineNumbers} onToggle={() => { setShowLineNumbers(!showLineNumbers) }} disabled={!isLineNumbersGreaterThenOne || !decodeBase64} data-cy="lineNumbersCheckBoxInput"/>
</div> </div>
<span style={{ marginLeft: '.2rem' }}>Line numbers</span> <span style={{ marginLeft: '.2rem' }}>Line numbers</span>
{isBase64Encoding && <div style={{ paddingTop: 3, paddingLeft: (isLineNumbersGreaterThenOne || supportsPrettying) ? 20 : 0 }}> {isBase64Encoding && <div style={{ paddingTop: 3, paddingLeft: (isLineNumbersGreaterThenOne || supportsPrettying) ? 20 : 0 }}>
<Checkbox checked={decodeBase64} onToggle={() => { setDecodeBase64(!decodeBase64) }} /> <Checkbox checked={decodeBase64} onToggle={() => { setDecodeBase64(!decodeBase64) }} data-cy="decodeBase64CheckboxInput"/>
</div>} </div>}
{isBase64Encoding && <span style={{ marginLeft: '.2rem' }}>Decode Base64</span>} {isBase64Encoding && <span style={{ marginLeft: '.2rem' }}>Decode Base64</span>}
{!isDecodeGrpc && <span style={{ fontSize: '12px', color: '#DB2156', marginLeft: '.8rem' }}>More than one message in protobuf payload is not supported</span>} {!isDecodeGrpc && <span style={{ fontSize: '12px', color: '#DB2156', marginLeft: '.8rem' }}>More than one message in protobuf payload is not supported</span>}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; background: none; display: block; shape-rendering: auto;" width="200px" height="200px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
<circle cx="50" cy="50" fill="none" stroke="#1d3f72" stroke-width="10" r="35" stroke-dasharray="164.93361431346415 56.97787143782138" transform="rotate(275.903 50 50)">
<animateTransform attributeName="transform" type="rotate" repeatCount="indefinite" dur="1s" values="0 50 50;360 50 50" keyTimes="0;1"></animateTransform>
</circle>
<!-- [ldio] generated by https://loading.io/ --></svg>

After

Width:  |  Height:  |  Size: 673 B

View File

@@ -4,15 +4,15 @@ import SwapHorizIcon from '@mui/icons-material/SwapHoriz';
import styles from './EntryListItem.module.sass'; import styles from './EntryListItem.module.sass';
import StatusCode, {getClassification, StatusCodeClassification} from "../UI/StatusCode/StatusCode"; import StatusCode, {getClassification, StatusCodeClassification} from "../UI/StatusCode/StatusCode";
import Protocol, {ProtocolInterface} from "../UI/Protocol/Protocol" import Protocol, {ProtocolInterface} from "../UI/Protocol/Protocol"
import eBPFLogo from './assets/lock.svg'; import eBPFLogo from 'assets/lock.svg';
import {Summary} from "../UI/Summary/Summary"; import {Summary} from "../UI/Summary/Summary";
import Queryable from "../UI/Queryable/Queryable"; import Queryable from "../UI/Queryable/Queryable";
import ingoingIconSuccess from "./assets/ingoing-traffic-success.svg" import ingoingIconSuccess from "assets/ingoing-traffic-success.svg"
import ingoingIconFailure from "./assets/ingoing-traffic-failure.svg" import ingoingIconFailure from "assets/ingoing-traffic-failure.svg"
import ingoingIconNeutral from "./assets/ingoing-traffic-neutral.svg" import ingoingIconNeutral from "assets/ingoing-traffic-neutral.svg"
import outgoingIconSuccess from "./assets/outgoing-traffic-success.svg" import outgoingIconSuccess from "assets/outgoing-traffic-success.svg"
import outgoingIconFailure from "./assets/outgoing-traffic-failure.svg" import outgoingIconFailure from "assets/outgoing-traffic-failure.svg"
import outgoingIconNeutral from "./assets/outgoing-traffic-neutral.svg" import outgoingIconNeutral from "assets/outgoing-traffic-neutral.svg"
import {useRecoilState} from "recoil"; import {useRecoilState} from "recoil";
import focusedEntryIdAtom from "../../recoil/focusedEntryId"; import focusedEntryIdAtom from "../../recoil/focusedEntryId";
import queryAtom from "../../recoil/query"; import queryAtom from "../../recoil/query";

View File

@@ -4,8 +4,8 @@ import {Button, Grid, Modal, Box, Typography, Backdrop, Fade, Divider, debounce}
import CodeEditor from '@uiw/react-textarea-code-editor'; import CodeEditor from '@uiw/react-textarea-code-editor';
import MenuBookIcon from '@mui/icons-material/MenuBook'; import MenuBookIcon from '@mui/icons-material/MenuBook';
import { SyntaxHighlighter } from "../UI/SyntaxHighlighter"; import { SyntaxHighlighter } from "../UI/SyntaxHighlighter";
import filterUIExample1 from "../TrafficViewer/assets/filter-ui-example-1.png" import filterUIExample1 from "assets/filter-ui-example-1.png"
import filterUIExample2 from "../TrafficViewer/assets/filter-ui-example-2.png" import filterUIExample2 from "assets/filter-ui-example-2.png"
import variables from '../../variables.module.scss'; import variables from '../../variables.module.scss';
import { useRecoilState, useRecoilValue } from "recoil"; import { useRecoilState, useRecoilValue } from "recoil";
import queryAtom from "../../recoil/query"; import queryAtom from "../../recoil/query";

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -1,6 +1,6 @@
import React from "react"; import React from "react";
import collapsedImg from "../assets/collapsed.svg"; import collapsedImg from "assets/collapsed.svg";
import expandedImg from "../assets/expanded.svg"; import expandedImg from "assets/expanded.svg";
import styles from "./CollapsibleContainer.module.sass"; import styles from "./CollapsibleContainer.module.sass";
interface Props { interface Props {

View File

Before

Width:  |  Height:  |  Size: 711 B

After

Width:  |  Height:  |  Size: 711 B

View File

Before

Width:  |  Height:  |  Size: 302 B

After

Width:  |  Height:  |  Size: 302 B

View File

@@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { CopyToClipboard } from 'react-copy-to-clipboard'; import { CopyToClipboard } from 'react-copy-to-clipboard';
import duplicateImg from "../assets/duplicate.svg"; import duplicateImg from "assets/duplicate.svg";
import styles from './FancyTextDisplay.module.sass'; import styles from './FancyTextDisplay.module.sass';
interface Props { interface Props {

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -5,8 +5,9 @@ const DEFUALT_LINK = "https://getmizu.io/docs"
interface LinkProps { interface LinkProps {
link?: string, link?: string,
className?: string className?: string,
title?: string title?: string,
children?: React.ReactNode
} }
export const Link: React.FC<LinkProps> = ({ link, className, title, children }) => { export const Link: React.FC<LinkProps> = ({ link, className, title, children }) => {

View File

@@ -1,5 +1,5 @@
import React from "react"; import React from "react";
import circleImg from '../assets/dotted-circle.svg'; import circleImg from 'assets/dotted-circle.svg';
import styles from './NoDataMessage.module.sass' import styles from './NoDataMessage.module.sass'
export interface Props { export interface Props {

View File

Before

Width:  |  Height:  |  Size: 180 B

After

Width:  |  Height:  |  Size: 180 B

View File

@@ -4,7 +4,7 @@ import { Autocomplete } from "@mui/material";
import { Checkbox, TextField } from "@mui/material"; import { Checkbox, TextField } from "@mui/material";
import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank'; import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank';
import CheckBoxIcon from '@mui/icons-material/CheckBox'; import CheckBoxIcon from '@mui/icons-material/CheckBox';
import DefaultIconDown from "DefaultIconDown.svg"; import DefaultIconDown from "assets/DefaultIconDown.svg";
import styles from "./SearchableDropdown.module.sass"; import styles from "./SearchableDropdown.module.sass";
interface SearchableDropdownProps { interface SearchableDropdownProps {

View File

@@ -1,4 +1,4 @@
import {ReactComponent as DefaultIconDown} from '../assets/default_icon_down.svg'; import {ReactComponent as DefaultIconDown} from './assets/defaultIconDown.svg';
import {MenuItem, Select as MUISelect, SelectProps as MUISelectProps} from '@mui/material'; import {MenuItem, Select as MUISelect, SelectProps as MUISelectProps} from '@mui/material';
import React from 'react'; import React from 'react';
import styles from './Select.module.sass'; import styles from './Select.module.sass';

View File

@@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.99999 13.6568L9.99997 13.6569L5.75732 9.41421L7.17154 8L10.0001 10.8285L12.8285 8.00009L14.2428 9.41431L10.0001 13.6569L9.99999 13.6568Z" fill="#205CF5"/>
</svg>

After

Width:  |  Height:  |  Size: 310 B

View File

@@ -1,8 +1,8 @@
import style from './StatusBar.module.sass'; import style from './StatusBar.module.sass';
import React, {useState} from "react"; import React, {useState} from "react";
import warningIcon from '../assets/warning_icon.svg'; import warningIcon from 'assets/warning_icon.svg';
import failIcon from '../assets/failed.svg'; import failIcon from 'assets/failed.svg';
import successIcon from '../assets/success.svg'; import successIcon from 'assets/success.svg';
import {useRecoilValue} from "recoil"; import {useRecoilValue} from "recoil";
import tappingStatusAtom, {tappingStatusDetails} from "../../../recoil/tappingStatus"; import tappingStatusAtom, {tappingStatusDetails} from "../../../recoil/tappingStatus";
import Tooltip from "../Tooltip/Tooltip"; import Tooltip from "../Tooltip/Tooltip";

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="7.237" height="7.237" viewBox="0 0 7.237 7.237" fill="white">
<path id="icon_down" d="M5.117 0H3.07v3.07H0v2.047h5.117V0z" transform="rotate(45 1.809 4.367)"/>
</svg>

Before

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

View File

@@ -1,5 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 22 22">
<g id="prefix__icon_expand" fill="#627ef7" transform="rotate(0 11 11)">
<path id="prefix__icon_down" d="M5.117 0H3.07v3.07H0v2.047h5.117V0z" transform="rotate(-45 16.54 -2.201)"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 292 B

View File

@@ -1,5 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 22 22">
<g id="prefix__icon_expand" fill="#627ef7" transform="rotate(180 11 11)">
<path id="prefix__icon_down" d="M5.117 0H3.07v3.07H0v2.047h5.117V0z" transform="rotate(-45 16.54 -2.201)"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 294 B

View File

@@ -1,10 +1,10 @@
import { Box, Fade, FormControl, Modal, Backdrop } from "@mui/material"; import { Box, Fade, FormControl, Modal, Backdrop } from "@mui/material";
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { RedocStandalone } from "redoc"; import { RedocStandalone } from "redoc";
import closeIcon from "./assets/closeIcon.svg"; import closeIcon from "assets/closeIcon.svg";
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import style from './OasModal.module.sass'; import style from './OasModal.module.sass';
import openApiLogo from './assets/openApiLogo.png' import openApiLogo from 'assets/openApiLogo.png'
import { redocThemeOptions } from "./redocThemeOptions"; import { redocThemeOptions } from "./redocThemeOptions";
import React from "react"; import React from "react";
import { TOAST_CONTAINER_ID } from "../../../configs/Consts"; import { TOAST_CONTAINER_ID } from "../../../configs/Consts";

View File

@@ -1,15 +1,15 @@
import React, { useState, useEffect, useCallback, useMemo } from "react"; import React, { useState, useEffect, useCallback, useMemo } from "react";
import { Box, Fade, Modal, Backdrop, Button } from "@mui/material"; import { Box, Fade, Modal, Backdrop, Button } from "@mui/material";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import spinnerImg from '../../assets/spinner.svg'; import spinnerImg from 'assets/spinner.svg';
import Graph from "react-graph-vis"; import Graph from "react-graph-vis";
import debounce from 'lodash/debounce'; import debounce from 'lodash/debounce';
import ServiceMapOptions from './ServiceMapOptions' import ServiceMapOptions from './ServiceMapOptions'
import { useCommonStyles } from "../../../helpers/commonStyle"; import { useCommonStyles } from "../../../helpers/commonStyle";
import refreshIcon from "./assets/refresh.svg"; import refreshIcon from "assets/refresh.svg";
import filterIcon from "./assets/filter-icon.svg"; import filterIcon from "assets/filter-icon.svg";
import filterIconClicked from "./assets/filter-icon-clicked.svg"; import filterIconClicked from "assets/filter-icon-clicked.svg";
import closeIcon from "./assets/close.svg" import closeIcon from "assets/close.svg"
import styles from './ServiceMapModal.module.sass' import styles from './ServiceMapModal.module.sass'
import SelectList from "../../UI/SelectList/SelectList"; import SelectList from "../../UI/SelectList/SelectList";
import { GraphData, ServiceMapGraph } from "./ServiceMapModalTypes" import { GraphData, ServiceMapGraph } from "./ServiceMapModalTypes"

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; background: none; display: block; shape-rendering: auto;" width="200px" height="200px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
<circle cx="50" cy="50" fill="none" stroke="#1d3f72" stroke-width="10" r="35" stroke-dasharray="164.93361431346415 56.97787143782138" transform="rotate(275.903 50 50)">
<animateTransform attributeName="transform" type="rotate" repeatCount="indefinite" dur="1s" values="0 50 50;360 50 50" keyTimes="0;1"></animateTransform>
</circle>
<!-- [ldio] generated by https://loading.io/ --></svg>

After

Width:  |  Height:  |  Size: 673 B

10506
ui/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -23,7 +23,7 @@
"mobx": "^6.6.0", "mobx": "^6.6.0",
"moment": "^2.29.3", "moment": "^2.29.3",
"node-fetch": "^3.2.4", "node-fetch": "^3.2.4",
"node-sass": "^6.0.1", "sass": "^1.52.3",
"numeral": "^2.0.6", "numeral": "^2.0.6",
"react": "^17.0.2", "react": "^17.0.2",
"react-copy-to-clipboard": "^5.1.0", "react-copy-to-clipboard": "^5.1.0",