@shortlink-org/portolan 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +387 -0
- package/catalog/enum_test.go +46 -0
- package/catalog/model.go +932 -0
- package/catalog/roundtrip_test.go +185 -0
- package/catalog/via_test.go +38 -0
- package/cli/portolan.mjs +368 -0
- package/go.mod +14 -0
- package/go.sum +14 -0
- package/index.html +13 -0
- package/internal/commands/cargo.go +154 -0
- package/internal/commands/commands.go +143 -0
- package/internal/commands/commands_test.go +323 -0
- package/internal/commands/gradle.go +77 -0
- package/internal/commands/justfile.go +82 -0
- package/internal/commands/makefile.go +106 -0
- package/internal/commands/maven.go +93 -0
- package/internal/commands/packagejson.go +159 -0
- package/internal/commands/pyproject.go +169 -0
- package/internal/commands/taskfile.go +101 -0
- package/internal/commands/testdata/estate/.cargo/config.toml +7 -0
- package/internal/commands/testdata/estate/Makefile +33 -0
- package/internal/commands/testdata/estate/Taskfile.yml +21 -0
- package/internal/commands/testdata/estate/build.gradle.kts +21 -0
- package/internal/commands/testdata/estate/justfile +20 -0
- package/internal/commands/testdata/estate/package.json +13 -0
- package/internal/commands/testdata/estate/pom.xml +29 -0
- package/internal/commands/testdata/estate/pyproject.toml +27 -0
- package/internal/commands/testdata/estate/xtask/src/main.rs +27 -0
- package/internal/commands/testdata/golden/commands.json +305 -0
- package/internal/gohttp/analyze.go +2500 -0
- package/internal/gohttp/endpoints.go +1067 -0
- package/internal/gohttp/roots.go +320 -0
- package/internal/gohttp/typed.go +143 -0
- package/internal/goscan/constants.go +85 -0
- package/internal/goscan/goscan_test.go +227 -0
- package/internal/goscan/names.go +52 -0
- package/internal/goscan/parse_test.go +11 -0
- package/internal/goscan/source.go +36 -0
- package/internal/goscan/tree.go +155 -0
- package/internal/goscan/types.go +99 -0
- package/internal/wsdl/ids.go +127 -0
- package/internal/wsdl/ids_test.go +21 -0
- package/internal/wsdl/model.go +62 -0
- package/internal/wsdl/parse.go +920 -0
- package/internal/wsdl/parse_test.go +133 -0
- package/package.json +117 -0
- package/plugin/describe.go +107 -0
- package/plugin/describe_test.go +114 -0
- package/plugin/protocol.go +117 -0
- package/plugin/schematest/schematest.go +126 -0
- package/plugins/README.md +1160 -0
- package/plugins/extract-adr/describe.go +19 -0
- package/plugins/extract-adr/describe_test.go +11 -0
- package/plugins/extract-adr/extract.go +153 -0
- package/plugins/extract-adr/extract_test.go +350 -0
- package/plugins/extract-adr/history.go +99 -0
- package/plugins/extract-adr/main.go +65 -0
- package/plugins/extract-adr/options.schema.json +26 -0
- package/plugins/extract-adr/parse.go +642 -0
- package/plugins/extract-adr/parse_test.go +405 -0
- package/plugins/extract-asyncapi/describe.go +19 -0
- package/plugins/extract-asyncapi/describe_test.go +11 -0
- package/plugins/extract-asyncapi/extract.go +315 -0
- package/plugins/extract-asyncapi/extract_test.go +197 -0
- package/plugins/extract-asyncapi/main.go +48 -0
- package/plugins/extract-asyncapi/options.schema.json +26 -0
- package/plugins/extract-asyncapi/spec.go +151 -0
- package/plugins/extract-celery/README.md +169 -0
- package/plugins/extract-celery/extract.py +346 -0
- package/plugins/extract-celery/extract_test.py +192 -0
- package/plugins/extract-celery/main.py +66 -0
- package/plugins/extract-celery/options.py +31 -0
- package/plugins/extract-celery/options.schema.json +31 -0
- package/plugins/extract-celery/producers.py +156 -0
- package/plugins/extract-celery/routes_test.py +106 -0
- package/plugins/extract-commands/describe.go +19 -0
- package/plugins/extract-commands/describe_test.go +11 -0
- package/plugins/extract-commands/extract.go +79 -0
- package/plugins/extract-commands/extract_test.go +92 -0
- package/plugins/extract-commands/main.go +55 -0
- package/plugins/extract-commands/options.schema.json +20 -0
- package/plugins/extract-csr/avro.go +258 -0
- package/plugins/extract-csr/describe.go +19 -0
- package/plugins/extract-csr/describe_test.go +11 -0
- package/plugins/extract-csr/extract.go +338 -0
- package/plugins/extract-csr/extract_test.go +374 -0
- package/plugins/extract-csr/jsonschema.go +343 -0
- package/plugins/extract-csr/lock.go +25 -0
- package/plugins/extract-csr/main.go +84 -0
- package/plugins/extract-csr/options.schema.json +43 -0
- package/plugins/extract-csr/subject.go +102 -0
- package/plugins/extract-django/README.md +386 -0
- package/plugins/extract-django/apps.py +100 -0
- package/plugins/extract-django/auth.py +302 -0
- package/plugins/extract-django/auth_test.py +188 -0
- package/plugins/extract-django/clients.py +121 -0
- package/plugins/extract-django/contracts.py +458 -0
- package/plugins/extract-django/database.py +119 -0
- package/plugins/extract-django/domain.py +318 -0
- package/plugins/extract-django/events.py +86 -0
- package/plugins/extract-django/extract.py +601 -0
- package/plugins/extract-django/extract_test.py +397 -0
- package/plugins/extract-django/flows.py +1278 -0
- package/plugins/extract-django/flows_test.py +338 -0
- package/plugins/extract-django/ids.py +42 -0
- package/plugins/extract-django/ids_test.py +30 -0
- package/plugins/extract-django/lifecycle.py +222 -0
- package/plugins/extract-django/lifecycle_test.py +76 -0
- package/plugins/extract-django/main.py +66 -0
- package/plugins/extract-django/openapi.py +229 -0
- package/plugins/extract-django/openapi_test.py +60 -0
- package/plugins/extract-django/operations.py +96 -0
- package/plugins/extract-django/options.py +61 -0
- package/plugins/extract-django/options.schema.json +126 -0
- package/plugins/extract-django/routing.py +214 -0
- package/plugins/extract-django/routing_test.py +198 -0
- package/plugins/extract-django/serializers.py +558 -0
- package/plugins/extract-django/store.py +434 -0
- package/plugins/extract-django/transport.py +242 -0
- package/plugins/extract-flows/describe.go +19 -0
- package/plugins/extract-flows/describe_test.go +11 -0
- package/plugins/extract-flows/extract.go +91 -0
- package/plugins/extract-flows/main.go +45 -0
- package/plugins/extract-flows/options.schema.json +16 -0
- package/plugins/extract-flows/parse.go +593 -0
- package/plugins/extract-flows/parse_test.go +204 -0
- package/plugins/extract-glossary/describe.go +19 -0
- package/plugins/extract-glossary/describe_test.go +11 -0
- package/plugins/extract-glossary/extract.go +115 -0
- package/plugins/extract-glossary/extract_test.go +220 -0
- package/plugins/extract-glossary/main.go +59 -0
- package/plugins/extract-glossary/options.schema.json +21 -0
- package/plugins/extract-glossary/parse.go +214 -0
- package/plugins/extract-glossary/parse_test.go +203 -0
- package/plugins/extract-go/aggregate.go +214 -0
- package/plugins/extract-go/client.go +409 -0
- package/plugins/extract-go/client_test.go +266 -0
- package/plugins/extract-go/describe.go +19 -0
- package/plugins/extract-go/describe_test.go +11 -0
- package/plugins/extract-go/enum.go +195 -0
- package/plugins/extract-go/enum_test.go +82 -0
- package/plugins/extract-go/event.go +99 -0
- package/plugins/extract-go/extract.go +191 -0
- package/plugins/extract-go/extract_test.go +261 -0
- package/plugins/extract-go/flow.go +1441 -0
- package/plugins/extract-go/flow_test.go +609 -0
- package/plugins/extract-go/httpclient.go +174 -0
- package/plugins/extract-go/httpclient_test.go +296 -0
- package/plugins/extract-go/ids.go +92 -0
- package/plugins/extract-go/layout.go +225 -0
- package/plugins/extract-go/layout_test.go +125 -0
- package/plugins/extract-go/lifecycle.go +324 -0
- package/plugins/extract-go/lifecycle_test.go +108 -0
- package/plugins/extract-go/main.go +79 -0
- package/plugins/extract-go/operation.go +157 -0
- package/plugins/extract-go/options.schema.json +66 -0
- package/plugins/extract-go/source.go +316 -0
- package/plugins/extract-go/transport.go +321 -0
- package/plugins/extract-go/transport_test.go +145 -0
- package/plugins/extract-go/wiring.go +434 -0
- package/plugins/extract-go-nats/describe.go +19 -0
- package/plugins/extract-go-nats/describe_test.go +11 -0
- package/plugins/extract-go-nats/extract.go +177 -0
- package/plugins/extract-go-nats/extract_test.go +389 -0
- package/plugins/extract-go-nats/index.go +379 -0
- package/plugins/extract-go-nats/main.go +42 -0
- package/plugins/extract-go-nats/options.schema.json +21 -0
- package/plugins/extract-go-nats/resolve.go +161 -0
- package/plugins/extract-go-nats/sites.go +224 -0
- package/plugins/extract-graphql/describe.go +19 -0
- package/plugins/extract-graphql/describe_test.go +11 -0
- package/plugins/extract-graphql/extract.go +433 -0
- package/plugins/extract-graphql/extract_test.go +256 -0
- package/plugins/extract-graphql/ids.go +49 -0
- package/plugins/extract-graphql/lex.go +237 -0
- package/plugins/extract-graphql/main.go +51 -0
- package/plugins/extract-graphql/options.schema.json +31 -0
- package/plugins/extract-graphql/parse.go +621 -0
- package/plugins/extract-graphql/parse_test.go +122 -0
- package/plugins/extract-http-clients/describe.go +19 -0
- package/plugins/extract-http-clients/describe_test.go +11 -0
- package/plugins/extract-http-clients/extract.go +705 -0
- package/plugins/extract-http-clients/extract_test.go +1263 -0
- package/plugins/extract-http-clients/main.go +42 -0
- package/plugins/extract-http-clients/options.schema.json +33 -0
- package/plugins/extract-java/README.md +190 -0
- package/plugins/extract-java/build/org/portolan/extract/Catalog.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients$1.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients$2.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients$Call.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients$Client.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients$Route.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Domain$Aggregate.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Domain.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Events$Found.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Events.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Extract.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows$1.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows$Binding.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows$Draft.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows$Frame.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows$Options.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Ids.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Json$Reader.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Json.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Lifecycle$1.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Lifecycle$Move.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Lifecycle.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Main.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/OpenApi$Operation.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/OpenApi$Spec.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/OpenApi.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Operations$1.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Operations$UseCase.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Operations.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Proto$Rpc.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Proto$Service.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Proto.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Protocol$Builder.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Protocol$Input.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Protocol$Options.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Protocol.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Source$Project.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Source$Unit.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Source.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Transport$Endpoint.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Transport.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Yaml$Line.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Yaml$Reader.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Yaml.class +0 -0
- package/plugins/extract-java/options.schema.json +70 -0
- package/plugins/extract-openapi/describe.go +19 -0
- package/plugins/extract-openapi/describe_test.go +11 -0
- package/plugins/extract-openapi/discover.go +243 -0
- package/plugins/extract-openapi/extract.go +526 -0
- package/plugins/extract-openapi/extract_test.go +545 -0
- package/plugins/extract-openapi/main.go +75 -0
- package/plugins/extract-openapi/options.schema.json +62 -0
- package/plugins/extract-openapi/spec.go +350 -0
- package/plugins/extract-project/README.md +22 -0
- package/plugins/extract-project/describe.go +19 -0
- package/plugins/extract-project/describe_test.go +11 -0
- package/plugins/extract-project/extract.go +221 -0
- package/plugins/extract-project/extract_test.go +109 -0
- package/plugins/extract-project/main.go +41 -0
- package/plugins/extract-project/options.schema.json +48 -0
- package/plugins/extract-proto/ast.go +125 -0
- package/plugins/extract-proto/consumes.go +77 -0
- package/plugins/extract-proto/describe.go +19 -0
- package/plugins/extract-proto/extract.go +293 -0
- package/plugins/extract-proto/extract_test.go +459 -0
- package/plugins/extract-proto/ids.go +89 -0
- package/plugins/extract-proto/ids_test.go +57 -0
- package/plugins/extract-proto/lex.go +285 -0
- package/plugins/extract-proto/main.go +100 -0
- package/plugins/extract-proto/module.go +120 -0
- package/plugins/extract-proto/options.schema.json +51 -0
- package/plugins/extract-proto/parse.go +720 -0
- package/plugins/extract-proto/parse_test.go +307 -0
- package/plugins/extract-proto/provides.go +236 -0
- package/plugins/extract-proto/resolve.go +222 -0
- package/plugins/extract-proto/resolve_test.go +119 -0
- package/plugins/extract-python-kafka/README.md +36 -0
- package/plugins/extract-python-kafka/extract.py +211 -0
- package/plugins/extract-python-kafka/extract_test.py +68 -0
- package/plugins/extract-python-kafka/main.py +59 -0
- package/plugins/extract-python-kafka/options.py +29 -0
- package/plugins/extract-python-kafka/options.schema.json +31 -0
- package/plugins/extract-redis/README.md +11 -0
- package/plugins/extract-redis/describe.go +19 -0
- package/plugins/extract-redis/describe_test.go +11 -0
- package/plugins/extract-redis/extract.go +183 -0
- package/plugins/extract-redis/extract_test.go +168 -0
- package/plugins/extract-redis/keyspaces.go +469 -0
- package/plugins/extract-redis/main.go +44 -0
- package/plugins/extract-redis/options.schema.json +30 -0
- package/plugins/extract-river/describe.go +19 -0
- package/plugins/extract-river/describe_test.go +11 -0
- package/plugins/extract-river/extract.go +507 -0
- package/plugins/extract-river/extract_test.go +132 -0
- package/plugins/extract-river/main.go +42 -0
- package/plugins/extract-river/options.schema.json +21 -0
- package/plugins/extract-rust/Cargo.lock +133 -0
- package/plugins/extract-rust/Cargo.toml +23 -0
- package/plugins/extract-rust/README.md +204 -0
- package/plugins/extract-rust/options.schema.json +65 -0
- package/plugins/extract-rust/rustfmt.toml +1 -0
- package/plugins/extract-sql/ddl.go +893 -0
- package/plugins/extract-sql/ddl_test.go +401 -0
- package/plugins/extract-sql/describe.go +19 -0
- package/plugins/extract-sql/describe_test.go +11 -0
- package/plugins/extract-sql/layout.go +221 -0
- package/plugins/extract-sql/layout_test.go +55 -0
- package/plugins/extract-sql/lineage.go +107 -0
- package/plugins/extract-sql/main.go +141 -0
- package/plugins/extract-sql/maps.go +564 -0
- package/plugins/extract-sql/maps_java.go +117 -0
- package/plugins/extract-sql/maps_rust.go +333 -0
- package/plugins/extract-sql/maps_rust_test.go +70 -0
- package/plugins/extract-sql/maps_test.go +204 -0
- package/plugins/extract-sql/maps_ts.go +398 -0
- package/plugins/extract-sql/maps_ts_test.go +136 -0
- package/plugins/extract-sql/options.schema.json +53 -0
- package/plugins/extract-sql/projection.go +70 -0
- package/plugins/extract-sql/projection_test.go +50 -0
- package/plugins/extract-sql/store.go +420 -0
- package/plugins/extract-sql/store_test.go +233 -0
- package/plugins/extract-sql/view.go +295 -0
- package/plugins/extract-ts/README.md +306 -0
- package/plugins/extract-ts/ast.test.ts +178 -0
- package/plugins/extract-ts/ast.ts +648 -0
- package/plugins/extract-ts/clients.ts +185 -0
- package/plugins/extract-ts/domain.ts +164 -0
- package/plugins/extract-ts/extract.test.ts +208 -0
- package/plugins/extract-ts/extract.ts +200 -0
- package/plugins/extract-ts/flows.ts +783 -0
- package/plugins/extract-ts/graphql.test.ts +73 -0
- package/plugins/extract-ts/graphql.ts +181 -0
- package/plugins/extract-ts/ids.test.ts +21 -0
- package/plugins/extract-ts/ids.ts +52 -0
- package/plugins/extract-ts/lifecycle.ts +138 -0
- package/plugins/extract-ts/main.ts +48 -0
- package/plugins/extract-ts/openapi.test.ts +64 -0
- package/plugins/extract-ts/openapi.ts +99 -0
- package/plugins/extract-ts/operations.ts +93 -0
- package/plugins/extract-ts/options.schema.json +96 -0
- package/plugins/extract-ts/source.test.ts +174 -0
- package/plugins/extract-ts/source.ts +465 -0
- package/plugins/extract-ts/transport.ts +147 -0
- package/plugins/extract-ts/tsconfig.json +13 -0
- package/plugins/extract-ts/wiring.ts +190 -0
- package/plugins/extract-watermill/describe.go +19 -0
- package/plugins/extract-watermill/describe_test.go +11 -0
- package/plugins/extract-watermill/extract.go +1228 -0
- package/plugins/extract-watermill/extract_test.go +234 -0
- package/plugins/extract-watermill/main.go +41 -0
- package/plugins/extract-watermill/options.schema.json +21 -0
- package/plugins/extract-wsdl/describe.go +19 -0
- package/plugins/extract-wsdl/describe_test.go +11 -0
- package/plugins/extract-wsdl/extract.go +148 -0
- package/plugins/extract-wsdl/extract_test.go +45 -0
- package/plugins/extract-wsdl/main.go +53 -0
- package/plugins/extract-wsdl/options.schema.json +59 -0
- package/plugins/fetch-bsr/auth.go +114 -0
- package/plugins/fetch-bsr/bsr.go +240 -0
- package/plugins/fetch-bsr/cache.go +66 -0
- package/plugins/fetch-bsr/describe.go +19 -0
- package/plugins/fetch-bsr/fetch.go +192 -0
- package/plugins/fetch-bsr/fetch_test.go +465 -0
- package/plugins/fetch-bsr/lock.go +71 -0
- package/plugins/fetch-bsr/main.go +117 -0
- package/plugins/fetch-bsr/options.schema.json +42 -0
- package/plugins/fetch-csr/auth.go +95 -0
- package/plugins/fetch-csr/cache.go +69 -0
- package/plugins/fetch-csr/describe.go +19 -0
- package/plugins/fetch-csr/describe_test.go +11 -0
- package/plugins/fetch-csr/fetch.go +254 -0
- package/plugins/fetch-csr/fetch_test.go +494 -0
- package/plugins/fetch-csr/lock.go +95 -0
- package/plugins/fetch-csr/main.go +122 -0
- package/plugins/fetch-csr/options.schema.json +42 -0
- package/plugins/fetch-csr/registry.go +209 -0
- package/plugins/fetch-git/cache.go +65 -0
- package/plugins/fetch-git/describe.go +19 -0
- package/plugins/fetch-git/describe_test.go +11 -0
- package/plugins/fetch-git/fetch.go +181 -0
- package/plugins/fetch-git/fetch_test.go +332 -0
- package/plugins/fetch-git/git.go +169 -0
- package/plugins/fetch-git/lock.go +72 -0
- package/plugins/fetch-git/main.go +127 -0
- package/plugins/fetch-git/offline.go +39 -0
- package/plugins/fetch-git/options.schema.json +42 -0
- package/plugins/fetch-git/pin.go +90 -0
- package/plugins/fetch-git/pin_test.go +74 -0
- package/plugins/gen-backstage/describe.go +17 -0
- package/plugins/gen-backstage/main.go +22 -0
- package/plugins/gen-backstage/options.schema.json +30 -0
- package/plugins/gen-backstage/plugin.go +473 -0
- package/plugins/gen-backstage/plugin_test.go +145 -0
- package/plugins/gen-backstage.wasm +0 -0
- package/plugins/gen-markdown/adr.go +162 -0
- package/plugins/gen-markdown/aggregate.go +362 -0
- package/plugins/gen-markdown/canonical.go +93 -0
- package/plugins/gen-markdown/context.go +90 -0
- package/plugins/gen-markdown/coverage_test.go +89 -0
- package/plugins/gen-markdown/describe.go +19 -0
- package/plugins/gen-markdown/describe_test.go +11 -0
- package/plugins/gen-markdown/external.go +71 -0
- package/plugins/gen-markdown/flow.go +277 -0
- package/plugins/gen-markdown/glossary.go +76 -0
- package/plugins/gen-markdown/glossary_test.go +148 -0
- package/plugins/gen-markdown/llms.go +302 -0
- package/plugins/gen-markdown/main.go +22 -0
- package/plugins/gen-markdown/markdown.go +254 -0
- package/plugins/gen-markdown/markdown_test.go +100 -0
- package/plugins/gen-markdown/module.go +107 -0
- package/plugins/gen-markdown/options.schema.json +16 -0
- package/plugins/gen-markdown/plugin.go +39 -0
- package/plugins/gen-markdown/quality_test.go +176 -0
- package/plugins/gen-markdown/redis_test.go +38 -0
- package/plugins/gen-markdown/render.go +344 -0
- package/plugins/gen-markdown/render_test.go +186 -0
- package/plugins/gen-markdown/service.go +456 -0
- package/plugins/gen-markdown/source.go +177 -0
- package/plugins/gen-markdown/store.go +201 -0
- package/plugins/gen-markdown.wasm +0 -0
- package/plugins/gen-mermaid/describe.go +17 -0
- package/plugins/gen-mermaid/main.go +22 -0
- package/plugins/gen-mermaid/options.schema.json +10 -0
- package/plugins/gen-mermaid/plugin.go +104 -0
- package/plugins/gen-mermaid/plugin_test.go +33 -0
- package/plugins/gen-mermaid.wasm +0 -0
- package/plugins/openapi/ids.go +261 -0
- package/plugins/openapi/ids_test.go +98 -0
- package/plugins/pyplugin/catalog.py +209 -0
- package/plugins/pyplugin/celery_conf.py +436 -0
- package/plugins/pyplugin/celery_tasks.py +76 -0
- package/plugins/pyplugin/kafka.py +570 -0
- package/plugins/pyplugin/names.py +38 -0
- package/plugins/pyplugin/protocol.py +79 -0
- package/plugins/pyplugin/source.py +285 -0
- package/plugins/verify-codeowners/describe.go +19 -0
- package/plugins/verify-codeowners/describe_test.go +11 -0
- package/plugins/verify-codeowners/main.go +75 -0
- package/plugins/verify-codeowners/match.go +85 -0
- package/plugins/verify-codeowners/match_test.go +47 -0
- package/plugins/verify-codeowners/options.schema.json +15 -0
- package/plugins/verify-codeowners/owners.go +164 -0
- package/plugins/verify-codeowners/owners_test.go +225 -0
- package/plugins/verify-codeowners/parse.go +90 -0
- package/plugins/verify-codeowners/parse_test.go +62 -0
- package/plugins/verify-otel/describe.go +19 -0
- package/plugins/verify-otel/describe_test.go +11 -0
- package/plugins/verify-otel/main.go +53 -0
- package/plugins/verify-otel/match.go +336 -0
- package/plugins/verify-otel/options.schema.json +30 -0
- package/plugins/verify-otel/otlp.go +200 -0
- package/plugins/verify-otel/verify.go +734 -0
- package/plugins/verify-otel/verify_test.go +460 -0
- package/portolan.json +1073 -0
- package/public/favicon.svg +12 -0
- package/schema/portolan.schema.json +2558 -0
- package/scripts/README.md +53 -0
- package/scripts/build-report.mjs +60 -0
- package/scripts/build-report.test.mjs +44 -0
- package/scripts/builtin-plugins.mjs +49 -0
- package/scripts/catalog-sources.mjs +67 -0
- package/scripts/diff.mjs +315 -0
- package/scripts/diff.test.mjs +151 -0
- package/scripts/forge-comment.mjs +144 -0
- package/scripts/forge-comment.test.mjs +151 -0
- package/scripts/forge-release.mjs +138 -0
- package/scripts/forge-release.test.mjs +106 -0
- package/scripts/forge.mjs +61 -0
- package/scripts/gen-likec4.mjs +854 -0
- package/scripts/gen-likec4.test.mjs +258 -0
- package/scripts/gen.mjs +603 -0
- package/scripts/generated-docs.test.mjs +66 -0
- package/scripts/local-api.mjs +1192 -0
- package/scripts/local-api.test.mjs +387 -0
- package/scripts/manifest.mjs +214 -0
- package/scripts/manifest.test.mjs +148 -0
- package/scripts/output-path.mjs +79 -0
- package/scripts/output-path.test.mjs +45 -0
- package/scripts/package-smoke.mjs +37 -0
- package/scripts/plugin-host.mjs +419 -0
- package/scripts/plugin-host.test.mjs +109 -0
- package/scripts/plugin-wasm-worker.mjs +34 -0
- package/scripts/run-builtin.mjs +81 -0
- package/scripts/schema.mjs +357 -0
- package/scripts/site-docs.mjs +295 -0
- package/scripts/site-docs.test.mjs +181 -0
- package/scripts/vendor-lock.mjs +58 -0
- package/scripts/vendor-lock.test.mjs +69 -0
- package/src/README.md +38 -0
- package/src/app/App.tsx +448 -0
- package/src/app/BranchPicker.test.ts +46 -0
- package/src/app/BranchPicker.tsx +153 -0
- package/src/app/Breadcrumbs.test.ts +38 -0
- package/src/app/Breadcrumbs.tsx +223 -0
- package/src/app/BuildStamp.tsx +146 -0
- package/src/app/CommandPalette.tsx +292 -0
- package/src/app/HashScroll.tsx +45 -0
- package/src/app/Sidebar.tsx +1742 -0
- package/src/app/TopBar.tsx +393 -0
- package/src/app/density.tsx +64 -0
- package/src/app/forge-access.test.ts +27 -0
- package/src/app/forge-access.tsx +80 -0
- package/src/app/panels.tsx +141 -0
- package/src/app/pins.tsx +242 -0
- package/src/app/query-client.ts +24 -0
- package/src/app/responsive.ts +55 -0
- package/src/app/shortcuts.test.ts +39 -0
- package/src/app/shortcuts.tsx +282 -0
- package/src/app/theme.tsx +51 -0
- package/src/app/title.test.ts +14 -0
- package/src/app/title.ts +30 -0
- package/src/app/toast.tsx +59 -0
- package/src/app/tree-keys.test.ts +80 -0
- package/src/app/tree-keys.ts +87 -0
- package/src/app/ui-store.ts +52 -0
- package/src/catalog-error.test.ts +105 -0
- package/src/catalog-profile.test.ts +59 -0
- package/src/catalog-profile.ts +101 -0
- package/src/catalog-stores.test.ts +431 -0
- package/src/catalog.test.ts +1215 -0
- package/src/catalog.ts +3125 -0
- package/src/chat/Cards.tsx +408 -0
- package/src/chat/ChatPanel.tsx +79 -0
- package/src/chat/ChatSettings.tsx +219 -0
- package/src/chat/Composer.tsx +99 -0
- package/src/chat/Conversation.tsx +281 -0
- package/src/chat/Header.tsx +46 -0
- package/src/chat/Message.tsx +49 -0
- package/src/chat/Notice.tsx +195 -0
- package/src/chat/Starter.tsx +67 -0
- package/src/chat/Steps.tsx +45 -0
- package/src/chat/Waiting.tsx +87 -0
- package/src/chat/flags.test.ts +59 -0
- package/src/chat/flags.ts +155 -0
- package/src/chat/linkify.test.ts +30 -0
- package/src/chat/linkify.ts +45 -0
- package/src/chat/prefs.ts +56 -0
- package/src/chat/prompt.test.ts +43 -0
- package/src/chat/prompt.ts +157 -0
- package/src/chat/store.ts +35 -0
- package/src/chat/tools.ts +58 -0
- package/src/chat/transport.ts +70 -0
- package/src/components/AdrRow.tsx +29 -0
- package/src/components/AnchorLink.tsx +67 -0
- package/src/components/ApiReference.tsx +134 -0
- package/src/components/AsyncApiReference.tsx +120 -0
- package/src/components/CatalogStamp.tsx +155 -0
- package/src/components/ChannelRows.tsx +132 -0
- package/src/components/CommandRows.tsx +139 -0
- package/src/components/DiagramSkeleton.tsx +71 -0
- package/src/components/EditorLink.tsx +85 -0
- package/src/components/FieldTree.tsx +305 -0
- package/src/components/FlowTrigger.tsx +34 -0
- package/src/components/Ident.tsx +89 -0
- package/src/components/Integrations.tsx +243 -0
- package/src/components/LifecycleDiagram.tsx +110 -0
- package/src/components/MachineDocs.tsx +42 -0
- package/src/components/Markdown.tsx +173 -0
- package/src/components/MarkdownTable.tsx +206 -0
- package/src/components/Mermaid.tsx +211 -0
- package/src/components/MethodRows.tsx +309 -0
- package/src/components/Overlay.tsx +125 -0
- package/src/components/PageHeader.tsx +189 -0
- package/src/components/RowActions.tsx +97 -0
- package/src/components/SchemaDocument.tsx +89 -0
- package/src/components/Select.tsx +126 -0
- package/src/components/ShapeRows.tsx +118 -0
- package/src/components/SourceDoc.tsx +82 -0
- package/src/components/SourcePreview.tsx +441 -0
- package/src/components/TabRow.tsx +182 -0
- package/src/components/TechIcon.tsx +34 -0
- package/src/components/Toc.tsx +132 -0
- package/src/components/WhatLinksHere.tsx +273 -0
- package/src/components/WsdlReference.tsx +84 -0
- package/src/components/ddd-icons.tsx +107 -0
- package/src/components/kind.tsx +157 -0
- package/src/components/logo.tsx +61 -0
- package/src/components/primitives.tsx +264 -0
- package/src/data.test.ts +18 -0
- package/src/data.ts +202 -0
- package/src/enrich.test.ts +1150 -0
- package/src/enrich.ts +672 -0
- package/src/er/ErCanvas.tsx +533 -0
- package/src/er/RedisSchema.tsx +74 -0
- package/src/er/RelationCard.tsx +267 -0
- package/src/er/StoreHeader.tsx +155 -0
- package/src/er/TableNode.tsx +84 -0
- package/src/er/ViewNode.tsx +83 -0
- package/src/er/layout.test.ts +115 -0
- package/src/er/layout.ts +77 -0
- package/src/er/lineage.test.ts +140 -0
- package/src/er/lineage.ts +107 -0
- package/src/er/markers.tsx +79 -0
- package/src/er/spec.test.ts +344 -0
- package/src/er/spec.ts +426 -0
- package/src/flow/ChainList.tsx +162 -0
- package/src/flow/FlowTable.tsx +123 -0
- package/src/flow/FlowToolbar.tsx +372 -0
- package/src/flow/StepDetail.tsx +380 -0
- package/src/flow/StepRail.tsx +428 -0
- package/src/flow/answers.test.ts +50 -0
- package/src/flow/answers.ts +58 -0
- package/src/flow/chain.test.ts +383 -0
- package/src/flow/chain.ts +353 -0
- package/src/flow/chapters.test.ts +185 -0
- package/src/flow/chapters.ts +225 -0
- package/src/flow/continues.test.ts +102 -0
- package/src/flow/continues.ts +65 -0
- package/src/flow/cross-context.test.ts +97 -0
- package/src/flow/cross-context.ts +35 -0
- package/src/flow/mermaid.test.ts +22 -0
- package/src/flow/mermaid.ts +141 -0
- package/src/flow/outline.test.ts +212 -0
- package/src/flow/outline.ts +170 -0
- package/src/flow/paths.test.ts +129 -0
- package/src/flow/paths.ts +147 -0
- package/src/flow/prefs.test.ts +80 -0
- package/src/flow/prefs.ts +104 -0
- package/src/graph/DependencyGraph.tsx +283 -0
- package/src/graph/DependencyNodes.tsx +162 -0
- package/src/graph/EdgeLabel.tsx +61 -0
- package/src/graph/FocusedEventGraph.tsx +211 -0
- package/src/graph/GraphToolbar.tsx +187 -0
- package/src/graph/RoutedEdge.tsx +80 -0
- package/src/graph/dependency-layout.test.ts +360 -0
- package/src/graph/dependency-layout.ts +444 -0
- package/src/graph/elk.test.ts +70 -0
- package/src/graph/elk.ts +287 -0
- package/src/graph/nodes.tsx +97 -0
- package/src/graph/theme.ts +81 -0
- package/src/graph/useElkFlow.ts +125 -0
- package/src/index.css +1547 -0
- package/src/language/InLanguage.tsx +40 -0
- package/src/language/TermCard.tsx +132 -0
- package/src/language/cards.test.ts +114 -0
- package/src/language/cards.ts +111 -0
- package/src/lib/admonition.test.ts +49 -0
- package/src/lib/admonition.ts +48 -0
- package/src/lib/adr.test.ts +131 -0
- package/src/lib/adr.ts +68 -0
- package/src/lib/api.test.ts +122 -0
- package/src/lib/api.ts +135 -0
- package/src/lib/backlinks.test.ts +330 -0
- package/src/lib/backlinks.ts +567 -0
- package/src/lib/branch-compare.ts +16 -0
- package/src/lib/build-info.test.ts +76 -0
- package/src/lib/build-info.ts +80 -0
- package/src/lib/catalog-diff.test.ts +275 -0
- package/src/lib/catalog-diff.ts +655 -0
- package/src/lib/clipboard.ts +43 -0
- package/src/lib/comparison-memory.test.ts +40 -0
- package/src/lib/comparison-memory.ts +39 -0
- package/src/lib/context-color.ts +27 -0
- package/src/lib/context-map.test.ts +148 -0
- package/src/lib/context-map.ts +399 -0
- package/src/lib/data-model.test.ts +245 -0
- package/src/lib/data-model.ts +399 -0
- package/src/lib/data-problems.test.ts +178 -0
- package/src/lib/data-problems.ts +314 -0
- package/src/lib/derive.test.ts +251 -0
- package/src/lib/derive.ts +515 -0
- package/src/lib/editor-link.test.ts +125 -0
- package/src/lib/editor-link.ts +96 -0
- package/src/lib/editor-prefs.ts +27 -0
- package/src/lib/event-graph.test.ts +237 -0
- package/src/lib/event-graph.ts +327 -0
- package/src/lib/export-canvas.ts +37 -0
- package/src/lib/export-file.test.ts +30 -0
- package/src/lib/export-file.ts +20 -0
- package/src/lib/flow-tree.test.ts +177 -0
- package/src/lib/flow-tree.ts +160 -0
- package/src/lib/forge-refs.test.ts +50 -0
- package/src/lib/forge-refs.ts +60 -0
- package/src/lib/format.test.ts +35 -0
- package/src/lib/format.ts +64 -0
- package/src/lib/github-catalog.test.ts +301 -0
- package/src/lib/github-catalog.ts +610 -0
- package/src/lib/integrations.test.ts +119 -0
- package/src/lib/integrations.ts +133 -0
- package/src/lib/kinds.test.ts +91 -0
- package/src/lib/kinds.ts +204 -0
- package/src/lib/lifecycle.test.ts +93 -0
- package/src/lib/lifecycle.ts +165 -0
- package/src/lib/local-api.ts +194 -0
- package/src/lib/motion-features.ts +11 -0
- package/src/lib/motion.test.ts +120 -0
- package/src/lib/motion.tsx +269 -0
- package/src/lib/palette-recent.test.ts +80 -0
- package/src/lib/palette-recent.ts +90 -0
- package/src/lib/palette.test.ts +365 -0
- package/src/lib/palette.ts +593 -0
- package/src/lib/pins.test.ts +139 -0
- package/src/lib/pins.ts +130 -0
- package/src/lib/problems.test.ts +112 -0
- package/src/lib/project-preview.ts +5 -0
- package/src/lib/proto-problems.test.ts +121 -0
- package/src/lib/proto-problems.ts +65 -0
- package/src/lib/queries.test.ts +113 -0
- package/src/lib/queries.ts +131 -0
- package/src/lib/registry.test.ts +219 -0
- package/src/lib/registry.ts +208 -0
- package/src/lib/scenarios.ts +547 -0
- package/src/lib/setup-info.test.ts +199 -0
- package/src/lib/setup-info.ts +415 -0
- package/src/lib/shape.test.ts +289 -0
- package/src/lib/shape.ts +454 -0
- package/src/lib/sidebar-prefs.test.ts +32 -0
- package/src/lib/sidebar-prefs.ts +75 -0
- package/src/lib/source-code.test.ts +159 -0
- package/src/lib/source-code.ts +286 -0
- package/src/lib/source-doc.test.ts +131 -0
- package/src/lib/source-doc.ts +103 -0
- package/src/lib/source-highlight.test.ts +29 -0
- package/src/lib/source-highlight.ts +24 -0
- package/src/lib/source-link.test.ts +153 -0
- package/src/lib/source-link.ts +201 -0
- package/src/lib/spec-files.test.ts +24 -0
- package/src/lib/spec-files.ts +23 -0
- package/src/lib/table-directive.test.ts +139 -0
- package/src/lib/table-directive.ts +106 -0
- package/src/lib/tech.test.ts +120 -0
- package/src/lib/tech.ts +421 -0
- package/src/lib/terms.test.ts +67 -0
- package/src/lib/terms.ts +179 -0
- package/src/lib/wire-problems.test.ts +263 -0
- package/src/lib/wire-problems.ts +281 -0
- package/src/likec4/C4View.tsx +55 -0
- package/src/likec4/CanvasBridge.tsx +187 -0
- package/src/likec4/FlowView.tsx +235 -0
- package/src/likec4/InteractiveView.tsx +144 -0
- package/src/likec4/canvas-viewport.test.ts +149 -0
- package/src/likec4/canvas-viewport.ts +135 -0
- package/src/likec4/flow-edges.test.ts +51 -0
- package/src/likec4/flow-edges.ts +89 -0
- package/src/likec4/frame-theme.test.ts +76 -0
- package/src/likec4/frame-theme.ts +101 -0
- package/src/likec4/highlight-css.test.ts +49 -0
- package/src/likec4/highlight-css.ts +52 -0
- package/src/likec4/ids.test.ts +151 -0
- package/src/likec4/ids.ts +115 -0
- package/src/likec4/levels.tsx +70 -0
- package/src/likec4/mapping.test.ts +66 -0
- package/src/likec4/mapping.ts +54 -0
- package/src/likec4/reserved.json +141 -0
- package/src/likec4/view-index.ts +78 -0
- package/src/main.tsx +13 -0
- package/src/map/ContextMapGraph.tsx +274 -0
- package/src/map/ContextNode.tsx +70 -0
- package/src/map/FloatingEdge.tsx +86 -0
- package/src/merge.test.ts +1038 -0
- package/src/merge.ts +1004 -0
- package/src/pages/AdrDetail.tsx +242 -0
- package/src/pages/AdrIndex.tsx +114 -0
- package/src/pages/AggregatePage.tsx +727 -0
- package/src/pages/BlockPage.tsx +478 -0
- package/src/pages/CatalogFailure.tsx +111 -0
- package/src/pages/Changes.tsx +313 -0
- package/src/pages/ContextMap.tsx +534 -0
- package/src/pages/ContextPage.tsx +346 -0
- package/src/pages/EnumPage.tsx +282 -0
- package/src/pages/EventPage.tsx +686 -0
- package/src/pages/ExternalPage.tsx +204 -0
- package/src/pages/FlowDetail.tsx +663 -0
- package/src/pages/FlowIndex.tsx +303 -0
- package/src/pages/GraphPage.tsx +217 -0
- package/src/pages/Language.tsx +257 -0
- package/src/pages/ModulePage.tsx +366 -0
- package/src/pages/NotFound.tsx +54 -0
- package/src/pages/Overview.tsx +344 -0
- package/src/pages/Problems.tsx +360 -0
- package/src/pages/RegistryIndex.tsx +118 -0
- package/src/pages/ServicePage.tsx +746 -0
- package/src/pages/Settings.tsx +975 -0
- package/src/pages/StorePage.tsx +114 -0
- package/src/peek/PeekCard.test.ts +35 -0
- package/src/peek/PeekCard.tsx +118 -0
- package/src/peek/PeekLayer.tsx +147 -0
- package/src/peek/model.test.ts +156 -0
- package/src/peek/model.ts +253 -0
- package/src/routes.test.ts +222 -0
- package/src/routes.ts +449 -0
- package/src/selection/DetailPanel.tsx +1407 -0
- package/src/selection/hash.test.ts +73 -0
- package/src/selection/hash.ts +58 -0
- package/src/selection/model.test.ts +199 -0
- package/src/selection/model.ts +473 -0
- package/src/selection/pages.test.ts +115 -0
- package/src/selection/pages.ts +268 -0
- package/src/selection/store.test.ts +62 -0
- package/src/selection/store.ts +46 -0
- package/src/selection/sync.tsx +99 -0
- package/src/table/ColumnsMenu.tsx +72 -0
- package/src/table/DataTable.tsx +780 -0
- package/src/table/Facets.tsx +54 -0
- package/src/table/GroupMenu.tsx +69 -0
- package/src/table/Toolbar.tsx +190 -0
- package/src/table/cells.tsx +117 -0
- package/src/table/compare.test.ts +117 -0
- package/src/table/compare.ts +196 -0
- package/src/table/export.test.ts +88 -0
- package/src/table/export.ts +66 -0
- package/src/table/facet-groups.test.ts +74 -0
- package/src/table/facet-groups.ts +56 -0
- package/src/table/grouping.test.ts +84 -0
- package/src/table/grouping.ts +82 -0
- package/src/table/infer.test.ts +57 -0
- package/src/table/infer.ts +50 -0
- package/src/table/persist.test.ts +76 -0
- package/src/table/persist.ts +112 -0
- package/src/table/sort-url.test.ts +75 -0
- package/src/table/sort-url.ts +52 -0
- package/src/table/types.ts +80 -0
- package/src/table/useTableState.ts +220 -0
- package/src/test-catalog.ts +7 -0
- package/src/testing/estate/data__catalog.json +2847 -0
- package/src/testing/estate/data__flows.json +1724 -0
- package/src/testing/estate/examples__auth__portolan__api.json +212 -0
- package/src/testing/estate/examples__auth__portolan__domain.json +1204 -0
- package/src/testing/estate/examples__auth__portolan__glossary.json +226 -0
- package/src/testing/estate/examples__auth__portolan__observed.json +757 -0
- package/src/testing/estate/examples__auth__portolan__stores.json +195 -0
- package/src/testing/estate/examples__shop__cart__portolan__api.json +234 -0
- package/src/testing/estate/examples__shop__cart__portolan__commands.json +86 -0
- package/src/testing/estate/examples__shop__cart__portolan__domain.json +966 -0
- package/src/testing/estate/examples__shop__cart__portolan__observed.json +498 -0
- package/src/testing/estate/examples__shop__cart__portolan__stores.json +208 -0
- package/src/testing/estate/examples__shop__oms__portolan__glossary.json +98 -0
- package/src/testing/estate/examples__shop__oms__portolan__proto.json +186 -0
- package/src/testing/estate.ts +49 -0
- package/src/trail/Trail.tsx +81 -0
- package/src/trail/model.test.ts +157 -0
- package/src/trail/model.ts +189 -0
- package/src/trail/record.tsx +32 -0
- package/src/trail/store.test.ts +66 -0
- package/src/trail/store.ts +102 -0
- package/tsconfig.json +35 -0
- package/vite.config.ts +171 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
import { Link } from "react-router";
|
|
2
|
+
import { Popover, PopoverButton, PopoverPanel } from "@headlessui/react";
|
|
3
|
+
import {
|
|
4
|
+
Keyboard,
|
|
5
|
+
Layers3,
|
|
6
|
+
Map,
|
|
7
|
+
Menu,
|
|
8
|
+
MessageSquare,
|
|
9
|
+
MoreHorizontal,
|
|
10
|
+
Moon,
|
|
11
|
+
Network,
|
|
12
|
+
Rows2,
|
|
13
|
+
Rows4,
|
|
14
|
+
Search,
|
|
15
|
+
Settings2,
|
|
16
|
+
Sun,
|
|
17
|
+
} from "lucide-react";
|
|
18
|
+
import type { LucideIcon } from "lucide-react";
|
|
19
|
+
import { Breadcrumbs } from "./Breadcrumbs";
|
|
20
|
+
import { BranchPicker } from "./BranchPicker";
|
|
21
|
+
import { BuildStamp } from "./BuildStamp";
|
|
22
|
+
import { useDensity } from "./density";
|
|
23
|
+
import { usePhone } from "./responsive";
|
|
24
|
+
import { useTheme } from "./theme";
|
|
25
|
+
import { useChatAvailable } from "../chat/prefs";
|
|
26
|
+
import { useChatUi } from "../chat/store";
|
|
27
|
+
import { paths } from "../routes";
|
|
28
|
+
import { activeCatalogProfile, catalogProfiles } from "../data";
|
|
29
|
+
|
|
30
|
+
export function TopBar({
|
|
31
|
+
onOpenPalette,
|
|
32
|
+
onOpenHelp,
|
|
33
|
+
onToggleSidebar,
|
|
34
|
+
narrow = false,
|
|
35
|
+
}: {
|
|
36
|
+
onOpenPalette: () => void;
|
|
37
|
+
onOpenHelp: () => void;
|
|
38
|
+
onToggleSidebar: () => void;
|
|
39
|
+
/** Below the narrow breakpoint the tree is a drawer, opened from here. */
|
|
40
|
+
narrow?: boolean;
|
|
41
|
+
}) {
|
|
42
|
+
const phone = usePhone();
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
/* One row while there is room for one, and rows when there is not: the
|
|
46
|
+
shell degrades to a drawer at the narrow breakpoint, but the bar's own
|
|
47
|
+
contents have a width of their own and run out before that. Wrapping is
|
|
48
|
+
what keeps every control reachable - hiding them would take the theme
|
|
49
|
+
and the shortcuts sheet away from exactly the window that has the least
|
|
50
|
+
room to do without them.
|
|
51
|
+
|
|
52
|
+
The controls wrap as CONTROLS, not as a block. Held together in one box
|
|
53
|
+
they wrapped as one - a first row carrying nothing but the drawer and
|
|
54
|
+
the word `portolan`, and the search sixty pixels below it beside a
|
|
55
|
+
third of a row of white. Flat, each one takes the space left on the row
|
|
56
|
+
above it, and the bar is two rows where it used to be three. The
|
|
57
|
+
breadcrumbs keep the left with `mr-auto`; every line is justified to
|
|
58
|
+
the end, so a control that does drop to the next row drops to the right
|
|
59
|
+
edge rather than under the crumbs.
|
|
60
|
+
|
|
61
|
+
On a phone wrapping is no longer the lesser evil: the bar wrapped to
|
|
62
|
+
three rows of chrome above a page that had few enough of its own, and
|
|
63
|
+
chrome that tall is not "reachable", it is in the way. So below the
|
|
64
|
+
phone breakpoint the bar keeps one row and folds instead - the search
|
|
65
|
+
box to its icon, the whole-estate views and the two settings into an
|
|
66
|
+
overflow menu, the build stamp into a popover. What stays on the row is
|
|
67
|
+
what a reader steers with: the drawer, where they are, and search. */
|
|
68
|
+
<header
|
|
69
|
+
className={`flex min-h-12 shrink-0 items-center border-b py-1 px-gutter border-line bg-canvas ${
|
|
70
|
+
phone ? "gap-x-2" : "flex-wrap justify-end gap-x-3 gap-y-2"
|
|
71
|
+
}`}
|
|
72
|
+
>
|
|
73
|
+
{narrow ? (
|
|
74
|
+
<button
|
|
75
|
+
type="button"
|
|
76
|
+
onClick={onToggleSidebar}
|
|
77
|
+
aria-label="Open the catalog"
|
|
78
|
+
aria-keyshortcuts="["
|
|
79
|
+
title="Catalog — ["
|
|
80
|
+
className="-ml-2 flex size-8 shrink-0 items-center justify-center rounded-control text-muted t-micro transition-colors hover:bg-surface hover:text-ink"
|
|
81
|
+
>
|
|
82
|
+
<Menu size={16} aria-hidden />
|
|
83
|
+
</button>
|
|
84
|
+
) : null}
|
|
85
|
+
|
|
86
|
+
{/* The one thing on the row that may be squeezed: a breadcrumb trail
|
|
87
|
+
truncates, a control does not. */}
|
|
88
|
+
<div className="mr-auto min-w-0">
|
|
89
|
+
<Breadcrumbs />
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
{/* On the phone the controls stay one box that never wraps: three rows
|
|
93
|
+
of chrome above a short page is worse than a search box folded to
|
|
94
|
+
its icon. */}
|
|
95
|
+
<div
|
|
96
|
+
className={
|
|
97
|
+
phone
|
|
98
|
+
? "ml-auto flex shrink-0 items-center justify-end gap-1"
|
|
99
|
+
: "contents"
|
|
100
|
+
}
|
|
101
|
+
>
|
|
102
|
+
<CatalogPicker compact={phone} />
|
|
103
|
+
<BranchPicker compact={phone} />
|
|
104
|
+
|
|
105
|
+
{/* Opens the palette rather than filtering in place: the sidebar box
|
|
106
|
+
narrows the tree, this one searches the whole catalog. */}
|
|
107
|
+
{phone ? (
|
|
108
|
+
<button
|
|
109
|
+
type="button"
|
|
110
|
+
onClick={onOpenPalette}
|
|
111
|
+
aria-label="Search catalog"
|
|
112
|
+
aria-keyshortcuts="Meta+K Control+K"
|
|
113
|
+
title="Search catalog"
|
|
114
|
+
className="flex size-8 shrink-0 items-center justify-center rounded-control border border-line text-muted t-micro transition-colors hover:bg-surface hover:border-line-strong hover:text-ink"
|
|
115
|
+
>
|
|
116
|
+
<Search size={16} aria-hidden />
|
|
117
|
+
</button>
|
|
118
|
+
) : (
|
|
119
|
+
<button
|
|
120
|
+
type="button"
|
|
121
|
+
onClick={onOpenPalette}
|
|
122
|
+
aria-label="Search catalog"
|
|
123
|
+
aria-keyshortcuts="Meta+K Control+K"
|
|
124
|
+
className="mono flex w-56 items-center gap-2 rounded-control border px-2 py-1.5 border-line text-muted t-micro transition-colors hover:bg-surface hover:border-line-strong"
|
|
125
|
+
>
|
|
126
|
+
<Search size={16} aria-hidden className="shrink-0" />
|
|
127
|
+
search
|
|
128
|
+
<span className="ml-auto rounded-[4px] border px-1 border-line">
|
|
129
|
+
⌘K
|
|
130
|
+
</span>
|
|
131
|
+
</button>
|
|
132
|
+
)}
|
|
133
|
+
|
|
134
|
+
{phone ? (
|
|
135
|
+
<OverflowMenu onOpenHelp={onOpenHelp} />
|
|
136
|
+
) : (
|
|
137
|
+
/* One border around the set, hairlines between them: four controls,
|
|
138
|
+
one object. */
|
|
139
|
+
<Wide onOpenHelp={onOpenHelp} />
|
|
140
|
+
)}
|
|
141
|
+
|
|
142
|
+
<BuildStamp compact={phone} />
|
|
143
|
+
</div>
|
|
144
|
+
</header>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function CatalogPicker({ compact }: { compact: boolean }) {
|
|
149
|
+
if (catalogProfiles.length < 2) return null;
|
|
150
|
+
|
|
151
|
+
const change = (id: string) => {
|
|
152
|
+
if (id === activeCatalogProfile.id) return;
|
|
153
|
+
const next = new URL(import.meta.env.BASE_URL, window.location.origin);
|
|
154
|
+
next.searchParams.set("catalog", id);
|
|
155
|
+
window.location.assign(next);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
return (
|
|
159
|
+
<label
|
|
160
|
+
className="mono flex shrink-0 items-center gap-1.5 rounded-control border border-line px-2 py-1.5 text-muted hover:border-line-strong hover:text-ink"
|
|
161
|
+
title="Catalog profile"
|
|
162
|
+
>
|
|
163
|
+
<Layers3 size={16} aria-hidden className="shrink-0" />
|
|
164
|
+
<span className="sr-only">Catalog</span>
|
|
165
|
+
<select
|
|
166
|
+
aria-label="Catalog profile"
|
|
167
|
+
value={activeCatalogProfile.id}
|
|
168
|
+
onChange={(event) => change(event.target.value)}
|
|
169
|
+
className={`bg-transparent text-ink outline-none ${compact ? "max-w-20" : "max-w-36"}`}
|
|
170
|
+
>
|
|
171
|
+
{catalogProfiles.map((profile) => (
|
|
172
|
+
<option key={profile.id} value={profile.id}>
|
|
173
|
+
{profile.title}
|
|
174
|
+
</option>
|
|
175
|
+
))}
|
|
176
|
+
</select>
|
|
177
|
+
</label>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function Wide({ onOpenHelp }: { onOpenHelp: () => void }) {
|
|
182
|
+
const { theme, toggle } = useTheme();
|
|
183
|
+
const { density, toggle: toggleDensity } = useDensity();
|
|
184
|
+
const compact = density === "compact";
|
|
185
|
+
const chat = useChatAvailable();
|
|
186
|
+
const openChat = () => useChatUi.getState().setOpen(true);
|
|
187
|
+
|
|
188
|
+
return (
|
|
189
|
+
<div className="seg">
|
|
190
|
+
{/* The two whole-estate views, side by side: the map is the domains
|
|
191
|
+
and what stands between them, the graph is the services and what
|
|
192
|
+
runs between them. */}
|
|
193
|
+
<Link
|
|
194
|
+
to="/map"
|
|
195
|
+
className="flex items-center gap-1.5"
|
|
196
|
+
aria-keyshortcuts="g m"
|
|
197
|
+
title="Context map — g m"
|
|
198
|
+
>
|
|
199
|
+
<Map size={16} aria-hidden />
|
|
200
|
+
map
|
|
201
|
+
</Link>
|
|
202
|
+
<Link
|
|
203
|
+
to="/graph"
|
|
204
|
+
className="flex items-center gap-1.5"
|
|
205
|
+
title="Dependency graph"
|
|
206
|
+
>
|
|
207
|
+
<Network size={16} aria-hidden />
|
|
208
|
+
graph
|
|
209
|
+
</Link>
|
|
210
|
+
{/* A question to the catalog, when something is set to answer it. */}
|
|
211
|
+
{chat ? (
|
|
212
|
+
<button
|
|
213
|
+
type="button"
|
|
214
|
+
onClick={openChat}
|
|
215
|
+
className="flex items-center gap-1.5"
|
|
216
|
+
title="Ask the catalog"
|
|
217
|
+
>
|
|
218
|
+
<MessageSquare size={16} aria-hidden />
|
|
219
|
+
ask
|
|
220
|
+
</button>
|
|
221
|
+
) : null}
|
|
222
|
+
{/* Density is a property of the whole app, so it lives beside the
|
|
223
|
+
theme: both are "how portolan is set", not "what is on screen". */}
|
|
224
|
+
<button
|
|
225
|
+
type="button"
|
|
226
|
+
onClick={toggleDensity}
|
|
227
|
+
aria-pressed={compact}
|
|
228
|
+
aria-label={
|
|
229
|
+
compact ? "Switch to comfortable rows" : "Switch to compact rows"
|
|
230
|
+
}
|
|
231
|
+
title={compact ? "Comfortable rows" : "Compact rows"}
|
|
232
|
+
className="flex items-center"
|
|
233
|
+
>
|
|
234
|
+
{compact ? (
|
|
235
|
+
<Rows2 size={16} aria-hidden />
|
|
236
|
+
) : (
|
|
237
|
+
<Rows4 size={16} aria-hidden />
|
|
238
|
+
)}
|
|
239
|
+
</button>
|
|
240
|
+
<button
|
|
241
|
+
type="button"
|
|
242
|
+
onClick={onOpenHelp}
|
|
243
|
+
aria-label="Keyboard shortcuts"
|
|
244
|
+
aria-keyshortcuts="?"
|
|
245
|
+
title="Keyboard shortcuts — ?"
|
|
246
|
+
className="flex items-center"
|
|
247
|
+
>
|
|
248
|
+
<Keyboard size={16} aria-hidden />
|
|
249
|
+
</button>
|
|
250
|
+
<button
|
|
251
|
+
type="button"
|
|
252
|
+
onClick={toggle}
|
|
253
|
+
aria-label={
|
|
254
|
+
theme === "dark" ? "Switch to light theme" : "Switch to dark theme"
|
|
255
|
+
}
|
|
256
|
+
className="flex items-center"
|
|
257
|
+
>
|
|
258
|
+
{theme === "dark" ? (
|
|
259
|
+
<Sun size={16} aria-hidden />
|
|
260
|
+
) : (
|
|
261
|
+
<Moon size={16} aria-hidden />
|
|
262
|
+
)}
|
|
263
|
+
</button>
|
|
264
|
+
{/* The page the three controls above are the shortcuts to: what this
|
|
265
|
+
catalog was built from, and where the same two preferences are set
|
|
266
|
+
in words. Last, because it is the only one that navigates. */}
|
|
267
|
+
<Link
|
|
268
|
+
to={paths.settings()}
|
|
269
|
+
aria-label="Settings"
|
|
270
|
+
title="Settings — projects, plugins and appearance"
|
|
271
|
+
className="flex items-center"
|
|
272
|
+
>
|
|
273
|
+
<Settings2 size={16} aria-hidden />
|
|
274
|
+
</Link>
|
|
275
|
+
</div>
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const ROW =
|
|
280
|
+
"mono flex w-full items-center gap-2 rounded-control px-2 py-2 text-left text-muted transition-colors hover:bg-surface hover:text-ink";
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Everything the wide bar puts on the row and a phone has no room for. It is a
|
|
284
|
+
* menu rather than a smaller segmented control because at this width the
|
|
285
|
+
* controls had shed their labels first, and five unlabelled icons in a strip is
|
|
286
|
+
* a puzzle - the menu buys the labels back with the space it saves.
|
|
287
|
+
*/
|
|
288
|
+
function OverflowMenu({ onOpenHelp }: { onOpenHelp: () => void }) {
|
|
289
|
+
const { theme, toggle } = useTheme();
|
|
290
|
+
const { density, toggle: toggleDensity } = useDensity();
|
|
291
|
+
const compact = density === "compact";
|
|
292
|
+
const chat = useChatAvailable();
|
|
293
|
+
|
|
294
|
+
return (
|
|
295
|
+
<Popover className="shrink-0">
|
|
296
|
+
<PopoverButton
|
|
297
|
+
aria-label="More"
|
|
298
|
+
title="More"
|
|
299
|
+
className={({ open }) =>
|
|
300
|
+
`flex size-8 items-center justify-center rounded-control border t-micro transition-colors border-line hover:bg-surface ${
|
|
301
|
+
open ? "text-accent" : "text-muted hover:text-ink"
|
|
302
|
+
}`
|
|
303
|
+
}
|
|
304
|
+
>
|
|
305
|
+
<MoreHorizontal size={16} aria-hidden />
|
|
306
|
+
</PopoverButton>
|
|
307
|
+
<PopoverPanel
|
|
308
|
+
anchor={{ to: "bottom end", gap: 4, padding: 8 }}
|
|
309
|
+
className="palette-in z-50 w-56 rounded-control border bg-canvas p-1 border-line-strong shadow-md focus:outline-none"
|
|
310
|
+
>
|
|
311
|
+
{({ close }) => (
|
|
312
|
+
<>
|
|
313
|
+
<div className="label mt-1 mb-1 px-2">the whole estate</div>
|
|
314
|
+
<Link to="/map" onClick={() => close()} className={ROW}>
|
|
315
|
+
<Map size={16} aria-hidden className="shrink-0" />
|
|
316
|
+
context map
|
|
317
|
+
</Link>
|
|
318
|
+
<Link to="/graph" onClick={() => close()} className={ROW}>
|
|
319
|
+
<Network size={16} aria-hidden className="shrink-0" />
|
|
320
|
+
dependency graph
|
|
321
|
+
</Link>
|
|
322
|
+
{chat ? (
|
|
323
|
+
<MenuButton
|
|
324
|
+
icon={MessageSquare}
|
|
325
|
+
onClick={() => {
|
|
326
|
+
useChatUi.getState().setOpen(true);
|
|
327
|
+
close();
|
|
328
|
+
}}
|
|
329
|
+
>
|
|
330
|
+
ask the catalog
|
|
331
|
+
</MenuButton>
|
|
332
|
+
) : null}
|
|
333
|
+
|
|
334
|
+
<div className="label mt-2 mb-1 px-2">how portolan is set</div>
|
|
335
|
+
<MenuButton
|
|
336
|
+
icon={compact ? Rows2 : Rows4}
|
|
337
|
+
onClick={() => {
|
|
338
|
+
toggleDensity();
|
|
339
|
+
close();
|
|
340
|
+
}}
|
|
341
|
+
>
|
|
342
|
+
{compact ? "comfortable rows" : "compact rows"}
|
|
343
|
+
</MenuButton>
|
|
344
|
+
<MenuButton
|
|
345
|
+
icon={theme === "dark" ? Sun : Moon}
|
|
346
|
+
onClick={() => {
|
|
347
|
+
toggle();
|
|
348
|
+
close();
|
|
349
|
+
}}
|
|
350
|
+
>
|
|
351
|
+
{theme === "dark" ? "light theme" : "dark theme"}
|
|
352
|
+
</MenuButton>
|
|
353
|
+
<MenuButton
|
|
354
|
+
icon={Keyboard}
|
|
355
|
+
onClick={() => {
|
|
356
|
+
onOpenHelp();
|
|
357
|
+
close();
|
|
358
|
+
}}
|
|
359
|
+
>
|
|
360
|
+
keyboard shortcuts
|
|
361
|
+
</MenuButton>
|
|
362
|
+
<Link
|
|
363
|
+
to={paths.settings()}
|
|
364
|
+
onClick={() => close()}
|
|
365
|
+
className={ROW}
|
|
366
|
+
>
|
|
367
|
+
<Settings2 size={16} aria-hidden className="shrink-0" />
|
|
368
|
+
settings
|
|
369
|
+
</Link>
|
|
370
|
+
</>
|
|
371
|
+
)}
|
|
372
|
+
</PopoverPanel>
|
|
373
|
+
</Popover>
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/** A row of the menu that does something rather than going somewhere. */
|
|
378
|
+
function MenuButton({
|
|
379
|
+
icon: Icon,
|
|
380
|
+
onClick,
|
|
381
|
+
children,
|
|
382
|
+
}: {
|
|
383
|
+
icon: LucideIcon;
|
|
384
|
+
onClick: () => void;
|
|
385
|
+
children: React.ReactNode;
|
|
386
|
+
}) {
|
|
387
|
+
return (
|
|
388
|
+
<button type="button" onClick={onClick} className={ROW}>
|
|
389
|
+
<Icon size={16} aria-hidden className="shrink-0" />
|
|
390
|
+
{children}
|
|
391
|
+
</button>
|
|
392
|
+
);
|
|
393
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Density, globally.
|
|
2
|
+
//
|
|
3
|
+
// Two settings, not a slider: comfortable is the default and compact is what a
|
|
4
|
+
// reader switches to when they are scanning a hundred rows rather than reading
|
|
5
|
+
// ten. It is written to <html data-density> rather than threaded through props,
|
|
6
|
+
// because everything that responds to it responds in CSS - a row height and a
|
|
7
|
+
// meta type size, both tokens - and nothing needs to re-render to obey.
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
createContext,
|
|
11
|
+
useCallback,
|
|
12
|
+
useContext,
|
|
13
|
+
useEffect,
|
|
14
|
+
useMemo,
|
|
15
|
+
useState,
|
|
16
|
+
} from "react";
|
|
17
|
+
import type { ReactNode } from "react";
|
|
18
|
+
|
|
19
|
+
export type Density = "comfortable" | "compact";
|
|
20
|
+
|
|
21
|
+
interface DensityCtx {
|
|
22
|
+
density: Density;
|
|
23
|
+
toggle: () => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const Ctx = createContext<DensityCtx>({
|
|
27
|
+
density: "comfortable",
|
|
28
|
+
toggle: () => {},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const KEY = "portolan.density";
|
|
32
|
+
|
|
33
|
+
function initial(): Density {
|
|
34
|
+
try {
|
|
35
|
+
return localStorage.getItem(KEY) === "compact" ? "compact" : "comfortable";
|
|
36
|
+
} catch {
|
|
37
|
+
/* private mode: this session still toggles, it just does not persist */
|
|
38
|
+
return "comfortable";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function DensityProvider({ children }: { children: ReactNode }) {
|
|
43
|
+
const [density, setDensity] = useState<Density>(initial);
|
|
44
|
+
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
document.documentElement.dataset["density"] = density;
|
|
47
|
+
try {
|
|
48
|
+
localStorage.setItem(KEY, density);
|
|
49
|
+
} catch {
|
|
50
|
+
/* see above */
|
|
51
|
+
}
|
|
52
|
+
}, [density]);
|
|
53
|
+
|
|
54
|
+
const toggle = useCallback(
|
|
55
|
+
() => setDensity((d) => (d === "compact" ? "comfortable" : "compact")),
|
|
56
|
+
[],
|
|
57
|
+
);
|
|
58
|
+
const value = useMemo(() => ({ density, toggle }), [density, toggle]);
|
|
59
|
+
return <Ctx.Provider value={value}>{children}</Ctx.Provider>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function useDensity(): DensityCtx {
|
|
63
|
+
return useContext(Ctx);
|
|
64
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { forgeCredentialScope } from "./forge-access";
|
|
3
|
+
|
|
4
|
+
describe("forgeCredentialScope", () => {
|
|
5
|
+
it("shares a token across repositories on one forge origin", () => {
|
|
6
|
+
expect(
|
|
7
|
+
forgeCredentialScope({
|
|
8
|
+
provider: "github",
|
|
9
|
+
owner: "acme",
|
|
10
|
+
repo: "shop",
|
|
11
|
+
webUrl: "https://github.com/acme/shop",
|
|
12
|
+
}),
|
|
13
|
+
).toBe("https://github.com");
|
|
14
|
+
expect(forgeCredentialScope("https://github.com/acme/payments")).toBe(
|
|
15
|
+
"https://github.com",
|
|
16
|
+
);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("keeps self-hosted forges in separate credential scopes", () => {
|
|
20
|
+
expect(forgeCredentialScope("https://gitlab.one.test/acme/shop")).toBe(
|
|
21
|
+
"https://gitlab.one.test",
|
|
22
|
+
);
|
|
23
|
+
expect(forgeCredentialScope("https://gitlab.two.test/acme/shop")).toBe(
|
|
24
|
+
"https://gitlab.two.test",
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
useCallback,
|
|
4
|
+
useContext,
|
|
5
|
+
useMemo,
|
|
6
|
+
useState,
|
|
7
|
+
} from "react";
|
|
8
|
+
import type { ReactNode } from "react";
|
|
9
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
10
|
+
import type { ForgeRepo } from "../lib/github-catalog";
|
|
11
|
+
import { forgeKeys, sourceKeys } from "../lib/queries";
|
|
12
|
+
|
|
13
|
+
interface ForgeAccessState {
|
|
14
|
+
tokenFor: (repo: ForgeRepo | string) => string;
|
|
15
|
+
connectedTo: (repo: ForgeRepo | string) => boolean;
|
|
16
|
+
connect: (repo: ForgeRepo | string, token: string) => void;
|
|
17
|
+
disconnect: (repo: ForgeRepo | string) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const Context = createContext<ForgeAccessState | null>(null);
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Repository credentials deliberately live only in React memory. They never
|
|
24
|
+
* enter a URL, Web Storage, Cache Storage, build output, or the comparison
|
|
25
|
+
* memory that remembers branch names.
|
|
26
|
+
*/
|
|
27
|
+
export function ForgeAccessProvider({ children }: { children: ReactNode }) {
|
|
28
|
+
const [tokens, setTokens] = useState<Readonly<Record<string, string>>>({});
|
|
29
|
+
const queryClient = useQueryClient();
|
|
30
|
+
// A token change makes every forge answer somebody else's. Dropping the
|
|
31
|
+
// queries, not just marking them stale, also drops the old token's keys.
|
|
32
|
+
const clearRuntimeCaches = useCallback(() => {
|
|
33
|
+
queryClient.removeQueries({ queryKey: forgeKeys.all });
|
|
34
|
+
queryClient.removeQueries({ queryKey: sourceKeys.all });
|
|
35
|
+
}, [queryClient]);
|
|
36
|
+
const connect = useCallback((repo: ForgeRepo | string, token: string) => {
|
|
37
|
+
const scope = forgeCredentialScope(repo);
|
|
38
|
+
const next = token.trim();
|
|
39
|
+
if (!scope || !next) return;
|
|
40
|
+
clearRuntimeCaches();
|
|
41
|
+
setTokens((current) => ({ ...current, [scope]: next }));
|
|
42
|
+
}, [clearRuntimeCaches]);
|
|
43
|
+
const disconnect = useCallback((repo: ForgeRepo | string) => {
|
|
44
|
+
const scope = forgeCredentialScope(repo);
|
|
45
|
+
clearRuntimeCaches();
|
|
46
|
+
setTokens((current) => {
|
|
47
|
+
if (!scope || !(scope in current)) return current;
|
|
48
|
+
const next = { ...current };
|
|
49
|
+
delete next[scope];
|
|
50
|
+
return next;
|
|
51
|
+
});
|
|
52
|
+
}, [clearRuntimeCaches]);
|
|
53
|
+
const value = useMemo<ForgeAccessState>(
|
|
54
|
+
() => ({
|
|
55
|
+
tokenFor: (repo) => tokens[forgeCredentialScope(repo)] ?? "",
|
|
56
|
+
connectedTo: (repo) => Boolean(tokens[forgeCredentialScope(repo)]),
|
|
57
|
+
connect,
|
|
58
|
+
disconnect,
|
|
59
|
+
}),
|
|
60
|
+
[connect, disconnect, tokens],
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
return <Context.Provider value={value}>{children}</Context.Provider>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function useForgeAccess(): ForgeAccessState {
|
|
67
|
+
const value = useContext(Context);
|
|
68
|
+
if (!value) throw new Error("useForgeAccess must be used inside ForgeAccessProvider");
|
|
69
|
+
return value;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Tokens are shared by repositories on one forge host, but never across hosts. */
|
|
73
|
+
export function forgeCredentialScope(repo: ForgeRepo | string): string {
|
|
74
|
+
const value = typeof repo === "string" ? repo : repo.webUrl;
|
|
75
|
+
try {
|
|
76
|
+
return new URL(value).origin.toLowerCase();
|
|
77
|
+
} catch {
|
|
78
|
+
return value.trim().replace(/\/$/, "").toLowerCase();
|
|
79
|
+
}
|
|
80
|
+
}
|