ypankovych commented on issue #18938:
URL: https://github.com/apache/superset/issues/18938#issuecomment-1161789831
We actually managed to do that with a bunch of tweaks & hacks.
First of all, you'll need a custom `/static` view to catch the static that's
being accessed.
```python
def custom_static(self, filename): # vendored from flask and modified to
support our static files
# Ensure get_send_file_max_age is called in all cases.
# Here, we ensure get_send_file_max_age is called for Blueprints.
cache_timeout = self.get_send_file_max_age(filename)
with contextlib.suppress(NotFound):
# here you mutate static files
mutated, render, mutated_filename =
get_mutated_static(self.static_folder, filename)
response = send_from_directory(
self.static_folder, mutated_filename, cache_timeout=0 if mutated
else cache_timeout
)
if mutated:
os.remove(os.path.join(self.static_folder, mutated_filename))
return response
raise NotFound
```
Then you set it as current static views in your `flask_app_mutator` function:
```python
app.view_functions["static"] = MethodType(custom_static, app) # hack
```
Here's the `mutated_static`:
```python
def get_mutated_static(static_dir, filename):
file_path = os.path.join(static_dir, filename)
for mutator_spec in MUTATED_STATIC:
if static_dir in mutator_spec.static_dirs and
mutator_spec.predicate(file_path):
file_content = mutator_spec.mutator(file_path)
break
else:
return False, False, filename
_, suffix = os.path.splitext(filename)
with tempfile.NamedTemporaryFile(dir=static_dir, mode="w", delete=False,
suffix=suffix) as temp_fp:
temp_fp.write(file_content)
return True, mutator_spec.render, os.path.relpath(temp_fp.name,
static_dir)
```
In a nutshell, you mutate your static, write it to a temp file, make a
response based on a temp file, you remove the temp file.
Here we register our mutated static:
```python
class MutatedStaticSpec(NamedTuple):
predicate: Callable[[str], bool]
mutator: Callable[[str], Union[str, bytes]]
static_dirs: List[str] = ["default dir here (the superset's one)"]
# mutate static file at runtime
# you match the file in `predicate` within the `static_dirs` folders, mutate
the content in `mutator`,
MUTATED_STATIC = (
MutatedStaticSpec(
predicate=lambda file_path: (
# we don't know the exact filename, as it may change any time
file_path.endswith(".js")
and any(placeholder in open(file_path).read() for placeholder in
JS_CURRENCY_LOCALE_PLACEHOLDERS)
),
mutator=_set_currency_placeholder,
static_dirs=[os.path.join("/app/superset", "static")],
),
)
```
Here's js currency locale placeholder (you don't need to change it):
```python
# [0] minimized js version, [1] formatted (we need this for compatibility
between superset 1.4 and 1.5)
JS_CURRENCY_LOCALE_PLACEHOLDERS = ("currency:[\"$\",\"\"]", "currency:
[\"$\", \"\"]")
```
And here's `_set_currency_placeholder`:
```python
def _set_currency_placeholder(file_path):
with open(file_path) as fp:
file_content = fp.read()
for placeholder in JS_CURRENCY_LOCALE_PLACEHOLDERS:
file_content = file_content.replace(
placeholder,
render_template_string("currency:[\"{{ currency_symbol
}}\",\"\"]")
)
return file_content
```
As you can see here, we render a single string
`render_template_string("currency:[\"{{ currency_symbol }}\",\"\"]")`, so we
need to have a currency in our general app context. And as we're using the
flask app, we can simply add to the global context as follows:
```python
def get_currency():
# use any currency symbol here, you'd probably want to get it somewhere
from the settings
return {"currency_symbol": "$"}
```
Then register that context processor in `superset_config.py` as follows:
```python
CONTEXT_PROCESSORS = (get_client_currency,)
```
When you access a chart/dashboard, static will mutate during that process,
so the currency symbol gets replaced, and you'll see it in the UI.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]