diff --git a/.github/workflows/build-docker.yaml b/.github/workflows/build-docker.yaml new file mode 100644 index 000000000000..990aaeecb7cc --- /dev/null +++ b/.github/workflows/build-docker.yaml @@ -0,0 +1,117 @@ +name: build-docker +on: + workflow_dispatch: + +permissions: + id-token: write # allows the JWT to be requested from GitHub's OIDC provider + contents: read # This is required for actions/checkout + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + arch_amd64: amd64 + arch_arm64: arm64 + docker_images: | + name=rudderstack/profiles-code-server + docker_tags: | + type=raw,value=latest + +jobs: + metadata: + runs-on: ubuntu-latest + outputs: + labels: ${{ steps.meta.outputs.labels }} + build-date: ${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }} + version: ${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }} + revision: ${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }} + tags: ${{ steps.meta.outputs.tags }} + arm64_tags: ${{ steps.arm64_meta.outputs.tags }} + arm64_labels: ${{ steps.arm64_meta.outputs.labels }} + amd64_tags: ${{ steps.amd64_meta.outputs.tags }} + amd64_labels: ${{ steps.amd64_meta.outputs.labels }} + steps: + - name: docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.docker_images }} + tags: ${{ env.docker_tags }} + - name: docker arm64 meta + id: arm64_meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.docker_images }} + tags: ${{ env.docker_tags }} + flavor: | + suffix=-${{ env.arch_arm64 }},onlatest=true + - name: docker amd64 meta + id: amd64_meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.docker_images }} + tags: ${{ env.docker_tags }} + flavor: | + suffix=-${{ env.arch_amd64 }},onlatest=true + + build: + needs: + - metadata + strategy: + fail-fast: false + matrix: + build-config: + - os: [self-hosted, Linux, ARM64, ubuntu-22] + tags: ${{ needs.metadata.outputs.arm64_tags }} + labels: ${{ needs.metadata.outputs.arm64_labels }} + platform: linux/arm64 + - os: ubuntu-latest + tags: ${{ needs.metadata.outputs.amd64_tags }} + labels: ${{ needs.metadata.outputs.amd64_labels }} + platform: linux/amd64 + runs-on: ${{ matrix.build-config.os }} + steps: + - name: checkout + uses: actions/checkout@v4 + - name: setup buildx + uses: docker/setup-buildx-action@v3 + - name: docker login + uses: docker/login-action@v3.1.0 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: docker build + uses: rudderlabs/build-scan-push-action@v1.5.3 + with: + context: . + platforms: ${{ matrix.build-config.platform }} + push: true + tags: ${{ matrix.build-config.tags }} + labels: ${{ matrix.build-config.labels }} + build-args: | + VERSION=${{ github.ref_name }} + GITHUB_PAT=${{ secrets.PAT }} + ENTERPRISE_TOKEN=${{ secrets.ENTERPRISE_TOKEN }} + cache-from: type=gha + cache-to: type=gha,mode=max + + manifest: + runs-on: ubuntu-latest + needs: [build, metadata] + steps: + - name: setup buildx + uses: docker/setup-buildx-action@v3 + - name: docker login + uses: docker/login-action@v3.1.0 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: multi-arch manifest + run: | + while read -r tag; do + echo "$tag" + arm_tag=$(echo "${{ needs.metadata.outputs.arm64_tags }}" | grep "$tag") + amd_tag=$(echo "${{ needs.metadata.outputs.amd64_tags }}" | grep "$tag") + docker buildx imagetools create -t $tag $arm_tag $amd_tag + done <<< "${{ needs.metadata.outputs.tags }}" diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 0a243e388740..2ae82c7e8bdc 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -34,7 +34,7 @@ jobs: - name: Checkout repo uses: actions/checkout@v4 - name: Check changed files - uses: dorny/paths-filter@v3 + uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 #v3 id: filter with: filters: | @@ -103,7 +103,7 @@ jobs: - uses: actions/checkout@v4 - uses: azure/setup-helm@v4 with: - token: ${{ secrets.GITHUB_TOKEN }} + token: ${{ secrets.PAT }} - run: helm plugin install https://github.com/instrumenta/helm-kubeval - run: helm kubeval ci/helm-chart @@ -173,7 +173,7 @@ jobs: with: submodules: true - run: sudo apt update && sudo apt install -y libkrb5-dev - - uses: awalsh128/cache-apt-pkgs-action@latest + - uses: awalsh128/cache-apt-pkgs-action@4c82c3ccdc1344ee11e9775dbdbdf43aa8a5614e with: packages: quilt version: 1.0 @@ -188,7 +188,7 @@ jobs: - run: SKIP_SUBMODULE_DEPS=1 npm ci - run: npm run build env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.PAT }} # Get Code's git hash. When this changes it means the content is # different and we need to rebuild. - name: Get latest lib/vscode rev @@ -293,7 +293,7 @@ jobs: key: cache-caddy-2.5.2 - name: Install Caddy env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ secrets.PAT }} if: steps.caddy-cache.outputs.cache-hit != 'true' run: | gh release download v2.5.2 --repo caddyserver/caddy --pattern "caddy_2.5.2_linux_amd64.tar.gz" diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 91e320087175..28973ba8a031 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -49,7 +49,7 @@ jobs: - run: npm run publish:npm env: VERSION: ${{ env.VERSION }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.PAT }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} NPM_ENVIRONMENT: "production" @@ -167,7 +167,7 @@ jobs: with: registry: ghcr.io username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + password: ${{ secrets.PAT }} # Strip out the v (v4.9.1 -> 4.9.1). - name: Get and set VERSION diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d5223c0485cb..23a550e27221 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -118,7 +118,7 @@ jobs: VERSION: ${{ env.VERSION }} run: npm run package $PKG_ARCH - - uses: softprops/action-gh-release@v1 + - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 #v1 with: draft: true discussion_category_name: "📣 Announcements" @@ -130,7 +130,7 @@ jobs: timeout-minutes: 15 needs: npm-version env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.PAT }} steps: - name: Checkout repo @@ -179,7 +179,7 @@ jobs: VERSION: ${{ env.VERSION }} run: npm run package - - uses: softprops/action-gh-release@v1 + - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 #v1 with: draft: true discussion_category_name: "📣 Announcements" @@ -191,7 +191,7 @@ jobs: timeout-minutes: 15 needs: npm-version env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.PAT }} steps: - name: Checkout repo @@ -240,7 +240,7 @@ jobs: VERSION: ${{ env.VERSION }} run: npm run package - - uses: softprops/action-gh-release@v1 + - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 #v1 with: draft: true discussion_category_name: "📣 Announcements" @@ -257,7 +257,7 @@ jobs: with: name: npm-release-package - - uses: softprops/action-gh-release@v1 + - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 #v1 with: draft: true discussion_category_name: "📣 Announcements" @@ -269,7 +269,7 @@ jobs: timeout-minutes: 15 steps: - name: Download artifacts - uses: dawidd6/action-download-artifact@v10 + uses: dawidd6/action-download-artifact@4c1e823582f43b179e2cbb49c3eade4e41f992e2 #v10 id: download with: branch: ${{ github.ref }} diff --git a/.truffleignore b/.truffleignore new file mode 100644 index 000000000000..35ec3b9d7586 --- /dev/null +++ b/.truffleignore @@ -0,0 +1 @@ +/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000000..66ae56cd530a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,60 @@ +# Base image +FROM ubuntu:22.04 + +# Install Python, pip, git, curl, and wget +RUN apt-get update && \ + apt-get install -y python3.10 python3-pip git curl wget sudo && \ + apt-get clean + +# Create a non-root user +RUN useradd -m -s /bin/bash codeuser + +# Create project directory +RUN mkdir -p /home/codeuser/project + +# Create .pb directory and siteconfig.yaml file +RUN mkdir -p /home/codeuser/.pb && \ + touch /home/codeuser/.pb/siteconfig.yaml + +# Install RudderStack Profiles CLI (assuming pip install) +RUN pip3 install profiles-rudderstack + +# Install code-server (VSCode in the browser) +RUN curl -fsSL https://code-server.dev/install.sh | sh + +# Switch to codeuser for extension installation and MCP setup +USER codeuser +WORKDIR /home/codeuser + +# Install extension as codeuser +RUN code-server --install-extension saoudrizwan.claude-dev + +# Clone profiles-mcp as codeuser +RUN git clone https://github.com/rudderlabs/profiles-mcp + +# Set up the Python script +# RUN echo '#!/usr/bin/env python3' > /home/codeuser/profiles-mcp/scripts/update_mcp_config.py +# RUN echo 'RUDDERSTACK_PAT=xxxx' > /home/codeuser/profiles-mcp/.env + +# Run setup as codeuser +# RUN cd /home/codeuser/profiles-mcp && bash setup.sh + +# Create MCP settings directory and file +# RUN mkdir -p /home/codeuser/.local/share/code-server/User/globalStorage/saoudrizwan.claude-dev/settings/ +# RUN echo '{"mcpServers":{ "Profiles": { "command": "/home/codeuser/profiles-mcp/scripts/start.sh", "args": [] }}}' > /home/codeuser/.local/share/code-server/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json + +# Set proper ownership and permissions +USER root +RUN chown -R codeuser:codeuser /home/codeuser +RUN chmod 755 /home/codeuser/project +RUN chmod 644 /home/codeuser/.pb/siteconfig.yaml +RUN chmod 755 /home/codeuser/.pb + +# Switch back to codeuser +USER codeuser +WORKDIR /home/codeuser/project + +EXPOSE 8080 + +# Start code-server when container runs, opening the project directory +CMD ["code-server", "--bind-addr", "0.0.0.0:8080", "/home/codeuser/project"] \ No newline at end of file diff --git a/patches/rudderstack-plugin.diff b/patches/rudderstack-plugin.diff new file mode 100644 index 000000000000..2f51b80045e9 --- /dev/null +++ b/patches/rudderstack-plugin.diff @@ -0,0 +1,447 @@ +Index: code-server/lib/vscode/src/vs/workbench/workbench.common.main.ts +=================================================================== +--- code-server.orig/lib/vscode/src/vs/workbench/workbench.common.main.ts ++++ code-server/lib/vscode/src/vs/workbench/workbench.common.main.ts +@@ -420,5 +420,8 @@ import './contrib/dropOrPasteInto/browse + // Edit Telemetry + import './contrib/editTelemetry/browser/editTelemetry.contribution.js'; + ++// Rudderstack ++import './contrib/rudderstack/browser/rudderstack.contribution.js'; ++ + + //#endregion +Index: code-server/lib/vscode/src/vs/workbench/contrib/rudderstack/browser/media/rudderstack-icon.svg +=================================================================== +--- /dev/null ++++ code-server/lib/vscode/src/vs/workbench/contrib/rudderstack/browser/media/rudderstack-icon.svg +@@ -0,0 +1,4 @@ ++ ++ ++ ++ +Index: code-server/lib/vscode/src/vs/workbench/contrib/rudderstack/browser/rudderstack.contribution.ts +=================================================================== +--- /dev/null ++++ code-server/lib/vscode/src/vs/workbench/contrib/rudderstack/browser/rudderstack.contribution.ts +@@ -0,0 +1,39 @@ ++/* eslint-disable header/header */ ++import { ViewContainerLocation, Extensions as ViewExtensions } from '../../../common/views.js'; ++import { IViewContainersRegistry, IViewsRegistry } from '../../../common/views.js'; ++import { Registry } from '../../../../platform/registry/common/platform.js'; ++import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js'; ++import * as nls from '../../../../nls.js'; ++import { KeyMod, KeyCode } from '../../../../base/common/keyCodes.js'; ++import { rudderstackFeatureViewIcon } from './rudderstackIcons.js'; ++import { RudderstackViewPaneContainer } from './rudderstackViewlet.js'; ++import { RudderstackMainView } from './rudderstackMainView.js'; ++import { VIEWLET_ID, MAIN_VIEW_ID } from '../common/rudderstack.js'; ++ ++// Register the view container (activity bar icon) ++const viewContainer = Registry.as(ViewExtensions.ViewContainersRegistry).registerViewContainer({ ++ id: VIEWLET_ID, // Unique ID ++ title: nls.localize2('rudderstack', "Rudderstack"), // Display name ++ openCommandActionDescriptor: { ++ id: VIEWLET_ID, ++ mnemonicTitle: nls.localize({ key: 'miViewRudderstack', comment: ['&& denotes a mnemonic'] }, "&&Rudderstack"), ++ keybindings: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyX }, // Optional shortcut ++ }, ++ ctorDescriptor: new SyncDescriptor(RudderstackViewPaneContainer), // Container class ++ icon: rudderstackFeatureViewIcon, // Icon for activity bar ++ alwaysUseContainerInfo: true, ++ order: 1000, // High number to appear last ++}, ViewContainerLocation.Sidebar); ++ ++// Register views inside the container ++const viewsRegistry = Registry.as(ViewExtensions.ViewsRegistry); ++viewsRegistry.registerViews([{ ++ id: MAIN_VIEW_ID, ++ name: nls.localize2('rudderstackMainView', "Rudderstack"), ++ containerIcon: rudderstackFeatureViewIcon, ++ ctorDescriptor: new SyncDescriptor(RudderstackMainView), ++ order: 10, ++ weight: 40, ++ canToggleVisibility: true, ++ canMoveView: true ++}], viewContainer); +\ No newline at end of file +Index: code-server/lib/vscode/src/vs/workbench/contrib/rudderstack/browser/rudderstackIcons.ts +=================================================================== +--- /dev/null ++++ code-server/lib/vscode/src/vs/workbench/contrib/rudderstack/browser/rudderstackIcons.ts +@@ -0,0 +1,6 @@ ++/* eslint-disable header/header */ ++import { URI } from '../../../../base/common/uri.js'; ++import { FileAccess } from '../../../../base/common/network.js'; ++ ++// Main activity bar icon - direct URI to custom SVG ++export const rudderstackFeatureViewIcon = URI.parse(FileAccess.asBrowserUri('vs/workbench/contrib/rudderstack/browser/media/rudderstack-icon.svg').toString()); +Index: code-server/lib/vscode/src/vs/workbench/contrib/rudderstack/browser/rudderstackMainView.ts +=================================================================== +--- /dev/null ++++ code-server/lib/vscode/src/vs/workbench/contrib/rudderstack/browser/rudderstackMainView.ts +@@ -0,0 +1,307 @@ ++/* eslint-disable header/header */ ++import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js'; ++import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js'; ++import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; ++import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; ++import { IViewDescriptorService } from '../../../common/views.js'; ++import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; ++import { IOpenerService } from '../../../../platform/opener/common/opener.js'; ++import { IThemeService } from '../../../../platform/theme/common/themeService.js'; ++import { IHoverService } from '../../../../platform/hover/browser/hover.js'; ++import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js'; ++import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js'; ++import { ITerminalService, ITerminalGroupService, ITerminalEditorService } from '../../../contrib/terminal/browser/terminal.js'; ++import { TerminalLocation } from '../../../../platform/terminal/common/terminal.js'; ++import { IEditorService } from '../../../services/editor/common/editorService.js'; ++import { IFileService } from '../../../../platform/files/common/files.js'; ++import { VSBuffer } from '../../../../base/common/buffer.js'; ++import { URI } from '../../../../base/common/uri.js'; ++import { SaveReason } from '../../../common/editor.js'; ++import { ViewPane } from '../../../browser/parts/views/viewPane.js'; ++import { IViewletViewOptions } from '../../../browser/parts/views/viewsViewlet.js'; ++import { MAIN_VIEW_ID } from '../common/rudderstack.js'; ++import { Button } from '../../../../base/browser/ui/button/button.js'; ++import { defaultButtonStyles } from '../../../../platform/theme/browser/defaultStyles.js'; ++import { $, append } from '../../../../base/browser/dom.js'; ++import { Severity } from '../../../../platform/notification/common/notification.js'; ++import * as nls from '../../../../nls.js'; ++ ++export class RudderstackMainView extends ViewPane { ++ ++ static readonly ID = MAIN_VIEW_ID; ++ ++ private primaryButton: Button | undefined; ++ private runProjectButton: Button | undefined; ++ private compileProjectButton: Button | undefined; ++ ++ constructor( ++ options: IViewletViewOptions, ++ @IKeybindingService keybindingService: IKeybindingService, ++ @IContextMenuService contextMenuService: IContextMenuService, ++ @IConfigurationService configurationService: IConfigurationService, ++ @IContextKeyService contextKeyService: IContextKeyService, ++ @IViewDescriptorService viewDescriptorService: IViewDescriptorService, ++ @IInstantiationService instantiationService: IInstantiationService, ++ @IOpenerService openerService: IOpenerService, ++ @IThemeService themeService: IThemeService, ++ @IHoverService hoverService: IHoverService, ++ @IDialogService private readonly dialogService: IDialogService, ++ @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, ++ @ITerminalService private readonly terminalService: ITerminalService, ++ @ITerminalGroupService private readonly terminalGroupService: ITerminalGroupService, ++ @ITerminalEditorService private readonly terminalEditorService: ITerminalEditorService, ++ @IEditorService private readonly editorService: IEditorService, ++ @IFileService private readonly fileService: IFileService, ++ ) { ++ super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, hoverService); ++ } ++ ++ protected override renderBody(container: HTMLElement): void { ++ super.renderBody(container); ++ ++ // Clear container ++ container.innerHTML = ''; ++ ++ // Create main content container with proper spacing ++ const contentContainer = append(container, $('.rudderstack-content')); ++ contentContainer.style.padding = '20px'; ++ contentContainer.style.display = 'flex'; ++ contentContainer.style.flexDirection = 'column'; ++ contentContainer.style.gap = '16px'; ++ ++ // Title ++ const title = append(contentContainer, $('.rudderstack-title')); ++ title.style.fontSize = '14px'; ++ title.style.fontWeight = '600'; ++ title.style.color = 'var(--vscode-foreground)'; ++ title.textContent = nls.localize('rudderstackTitle', 'Rudderstack Profiles'); ++ ++ // Description ++ const description = append(contentContainer, $('.rudderstack-description')); ++ description.style.fontSize = '12px'; ++ description.style.color = 'var(--vscode-descriptionForeground)'; ++ description.style.marginBottom = '8px'; ++ description.textContent = nls.localize('rudderstackDescription', 'edit your project'); ++ ++ // Button container ++ const buttonContainer = append(contentContainer, $('.button-container')); ++ buttonContainer.style.display = 'flex'; ++ buttonContainer.style.flexDirection = 'column'; ++ buttonContainer.style.gap = '8px'; ++ ++ // Primary action button (like "Run and Debug" button) ++ this.primaryButton = this._register(new Button(buttonContainer, { ++ supportIcons: true, ++ title: nls.localize('saveAndExit', 'Save and Exit'), ++ ...defaultButtonStyles ++ })); ++ this.primaryButton.label = `$(save) ${nls.localize('saveAndExit', 'Save and Exit')}`; ++ this._register(this.primaryButton.onDidClick(async () => { ++ await this.onSaveAndExit(); ++ })); ++ ++ // Project Actions Section ++ const projectActionsTitle = append(contentContainer, $('.project-actions-title')); ++ projectActionsTitle.style.fontSize = '12px'; ++ projectActionsTitle.style.fontWeight = '600'; ++ projectActionsTitle.style.color = 'var(--vscode-foreground)'; ++ projectActionsTitle.style.marginTop = '16px'; ++ projectActionsTitle.style.marginBottom = '8px'; ++ projectActionsTitle.textContent = nls.localize('projectActions', 'Project Actions'); ++ ++ // Project buttons container ++ const projectButtonContainer = append(contentContainer, $('.project-button-container')); ++ projectButtonContainer.style.display = 'flex'; ++ projectButtonContainer.style.flexDirection = 'column'; ++ projectButtonContainer.style.gap = '8px'; ++ ++ // Run Project button ++ this.runProjectButton = this._register(new Button(projectButtonContainer, { ++ supportIcons: true, ++ secondary: true, ++ title: nls.localize('runProject', 'Run Project'), ++ ...defaultButtonStyles ++ })); ++ this.runProjectButton.label = `$(play) ${nls.localize('runProject', 'Run Project')}`; ++ this._register(this.runProjectButton.onDidClick(async () => { ++ await this.onRunProject(); ++ })); ++ ++ // Compile Project button ++ this.compileProjectButton = this._register(new Button(projectButtonContainer, { ++ supportIcons: true, ++ secondary: true, ++ title: nls.localize('compileProject', 'Compile Project'), ++ ...defaultButtonStyles ++ })); ++ this.compileProjectButton.label = `$(tools) ${nls.localize('compileProject', 'Compile Project')}`; ++ this._register(this.compileProjectButton.onDidClick(async () => { ++ await this.onCompileProject(); ++ })); ++ } ++ ++ private async getStatusFileUri(): Promise { ++ // Try to get the status file path from VS Code configuration ++ const statusFilePath = this.configurationService.getValue('rudderstack.statusFilePath'); ++ if (statusFilePath) { ++ // If it's a relative path, resolve it against the workspace ++ if (!statusFilePath.startsWith('/') && !statusFilePath.match(/^[a-zA-Z]:/)) { ++ const workspace = this.workspaceContextService.getWorkspace(); ++ if (workspace.folders && workspace.folders.length > 0) { ++ return URI.joinPath(workspace.folders[0].uri, statusFilePath); ++ } ++ } ++ // For absolute paths, try to create URI (may not work in browser context) ++ try { ++ return URI.file(statusFilePath); ++ } catch (error) { ++ console.warn('Failed to create URI from absolute path:', statusFilePath, error); ++ } ++ } ++ ++ // Fallback: Use workspace-relative path with proper URI handling ++ const workspace = this.workspaceContextService.getWorkspace(); ++ if (workspace.folders && workspace.folders.length > 0) { ++ const statusFileUri = URI.joinPath(workspace.folders[0].uri, 'rudderstack_status.json'); ++ console.log('No rudderstack.statusFilePath configured, using workspace-relative location:', statusFileUri.toString()); ++ return statusFileUri; ++ } ++ ++ console.warn('No workspace found, cannot determine status file location'); ++ return undefined; ++ } ++ ++ private async onSaveAndExit(): Promise { ++ const result = await this.dialogService.confirm({ ++ type: Severity.Warning, ++ message: nls.localize('saveAndExitConfirm', 'Save and Exit'), ++ detail: nls.localize('saveAndExitDetail', 'Are you sure you want to save all files and exit?'), ++ primaryButton: nls.localize('saveAndExit', 'Save and Exit'), ++ cancelButton: nls.localize('cancel', 'Cancel') ++ }); ++ ++ if (result.confirmed) { ++ try { ++ // Step 1: Save all files in the active folder ++ console.log('Saving all files...'); ++ const saveResult = await this.editorService.saveAll({ ++ includeUntitled: true, ++ reason: SaveReason.EXPLICIT ++ }); ++ ++ if (!saveResult.success) { ++ throw new Error('Some files could not be saved'); ++ } ++ ++ // Step 2: Write status file to configured location ++ const statusFileUri = await this.getStatusFileUri(); ++ if (statusFileUri) { ++ console.log(`Writing status file to: ${statusFileUri.toString()}`); ++ const statusData = { ++ timestamp: new Date().toISOString(), ++ action: 'save_and_exit', ++ status: 'completed', ++ savedFiles: saveResult.editors.length ++ }; ++ ++ const statusFileContent = VSBuffer.fromString(JSON.stringify(statusData, null, 2)); ++ await this.fileService.writeFile(statusFileUri, statusFileContent); ++ ++ console.log('Status file written successfully'); ++ } else { ++ console.warn('No status file path configured, skipping status file creation'); ++ } ++ ++ // Show success notification ++ this.dialogService.confirm({ ++ type: Severity.Info, ++ message: nls.localize('saveAndExitSuccess', 'Save and Exit Complete'), ++ detail: nls.localize('saveAndExitSuccessDetail', 'All files have been saved successfully.'), ++ primaryButton: nls.localize('ok', 'OK') ++ }); ++ ++ console.log('Save and exit operation completed successfully'); ++ ++ } catch (error) { ++ console.error('Save and exit operation failed:', error); ++ this.dialogService.confirm({ ++ type: Severity.Error, ++ message: nls.localize('saveAndExitError', 'Save and Exit Failed'), ++ detail: nls.localize('saveAndExitErrorDetail', 'Failed to save files or write status: {0}', error instanceof Error ? error.message : 'Unknown error'), ++ primaryButton: nls.localize('ok', 'OK') ++ }); ++ } ++ } ++ } ++ ++ private async onRunProject(): Promise { ++ try { ++ // Get or create a terminal instance ++ const terminal = await this.terminalService.getActiveOrCreateInstance(); ++ ++ // Ensure the terminal is visible based on its location ++ if (terminal.target === TerminalLocation.Editor) { ++ const existingEditors = this.editorService.findEditors(terminal.resource); ++ this.terminalEditorService.openEditor(terminal, { viewColumn: existingEditors?.[0]?.groupId }); ++ } else { ++ // Show the terminal panel ++ await this.terminalGroupService.showPanel(true); ++ } ++ ++ // Make sure the terminal is focused and ready ++ await terminal.focusWhenReady(true); ++ ++ // Execute the 'pb run' command ++ terminal.runCommand('pb run', true); ++ ++ console.log('Executing: pb run'); ++ } catch (error) { ++ console.error('Failed to run project:', error); ++ // Optionally show an error dialog ++ this.dialogService.confirm({ ++ type: Severity.Error, ++ message: nls.localize('runProjectError', 'Failed to run project'), ++ detail: nls.localize('runProjectErrorDetail', 'Could not execute "pb run" in terminal. Please check if the terminal is available.'), ++ primaryButton: nls.localize('ok', 'OK') ++ }); ++ } ++ } ++ ++ private async onCompileProject(): Promise { ++ try { ++ // Get or create a terminal instance ++ const terminal = await this.terminalService.getActiveOrCreateInstance(); ++ ++ // Ensure the terminal is visible based on its location ++ if (terminal.target === TerminalLocation.Editor) { ++ const existingEditors = this.editorService.findEditors(terminal.resource); ++ this.terminalEditorService.openEditor(terminal, { viewColumn: existingEditors?.[0]?.groupId }); ++ } else { ++ // Show the terminal panel ++ await this.terminalGroupService.showPanel(true); ++ } ++ ++ // Make sure the terminal is focused and ready ++ await terminal.focusWhenReady(true); ++ ++ // Execute the 'pb compile' command ++ terminal.runCommand('pb compile', true); ++ ++ console.log('Executing: pb compile'); ++ } catch (error) { ++ console.error('Failed to compile project:', error); ++ // Optionally show an error dialog ++ this.dialogService.confirm({ ++ type: Severity.Error, ++ message: nls.localize('compileProjectError', 'Failed to compile project'), ++ detail: nls.localize('compileProjectErrorDetail', 'Could not execute "pb compile" in terminal. Please check if the terminal is available.'), ++ primaryButton: nls.localize('ok', 'OK') ++ }); ++ } ++ } ++ ++ protected override layoutBody(height: number, width: number): void { ++ super.layoutBody(height, width); ++ // Handle any layout changes if needed ++ } ++} +\ No newline at end of file +Index: code-server/lib/vscode/src/vs/workbench/contrib/rudderstack/browser/rudderstackViewlet.ts +=================================================================== +--- /dev/null ++++ code-server/lib/vscode/src/vs/workbench/contrib/rudderstack/browser/rudderstackViewlet.ts +@@ -0,0 +1,37 @@ ++/* eslint-disable header/header */ ++import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; ++import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; ++import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js'; ++import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; ++import { IStorageService } from '../../../../platform/storage/common/storage.js'; ++import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; ++import { IThemeService } from '../../../../platform/theme/common/themeService.js'; ++import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js'; ++import { ViewPaneContainer } from '../../../browser/parts/views/viewPaneContainer.js'; ++import { IViewDescriptorService } from '../../../common/views.js'; ++import { IViewsService } from '../../../services/views/common/viewsService.js'; ++import { IExtensionService } from '../../../services/extensions/common/extensions.js'; ++import { IWorkbenchLayoutService } from '../../../services/layout/browser/layoutService.js'; ++import { ILogService } from '../../../../platform/log/common/log.js'; ++import { VIEWLET_ID } from '../common/rudderstack.js'; ++ ++export class RudderstackViewPaneContainer extends ViewPaneContainer { ++ ++ constructor( ++ @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, ++ @ITelemetryService telemetryService: ITelemetryService, ++ @IWorkspaceContextService contextService: IWorkspaceContextService, ++ @IStorageService storageService: IStorageService, ++ @IConfigurationService configurationService: IConfigurationService, ++ @IInstantiationService instantiationService: IInstantiationService, ++ @IThemeService themeService: IThemeService, ++ @IContextMenuService contextMenuService: IContextMenuService, ++ @IExtensionService extensionService: IExtensionService, ++ @IContextKeyService contextKeyService: IContextKeyService, ++ @IViewDescriptorService viewDescriptorService: IViewDescriptorService, ++ @IViewsService viewsService: IViewsService, ++ @ILogService logService: ILogService, ++ ) { ++ super(VIEWLET_ID, { mergeViewWithContainerWhenSingleView: true }, instantiationService, configurationService, layoutService, contextMenuService, telemetryService, extensionService, themeService, storageService, contextService, viewDescriptorService, logService); ++ } ++} +\ No newline at end of file +Index: code-server/lib/vscode/src/vs/workbench/contrib/rudderstack/common/rudderstack.ts +=================================================================== +--- /dev/null ++++ code-server/lib/vscode/src/vs/workbench/contrib/rudderstack/common/rudderstack.ts +@@ -0,0 +1,7 @@ ++/*--------------------------------------------------------------------------------------------- ++ * Copyright (c) Microsoft Corporation. All rights reserved. ++ * Licensed under the MIT License. See License.txt in the project root for license information. ++ *--------------------------------------------------------------------------------------------*/ ++ ++export const VIEWLET_ID = 'workbench.view.rudderstack'; ++export const MAIN_VIEW_ID = 'workbench.rudderstack.mainView'; +\ No newline at end of file diff --git a/patches/series b/patches/series index ffc15fdd9d75..3b655a24a557 100644 --- a/patches/series +++ b/patches/series @@ -22,3 +22,4 @@ clipboard.diff display-language.diff trusted-domains.diff signature-verification.diff +rudderstack-plugin.diff diff --git a/src/browser/media/favicon-dark-support.svg b/src/browser/media/favicon-dark-support.svg deleted file mode 100644 index d64bf32ed96e..000000000000 --- a/src/browser/media/favicon-dark-support.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/browser/media/favicon.ico b/src/browser/media/favicon.ico index 56078ead6697..9e3647d288ab 100644 Binary files a/src/browser/media/favicon.ico and b/src/browser/media/favicon.ico differ diff --git a/src/browser/media/favicon.svg b/src/browser/media/favicon.svg deleted file mode 100644 index 01a01541ec75..000000000000 --- a/src/browser/media/favicon.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/browser/media/pwa-icon-192.png b/src/browser/media/pwa-icon-192.png deleted file mode 100644 index 9f46dd830361..000000000000 Binary files a/src/browser/media/pwa-icon-192.png and /dev/null differ diff --git a/src/browser/media/pwa-icon-512.png b/src/browser/media/pwa-icon-512.png deleted file mode 100644 index 9b899e8d690e..000000000000 Binary files a/src/browser/media/pwa-icon-512.png and /dev/null differ diff --git a/src/browser/media/pwa-icon-maskable-192.png b/src/browser/media/pwa-icon-maskable-192.png deleted file mode 100644 index 3f28593b3aee..000000000000 Binary files a/src/browser/media/pwa-icon-maskable-192.png and /dev/null differ diff --git a/src/browser/media/pwa-icon-maskable-512.png b/src/browser/media/pwa-icon-maskable-512.png deleted file mode 100644 index 7df85f7665ac..000000000000 Binary files a/src/browser/media/pwa-icon-maskable-512.png and /dev/null differ diff --git a/src/browser/media/templates.png b/src/browser/media/templates.png deleted file mode 100644 index 1437658ec13a..000000000000 Binary files a/src/browser/media/templates.png and /dev/null differ diff --git a/src/browser/pages/login.html b/src/browser/pages/login.html index c7fb2f2ac67e..9796f0579be2 100644 --- a/src/browser/pages/login.html +++ b/src/browser/pages/login.html @@ -12,11 +12,9 @@ /> {{I18N_LOGIN_TITLE}} - + - -