Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/check-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
node-version: ['>=18.18.x']
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.12.1
uses: styfle/cancel-workflow-action@0.13.1
with:
access_token: ${{ secrets.GITHUB_TOKEN }}

Expand All @@ -28,7 +28,7 @@ jobs:
corepack enable

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v6.3.0
uses: actions/setup-node@v6.4.0
with:
node-version: ${{ matrix.node-version }}
cache: yarn
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/check-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
node-version: ['>=18.18.x']
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.12.1
uses: styfle/cancel-workflow-action@0.13.1
with:
access_token: ${{ secrets.GITHUB_TOKEN }}

Expand All @@ -26,7 +26,7 @@ jobs:
corepack enable

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v6.3.0
uses: actions/setup-node@v6.4.0
with:
node-version: ${{ matrix.node-version }}
cache: yarn
Expand All @@ -45,7 +45,7 @@ jobs:
node-version: ['>=18.18.x']
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.12.1
uses: styfle/cancel-workflow-action@0.13.1
with:
access_token: ${{ secrets.GITHUB_TOKEN }}

Expand All @@ -56,7 +56,7 @@ jobs:
corepack enable

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v6.3.0
uses: actions/setup-node@v6.4.0
with:
node-version: ${{ matrix.node-version }}
cache: yarn
Expand All @@ -71,7 +71,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.12.1
uses: styfle/cancel-workflow-action@0.13.1
with:
access_token: ${{ secrets.GITHUB_TOKEN }}

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/check-pr-title.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
corepack enable

- name: Set up Node.js environment
uses: actions/setup-node@v6.3.0
uses: actions/setup-node@v6.4.0
with:
node-version: '>=18.18.x'

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:

steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.12.1
uses: styfle/cancel-workflow-action@0.13.1
with:
access_token: ${{ github.token }}

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy-storybook-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
corepack enable

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v6.3.0
uses: actions/setup-node@v6.4.0
with:
node-version: ${{ matrix.node-version }}
cache: yarn
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-dapps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
corepack enable

- name: Setup Node.js environment
uses: actions/setup-node@v6.3.0
uses: actions/setup-node@v6.4.0
with:
node-version: '>=18.18.x'
cache: yarn
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-libs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ jobs:
corepack enable

- name: Setup Node.js environment
uses: actions/setup-node@v6.3.0
uses: actions/setup-node@v6.4.0
with:
node-version: '>=18.18.x'
cache: yarn
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:

steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.12.1
uses: styfle/cancel-workflow-action@0.13.1
with:
access_token: ${{ secrets.GITHUB_TOKEN }}

Expand All @@ -30,7 +30,7 @@ jobs:
corepack enable

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v6.3.0
uses: actions/setup-node@v6.4.0
with:
node-version: ${{ matrix.node-version }}
cache: yarn
Expand Down
156 changes: 156 additions & 0 deletions apps/tangle-cloud/src/components/blueprintApps/BlueprintHostCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import type { Blueprint } from '@tangle-network/tangle-shared-ui/types/blueprint';
import {
Card,
CardVariant,
Typography,
Button,
} from '@tangle-network/ui-components';
import { ExternalLinkLine } from '@tangle-network/icons';

const SURFACE_LABELS: Record<
NonNullable<Blueprint['blueprintUi']>['surfaces'][number],
string
> = {
'generic-overview': 'Overview',
'service-explorer': 'Service explorer',
'service-console': 'Service console',
'actions-panel': 'Actions',
resources: 'Resources',
chat: 'Chat',
vaults: 'Vaults',
metrics: 'Metrics',
permissions: 'Permissions',
};

type Props = {
blueprint: Blueprint;
serviceId?: bigint;
};

const BlueprintHostCard = ({ blueprint, serviceId }: Props) => {
if (!blueprint.blueprintUi) {
return null;
}

const { blueprintUi } = blueprint;
const publisherLabel = blueprintUi.publisher.namespace
? `@${blueprintUi.publisher.namespace}`
: blueprintUi.publisher.name;

return (
<Card variant={CardVariant.GLASS} className="p-6 space-y-5">
<div className="flex flex-col gap-4 md:flex-row md:items-start md:justify-between">
<div className="space-y-2">
<Typography variant="h5" fw="bold">
Hosted Blueprint Contract
</Typography>
<Typography variant="body1">{blueprintUi.displayName}</Typography>
<Typography variant="body2" className="text-mono-100 max-w-3xl">
{blueprintUi.description}
</Typography>
</div>

{blueprintUi.externalApp && (
<Button
variant="secondary"
onClick={() =>
window.open(
blueprintUi.externalApp?.url,
'_blank',
'noopener,noreferrer',
)
}
>
<span className="inline-flex items-center gap-2">
Open Publisher App
<ExternalLinkLine className="w-4 h-4" />
</span>
</Button>
)}
</div>

<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
<InfoBlock
label="Publisher"
value={`${publisherLabel}${blueprintUi.publisher.verified ? ' • verified' : ''}`}
/>
<InfoBlock
label="Hosted Tier"
value={
blueprintUi.tier === 'link-out'
? 'Tier 2 + link-out handoff'
: blueprintUi.tier === 'declarative'
? 'Tier 2 declarative host'
: 'Tier 1 generic host'
}
/>
<InfoBlock
label="Service Label"
value={blueprintUi.resources.serviceLabel}
/>
<InfoBlock
label="Resource Model"
value={`${blueprintUi.resources.itemLabel} • ${blueprintUi.resources.itemRoute}`}
/>
</div>

{(blueprintUi.requestedSlug || blueprintUi.canonicalSlug) && (
<div className="space-y-1">
<Typography variant="body2" className="text-mono-100">
Requested host slug
</Typography>
<Typography variant="body1" className="font-mono">
{blueprintUi.canonicalSlug ?? blueprintUi.requestedSlug}
</Typography>
</div>
)}

{blueprintUi.surfaces.length > 0 && (
<div className="space-y-2">
<Typography variant="body2" className="text-mono-100">
Shared host surfaces
</Typography>
<div className="flex flex-wrap gap-2">
{blueprintUi.surfaces.map((surface) => (
<span
key={surface}
className="rounded-full border border-mono-60 dark:border-mono-140 px-3 py-1.5 text-sm"
>
{SURFACE_LABELS[surface]}
</span>
))}
</div>
</div>
)}

{blueprintUi.externalApp && (
<div className="rounded-xl border border-yellow-500/30 bg-yellow-500/10 p-4 space-y-1">
<Typography variant="body2" fw="semibold">
Third-party app execution stays outside the shared cloud runtime
</Typography>
<Typography variant="body2" className="text-mono-100">
Tier 3 BYOdApp embedding is not enabled here. Tangle Cloud keeps the
shared host pages on-site and only hands off to publisher apps via a
new tab.
{serviceId !== undefined
? ` Service #${serviceId.toString()} remains manageable from the hosted protocol surfaces.`
: ''}
</Typography>
</div>
)}
</Card>
);
};

const InfoBlock = ({ label, value }: { label: string; value: string }) => (
<div className="space-y-1">
<Typography variant="body2" className="text-mono-100">
{label}
</Typography>
<Typography variant="body1" fw="semibold">
{value}
</Typography>
</div>
);

export default BlueprintHostCard;
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,22 @@ import { SelectOperatorsStep } from './OperatorSelectionStep';
import { RequestArgsConfigurationStep } from './RequestArgsConfigurationStep';
import { PaymentStep } from './PaymentStep';
import { RequestModeStep } from './RequestModeStep';
import {
Accordion,
AccordionButton,
AccordionContent,
AccordionItem,
Typography,
} from '@tangle-network/ui-components';

export const Deployment: FC<BaseDeployStepProps> = (props) => {
const minimumNativeSecurityRequirement = 0;
const expectedRequestArgsCount =
props.requestSchemaFieldCount ??
props.blueprint?.requestParams?.length ??
0;
const shouldShowAdvancedSummary =
expectedRequestArgsCount > 0 || props.hasRequestSchema === false;

return (
<>
Expand All @@ -16,9 +29,36 @@ export const Deployment: FC<BaseDeployStepProps> = (props) => {
{...props}
minimumNativeSecurityRequirement={minimumNativeSecurityRequirement}
/>
<RequestModeStep {...props} />
<RequestArgsConfigurationStep {...props} />
<PaymentStep {...props} />

<div className="rounded-3xl border border-mono-160/10 bg-mono-0/[0.03]">
<Accordion type="single" collapsible defaultValue={undefined}>
<AccordionItem value="advanced-config" className="p-0">
<AccordionButton className="px-6 py-4">
Advanced configuration
</AccordionButton>
<AccordionContent className="space-y-4 px-6 pb-6 pt-0">
<div className="space-y-1">
<Typography variant="body2" className="text-mono-100">
Most services only need a name, operators, and a caller. Open
this section when you need custom request args, security
commitments, or a non-default payment setup.
</Typography>
{shouldShowAdvancedSummary && (
<Typography variant="body3" className="text-mono-80">
{expectedRequestArgsCount > 0
? `This blueprint expects ${expectedRequestArgsCount} request argument${expectedRequestArgsCount === 1 ? '' : 's'}.`
: 'This blueprint has no request arguments, but its request schema could not be resolved.'}
</Typography>
)}
</div>

<RequestModeStep {...props} />
<RequestArgsConfigurationStep {...props} />
<PaymentStep {...props} />
</AccordionContent>
</AccordionItem>
</Accordion>
</div>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,12 @@ export const SelectOperatorsStep: FC<SelectOperatorsStepProps> = ({
blueprint,
blueprintOperators,
}) => {
const selectedOperators = watch('operators') ?? [];
const [rowSelection, setRowSelection] = useState<RowSelectionState>(
watch(`operators`)?.reduce((acc, operator) => {
selectedOperators.reduce((acc, operator) => {
acc[operator] = true;
return acc;
}, {} as RowSelectionState) || {},
}, {} as RowSelectionState),
);

const [searchQuery, setSearchQuery] = useState('');
Expand Down Expand Up @@ -105,6 +106,29 @@ export const SelectOperatorsStep: FC<SelectOperatorsStepProps> = ({
setValue(`operators`, Object.keys(rowSelection) as Address[]);
}, [rowSelection, setValue]);

useEffect(() => {
if (selectedOperators.length === 0) {
return;
}

const nextSelection = selectedOperators.reduce((acc, operator) => {
acc[operator] = true;
return acc;
}, {} as RowSelectionState);

const currentKeys = Object.keys(rowSelection).filter(
(key) => rowSelection[key],
);
const nextKeys = Object.keys(nextSelection);
const isSame =
currentKeys.length === nextKeys.length &&
nextKeys.every((key) => rowSelection[key]);

if (!isSame) {
setRowSelection(nextSelection);
}
}, [rowSelection, selectedOperators]);

const onSelectAsset = (asset: StakingAsset, isChecked: boolean) => {
const selectedAssets_ = Array.from(selectedAssets ?? []);
const newSelectedAssets = isChecked
Expand Down
Loading
Loading