-
Notifications
You must be signed in to change notification settings - Fork 460
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New feature: Add custom ad banner #1202
Conversation
Let useCustomBanners() always obtains the latest data instead of downloading it at runtime
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you also add the variable of the config URL to the list of downloaded assets, here - deploy/scripts/download_assets.sh
? Then use helper getExternalAssetFilePath
in the app config file to get the public path to the file in application code.
OK, I'll add the variable of the config URL to the list of downloaded assets, and use helper getExternalAssetFilePath in the app config file to get the public path to the file in application code. I've done that at first commit but remove it at second because at that time I wanted this part of the advertisement to be automatically adjusted with modifications to external files, rather than fixed at startup. Now I think we can add a separate environment variable to control the use of this feature. |
I'll add another env variables like NEXT_PUBLIC_DISABLE_DOWNLOAD_AT_RUM_TIME to realize that in other pr. |
2. Putting interval in the custom ad config and update the schema. 3. Add the variable of the config URL to the list of downloaded assets and use helper getExternalAssetFilePath in the app config file to get the public path to the file in application code. 4. Fix some variables' name and docs.
@tom2drum Please check again. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work! Leave some comments about the code style and types. Feel free to fix them.
I don't really think that we need this kind of setting. In general, the app should not break if the remote config is suddenly changed. Configuration should be persistent for the running instance. That's why we download all these files at run-time. If you need another configuration for your app, then re-run the container with new ENVs and you're good to go. It should not be any different than for other (non-json like) ENVs. |
Why not leave this as an optional configuration for deployment users to decide? |
Check this issue #1206 , that's anothe reason why I think this is necessary. |
It is fallible and potentially can break app integrity. I don't see any reason why we should make an exception for some config properties and allow them to be dynamic and not persistent. Such behavior should not be accepted on the general level of the app, imho. But users who really need this for some reason are always free to create a fork and make amends. |
I will take a look later when I have time. But I don't think it is going to change the approach. |
I fully understand your considerations. If you think this is not a feature that most users need, I will only implement it on my own branch. |
… play order setting; 2. Update schema and doc; 3. Modify some variable names to improve code readability
@tom2drum Please check the latest update. I've developed at https://testnet-qng.qitmeer.io/ |
# Conflicts: # deploy/scripts/download_assets.sh
docs/ENVS.md
Outdated
| banners | `array` | List of banners with their properties. Refer to the "Custom banners configuration properties" section below. | Required | - | See below | | ||
| interval | `number` | Duration (in milliseconds) for how long each banner will be displayed. | - | 60000 | `6000` | | ||
| randomStart | `boolean` | Set to true to randomly start playing advertisements from any position in the array | - | `false` | `true` | | ||
| randomNextAd | `boolean` | Set to ture to randomly play advertisements | - | `false` | `true` | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| randomNextAd | `boolean` | Set to ture to randomly play advertisements | - | `false` | `true` | | |
| randomNextAd | `boolean` | Set to true to randomly play advertisements | - | `false` | `true` | |
ui/shared/ad/CustomAdBanner.tsx
Outdated
const configUrl = (feature.isEnabled && feature.provider === 'custom') ? feature.configUrl : ''; | ||
|
||
const apiFetch = useFetch(); | ||
const { data: adConfig } = useQuery<unknown, ResourceError<unknown>, AdCustomConfig>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to manage the following states of the component as well:
- loading - while the config is loading it is good to show a skeleton
- error - if the request fails then render nothing (
null
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, I will add these two states
2. Specify a skeleton as a fallback prop for the Image
2.use 'test(urlTest)' instead of 'url()'
@tom2drum please check latest version |
.object() | ||
.shape({ | ||
text: yup.string(), | ||
url: yup.string().test(urlTest), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't it required, is it?
| NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP | `{ id: string; width: string; height: string }` | Placement config for desktop Adbutler banner | - | - | `{'id':'123456','width':'728','height':'90'}` | | ||
| NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE | `{ id: string; width: number; height: number }` | Placement config for mobile Adbutler banner | - | - | `{'id':'654321','width':'300','height':'100'}` | | ||
| NEXT_PUBLIC_AD_CUSTOM_CONFIG_URL | `string` | URL of configuration file (.json format only) which contains settings and list of custom banners that will be shown in the home page and token detail page. See below list of available properties for particular banner | - | - | `https://example.com/ad_custom_config.json` | | ||
|
||
#### Configuration properties |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#### Configuration properties | |
#### Custom ad configuration properties |
just a little bit more specific
const baseBanners = adConfig?.banners || []; | ||
const randomStart = adConfig?.randomStart || false; | ||
const randomNextAd = adConfig?.randomNextAd || false; | ||
const banners = randomNextAd ? shuffle(baseBanners) : baseBanners; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would probably do a memoization here, otherwise whenever component re-renders, the new sequence of banners will be generated, so it kind of affects randomness a little bit
mobileImageUrl: yup.string().test(urlTest).required(), | ||
}); | ||
|
||
const adCustomConfigSchema = yup |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you checked the schema validation localy as it is described in docs?
I guess we are missing .json()
here, so the yup can parse the string to the actual JSON.
Also in deploy/tools/envs-validator/index.ts
you need to replace ENV value with the content of the json-file in order to make the validator work.
appEnvs.NEXT_PUBLIC_AD_CUSTOM_CONFIG_URL = await getExternalJsonContent(
'./public/assets/ad_custom_config.json',
appEnvs.NEXT_PUBLIC_AD_CUSTOM_CONFIG_URL,
) || '[]';
Can you please temporarily add this config ENV to the .env.main
preset file to demonstrate that everything works as expected? I will run the validator in our CI then. After that, you can comment it out. I know it is not the best workflow, but we are trying to improve it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jasonzysun I have just merged some changes in the validation script, now it should be easier to add tests for the new variables. I've described all the necessary steps in the contribution guide. Check it out and let me know if you have any questions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's great to hear. I haven't been able to address this section of the content lately, but I'll take care of it in the coming days.
Do I understand correctly that this approach preloads a set of ads from a dynamic JSON manifest once on blockscout app server start? Is there any way to refresh the set of loaded assets in this approach? |
Yes, your understanding is correct. Due to the design of #1184 , the external customized configuration files referenced by the front-end will be downloaded to the Docker during startup. Therefore, if the customized advertising content in the configuration files is modified externally after startup, the current version of the front-end UI will not respond to changes in a timely manner, and the browser needs to be manually restarted. |
@jasonzysun got it, thank you! I know you've done a lot of work on this, so I must ask - is there a reason you didn't choose an approach like specifying an external iframe (or some external JS that would insert the iframe into the ad slot) url via an ENV value? This general practice is very common with display advertising systems + does allow you to manage the ad content, frequency, etc completely without making further changes to the blockscout/docker/etc instance. |
In fact, the purpose of this custom feature is not to introduce a new advertising system, but to provide a simple feature that allows users to implement their own advertising with just one configuration file when they have copy and images. |
In addition to the three methods, adbutler, coinzilla and slise, provided in the adBanner, a custom adBanner method has been added. The method of obtaining configuration files refers to NEXT_PUBLIC_MarkeTPLACE_CONFIG_URL and advertising display method refer to slise.
I did not use the two testing methods mentioned in the Contribution guide, but I have applied this configuration in Qitmeer's block browser and can access qng.qitmeer.io for viewing.