Skip to content

Conversation

Dshuishui
Copy link

No description provided.

@Copilot Copilot AI review requested due to automatic review settings September 26, 2025 13:12
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This change modifies the createPoster function in the ProjectPoster component to return a web URL instead of a File object. The function now saves the generated poster file to cloud storage and returns the accessible web URL.

  • Changed return type from Promise<File> to Promise<string>
  • Added cloud file saving functionality using saveFileForWebUrl
  • Integrated file conversion using fromNativeFile

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Copy link

Summary of Changes

Hello @Dshuishui, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request refactors the createPoster functionality within the ProjectPoster component to enhance its utility for sharing. Instead of returning a raw file, the function now processes the generated poster image, uploads it to cloud storage, and provides a direct web URL. This change simplifies the subsequent steps for users who wish to share or embed the project poster online, ensuring a more streamlined and web-friendly output.

Highlights

  • Function Signature Update: The createPoster function in ProjectPoster.vue has been updated to return a Promise<string> instead of a Promise<File>, indicating it now provides a web URL.
  • Cloud Storage Integration: The poster generation process now includes saving the generated image to cloud storage and retrieving its public web URL using saveFileForWebUrl.
  • File Type Conversion: A new utility fromNativeFile is utilized to convert the locally generated File object into a projectFile format suitable for cloud operations.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the createPoster function to return a web URL as a string instead of a File object, which aligns with the goal of providing a shareable link for the generated poster. The implementation is functionally correct. I've provided a couple of suggestions to refactor the code for better clarity and conciseness by using an existing utility function, which will simplify the logic and remove an unnecessary intermediate variable.

import { getProjectPageRoute } from '@/router'
import QRCode from 'qrcode'
import { saveFileForWebUrl } from '@/models/common/cloud'
import { fromNativeFile } from '@/models/common/file'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To simplify the implementation in createPoster, it's better to import fromBlob directly instead of fromNativeFile. This will allow you to create the custom File object from the blob without an intermediate step.

import { fromBlob } from '@/models/common/file'

Comment on lines 229 to 233
const nativeFile = new File([blob], `${props.projectData.name}-poster.png`, {
type: 'image/png'
})
const projectFile = fromNativeFile(nativeFile)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block can be simplified by using the fromBlob utility function directly on the blob from the canvas. This avoids the creation of an intermediate nativeFile object, making the code more concise and readable.

  const projectFile = fromBlob(`${props.projectData.name}-poster.png`, blob)

niupilot[bot]
niupilot bot previously requested changes Sep 26, 2025
Copy link

@niupilot niupilot bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Good implementation of the web URL functionality, but there are several important areas that need attention:

🚨 Critical Issues:

  • Missing error handling for file upload operations
  • Significant performance impact (adds 1-3s network latency)
  • Breaking API change lacking proper documentation

⚠️ Important Issues:

  • Security: Missing file upload validation and authorization checks
  • Import organization could be improved
  • Need loading states for UI components using this function

The functionality works as intended but requires hardening for production use.

import { getProjectPageRoute } from '@/router'
import QRCode from 'qrcode'
import { saveFileForWebUrl } from '@/models/common/cloud'
import { fromNativeFile } from '@/models/common/file'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Group imports from the same module together for better organization and maintainability.

Suggested change
import { fromNativeFile } from '@/models/common/file'
import { createFileWithUniversalUrl, saveFileForWebUrl } from '@/models/common/cloud'

})
const createPoster = async (): Promise<File> => {
const createPoster = async (): Promise<string> => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add JSDoc documentation for this breaking API change. Components using this function need to understand the return type change from File to string.

Suggested change
const createPoster = async (): Promise<string> => {
/**
* Creates a poster image from the current project data and returns a web URL to the uploaded image.
* @returns {Promise<string>} A promise that resolves to a web URL of the uploaded poster image
* @throws {Error} When poster element is not ready, poster generation fails, or upload fails
*/
const createPoster = async (): Promise<string> => {

@qiniu-ci
Copy link

This PR has been deployed to the preview environment. You can explore it using the preview URL.

Warning

Please note that deployments in the preview environment are temporary and will be automatically cleaned up after a certain period. Make sure to explore it before it is removed. For any questions, contact the XBuilder team.

@Dshuishui Dshuishui requested a review from Copilot September 29, 2025 01:34
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.


Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

resolve()
}
}
)
Copy link
Preview

Copilot AI Sep 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The watch callback may never execute if imgUrl.value is already truthy when the watch is set up, causing the promise to never resolve. Consider checking the initial value immediately after setting up the watch.

Suggested change
)
)
// Immediately check after setting up the watcher
if (imgUrl.value) {
unwatch()
resolve()
}

Copilot uses AI. Check for mistakes.

console.warn('Image failed to load:', img.src)
resolve()
}
setTimeout(() => resolve(), 2000)
Copy link
Preview

Copilot AI Sep 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The 2000ms timeout is a magic number. Consider defining this as a named constant like IMAGE_LOAD_TIMEOUT to make it more maintainable and self-documenting.

Copilot uses AI. Check for mistakes.

Copy link
Collaborator

@nighca nighca left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

先 merge

const shareResult = platform.shareFunction.shareImage(posterURL)
// if shareResult is from an async function, await it
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: 可以直接 await 的,对于非 Promise 的值,await 它得到的还是这个值,不会有什么问题

另外一般情况下一个函数(如这里的 shareImage)应当确保自己返回的要么总是 Promise,要么总是非 Promise,而不应该把这个负担转嫁给调用方

// unified image waiting function
const ensureImagesReady = async () => {
// wait for imgUrl to be set if not already
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

看上去这里直接用 await untilNotNull(imgUrl) 就好?

console.warn('Image failed to load:', img.src)
resolve()
}
setTimeout(() => resolve(), 2000)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个 setTimeout 不是常规逻辑,加个注释吧

@nighca nighca merged commit f0073b8 into goplus:trailhead_sharing Sep 29, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants