Skip to content

Commit

Permalink
Merge branch 'develop' into issue-3247-inaccurate-info-for-foreign-ke…
Browse files Browse the repository at this point in the history
…y-column-referencing-unique-column
  • Loading branch information
seancolsen authored Oct 25, 2023
2 parents 069bdd6 + cd3b437 commit 788a673
Show file tree
Hide file tree
Showing 53 changed files with 1,277 additions and 131 deletions.
52 changes: 50 additions & 2 deletions config/context_processors.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,65 @@
from django.conf import settings
from django.templatetags.static import static


from mathesar.utils.frontend import get_manifest_data


def frontend_settings(request):
manifest_data = get_manifest_data()
development_mode = settings.MATHESAR_MODE == 'DEVELOPMENT'

i18n_settings = get_i18n_settings(manifest_data, development_mode)
frontend_settings = {
'development_mode': settings.MATHESAR_MODE == 'DEVELOPMENT',
'manifest_data': get_manifest_data(),
'development_mode': development_mode,
'manifest_data': manifest_data,
'live_demo_mode': getattr(settings, 'MATHESAR_LIVE_DEMO', False),
'live_demo_username': getattr(settings, 'MATHESAR_LIVE_DEMO_USERNAME', None),
'live_demo_password': getattr(settings, 'MATHESAR_LIVE_DEMO_PASSWORD', None),
**i18n_settings
}
# Only include development URL if we're in development mode.
if frontend_settings['development_mode'] is True:
frontend_settings['client_dev_url'] = settings.MATHESAR_CLIENT_DEV_URL

return frontend_settings


def get_display_language_from_request(request):
# https://docs.djangoproject.com/en/4.2/topics/i18n/translation/#how-django-discovers-language-preference
# This automatically fallbacks to en because of https://docs.djangoproject.com/en/4.2/ref/settings/#std-setting-LANGUAGE_CODE
lang_from_locale_middleware = request.LANGUAGE_CODE

if request.user.is_authenticated:
return request.user.display_language or lang_from_locale_middleware
else:
return lang_from_locale_middleware


def get_i18n_settings(manifest_data, development_mode):
"""
Hard coding this for now
but will be taken from users model
and cookies later on
"""
display_language = 'en'
fallback_language = 'en'

client_dev_url = settings.MATHESAR_CLIENT_DEV_URL

if development_mode is True:
module_translations_file_path = f'{client_dev_url}/src/i18n/{display_language}/index.ts'
legacy_translations_file_path = f'{client_dev_url}/src/i18n/{display_language}/index.ts'
else:
try:
module_translations_file_path = static(manifest_data[display_language]["file"])
legacy_translations_file_path = static(manifest_data[f"{display_language}-legacy"]["file"])
except KeyError:
module_translations_file_path = static(manifest_data[fallback_language]["file"])
legacy_translations_file_path = static(manifest_data[f"{fallback_language}-legacy"]["file"])

return {
'module_translations_file_path': module_translations_file_path,
'legacy_translations_file_path': legacy_translations_file_path,
'display_language': display_language
}
8 changes: 8 additions & 0 deletions config/settings/common_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

from decouple import Csv, config as decouple_config
from dj_database_url import parse as db_url
from django.utils.translation import gettext_lazy


# We use a 'tuple' with pipes as delimiters as decople naively splits the global
Expand Down Expand Up @@ -50,6 +51,7 @@ def pipe_delim(pipe_string):
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.locale.LocaleMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
Expand Down Expand Up @@ -254,4 +256,10 @@ def pipe_delim(pipe_string):
# List of Template names that contains additional script tags to be added to the base template
BASE_TEMPLATE_ADDITIONAL_SCRIPT_TEMPLATES = []

# i18n
LANGUAGES = [
('en', gettext_lazy('English')),
('ja', gettext_lazy('Japanese')),
]
LANGUAGE_COOKIE_NAME = 'display_language'
SALT_KEY = SECRET_KEY
1 change: 1 addition & 0 deletions mathesar/api/ui/serializers/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class Meta:
'is_superuser',
'database_roles',
'schema_roles',
'display_language'
]
extra_kwargs = {
'password': {'write_only': True},
Expand Down
18 changes: 18 additions & 0 deletions mathesar/migrations/0005_user_display_language.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 3.1.14 on 2023-09-06 11:25

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('mathesar', '0004_shares'),
]

operations = [
migrations.AddField(
model_name='user',
name='display_language',
field=models.CharField(blank=True, default='en', max_length=30),
),
]
14 changes: 14 additions & 0 deletions mathesar/migrations/0009_merge_20231025_1733.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Generated by Django 3.1.14 on 2023-10-25 17:33

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('mathesar', '0008_auto_20230921_1834'),
('mathesar', '0005_user_display_language'),
]

operations = [
]
1 change: 1 addition & 0 deletions mathesar/models/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class User(AbstractUser):
full_name = models.CharField(max_length=255, blank=True, null=True)
short_name = models.CharField(max_length=255, blank=True, null=True)
password_change_needed = models.BooleanField(default=False)
display_language = models.CharField(max_length=30, blank=True, default='en')


class Role(models.TextChoices):
Expand Down
24 changes: 19 additions & 5 deletions mathesar/templates/mathesar/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
{% block title %}Home{% endblock %}

{% block styles %}
{% if not development_mode %} {% for css_file in manifest_data.module_css %}
<link rel="stylesheet" href="{% static css_file %}" />
{% endfor %} {% endif %}
{% if not development_mode %}
{% for css_file in manifest_data.module_css %}
<link rel="stylesheet" href="{% static css_file %}" />
{% endfor %}
{% endif %}
{% endblock %}

{% block scripts %}
Expand All @@ -17,6 +19,8 @@
{% endfor %}
{% endif %}

<script type="module" src="{{ module_translations_file_path }}"></script>

{% if development_mode %}
<script type="module" src="{{ client_dev_url }}/@vite/client"></script>
<script type="module" src="{{ client_dev_url }}/src/main.ts"></script>
Expand Down Expand Up @@ -52,12 +56,22 @@
></script>
<script
nomodule
id="vite-legacy-entry"
id="vite-legacy-translations-slot"
data-src="{{ legacy_translations_file_path }}"
>
System.import(
document.getElementById("vite-legacy-translations-slot").getAttribute("data-src")
);
</script>
<script
nomodule
id="vite-legacy-js-slot"
data-src="{% static manifest_data.legacy_js %}"
>
System.import(
document.getElementById("vite-legacy-entry").getAttribute("data-src")
document.getElementById("vite-legacy-js-slot").getAttribute("data-src")
);
</script>

{% endif %}
{% endblock %}
23 changes: 23 additions & 0 deletions mathesar/templates/mathesar/login_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@
font-size: var(--size-xx-large);
text-align: center;
}
.login-card .language-selector {
display: block;
background-color: transparent;
border: 1px solid var(--slate-200);
border-radius: 0.285rem;
cursor: pointer;
}
@media (max-width: 50rem) {
.unsupported-device {
display: block;
Expand Down Expand Up @@ -143,5 +150,21 @@
<div class="login-card align-center">
<h1>{% block h1 %} {% endblock %}</h1>
{% block box_content %} {% endblock %}
<!-- Commenting it out to avoid releasing any half baked changes
{% comment %} set_language https://docs.djangoproject.com/en/4.2/topics/i18n/translation/#the-set-language-redirect-view {% endcomment %}
<form action="{% url 'set_language' %}" method="post">{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}">
<select name="language" onchange="form.submit()" class="language-selector align-center" aria-label="Display Language">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected{% endif %}>
{{ language.name_local }} ({{ language.code }})
</option>
{% endfor %}
</select>
</form>
-->
</div>
{% endblock %}
4 changes: 4 additions & 0 deletions mathesar/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,14 @@
path('administration/users/', views.admin_home, name='admin_users_home'),
path('administration/users/<user_id>/', views.admin_home, name='admin_users_edit'),
path('administration/update/', views.admin_home, name='admin_update'),
path('administration/db-connection/', views.list_database_connection, name='list_database_connection'),
path('administration/db-connection/add/', views.add_database_connection, name='add_database_connection'),
path('administration/db-connection/edit/<db_name>/', views.edit_database_connection, name='edit_database_connection'),
path('shares/tables/<slug>/', views.shared_table, name='shared_table'),
path('shares/explorations/<slug>/', views.shared_query, name='shared_query'),
path('db/', views.home, name='db_home'),
path('db/<db_name>/', views.schemas, name='schemas'),
path('i18n/', include('django.conf.urls.i18n')),
re_path(
r'^db/(?P<db_name>\w+)/(?P<schema_id>\w+)/',
views.schema_home,
Expand Down
5 changes: 4 additions & 1 deletion mathesar/utils/frontend.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ def get_manifest_data():
module_data = raw_data['src/main.ts']
manifest_data['module_css'] = [filename for filename in module_data['css']]
manifest_data['module_js'] = module_data['file']

legacy_data = raw_data['src/main-legacy.ts']
manifest_data['legacy_polyfill_js'] = raw_data['vite/legacy-polyfills-legacy']['file']
manifest_data['legacy_js'] = legacy_data['file']

for locale, _ in settings.LANGUAGES or []:
manifest_data[locale] = raw_data[f'src/i18n/{locale}/index.ts']
manifest_data[f"{locale}-legacy"] = raw_data[f'src/i18n/{locale}/index-legacy.ts']

# Cache data for 1 hour
cache.set('manifest_data', manifest_data, 60 * 60)
return manifest_data
29 changes: 29 additions & 0 deletions mathesar/views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect, get_object_or_404
from rest_framework import status
Expand Down Expand Up @@ -80,7 +81,12 @@ def get_database_list(request):
failed_db_data = []
for db in permission_restricted_failed_db_qs:
failed_db_data.append({
'id': db.id,
'username': db.username,
'port': db.port,
'host': db.host,
'name': db.name,
'db_name': db.db_name,
'editable': db.editable,
'error': 'Error connecting to the database'
})
Expand Down Expand Up @@ -157,6 +163,7 @@ def get_common_data(request, database=None, schema=None):
'databases': get_database_list(request),
'tables': get_table_list(request, schema),
'queries': get_queries_list(request, schema),
'supported_languages': dict(getattr(settings, 'LANGUAGES', [])),
'routing_context': 'normal',
}

Expand Down Expand Up @@ -301,6 +308,28 @@ def schemas(request, db_name):
})


@login_required
def list_database_connection(request):
return render(request, 'mathesar/index.html', {
'common_data': get_common_data(request)
})


@login_required
def add_database_connection(request):
return render(request, 'mathesar/index.html', {
'common_data': get_common_data(request)
})


@login_required
def edit_database_connection(request, db_name):
database = get_current_database(request, db_name)
return render(request, 'mathesar/index.html', {
'common_data': get_common_data(request, database, None)
})


def shared_table(request, slug):
shared_table_link = SharedTable.get_by_slug(slug) if is_valid_uuid_v4(slug) else None
table = shared_table_link.table if shared_table_link else None
Expand Down
36 changes: 20 additions & 16 deletions mathesar_ui/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,42 @@
import { preloadCommonData } from '@mathesar/utils/preloadData';
import AppContext from './AppContext.svelte';
import RootRoute from './routes/RootRoute.svelte';
import { loadLocaleAsync } from './i18n/i18n-load';
import { setLocale } from './i18n/i18n-svelte';
import type { RequestStatus } from './api/utils/requestUtils';
import { getErrorMessage } from './utils/errors';
import ErrorBox from './components/message-boxes/ErrorBox.svelte';
import { loadLocaleAsync, loadTranslations } from './i18n/i18n-load';
let isTranslationsLoaded = false;
/**
* Later the translations file will be loaded
* in parallel to the FE's first chunk
* Why translations are being read from window object?
* In order to -
* 1. Load the translations file in parallel to the first FE chunk.
* 2. And then make it available for the entry(App.svelte)
* file to load them into memory.
*
* The index.html loads it as using a script tag
* Each translations file on load, attaches the translations
* to the window object
*/
let translationLoadStatus: RequestStatus = { state: 'processing' };
void (async () => {
try {
const { translations, displayLanguage } = window.Mathesar || {};
if (translations && displayLanguage) {
loadTranslations(displayLanguage, translations[displayLanguage]);
setLocale(displayLanguage);
isTranslationsLoaded = true;
} else {
await loadLocaleAsync('en');
setLocale('en');
translationLoadStatus = { state: 'success' };
} catch (exp) {
translationLoadStatus = {
state: 'failure',
errors: [getErrorMessage(exp)],
};
isTranslationsLoaded = true;
}
})();
const commonData = preloadCommonData();
</script>

{#if translationLoadStatus.state === 'success' && commonData}
{#if isTranslationsLoaded && commonData}
<AppContext {commonData}>
<RootRoute {commonData} />
</AppContext>
{:else if translationLoadStatus.state === 'processing'}
{:else if !isTranslationsLoaded}
<div class="app-loader">
<Spinner size="2rem" />
</div>
Expand Down
Loading

0 comments on commit 788a673

Please sign in to comment.