Skip to content
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

Add new configuration setup forms #6201

Open
wants to merge 13 commits into
base: production
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React from 'react';

import { configurationText } from '../../localization/configurationText';
import { ajax } from '../../utils/ajax';
import { Http } from '../../utils/ajax/definitions';
import { Container, H2 } from '../Atoms';
import type { SpecifyResource } from '../DataModel/legacyTypes';
import { tables } from '../DataModel/tables';
import type { Collection } from '../DataModel/types';
import { adminUser, collection, discipline, division, institution } from '../FormParse/webOnlyViews';
import { ResourceView } from '../Forms/ResourceView';

export function ConfigurationTool(): JSX.Element {

const onInstitutionSaved = async (data: any) => ajax('/specify/institution/create/', {
method: 'POST',
headers: { Accept: 'application/json' },
body: JSON.stringify(data),
errorMode: 'visible',
expectedErrors:
[Http.CREATED],
})
.then(({ data, status }) => {
if (status === Http.OK) {
console.log('Institution created successfully:', data);
} else {
console.error('Error creating institution:', data);
}
}).catch(error => {
console.error('Request failed:', error);
});

const resources = [
{ resource: new tables.Institution.Resource(), viewName: institution, onClick: () => console.log('click') },
{ resource: new tables.Division.Resource(), viewName: division, onClick: () => console.log('click') },
{ resource: new tables.Discipline.Resource(), viewName: discipline, onClick: () => console.log('click') },
{ resource: new tables.Collection.Resource(), viewName: collection, onClick: () => console.log('click') },
{ resource: new tables.SpecifyUser.Resource(), viewName: adminUser, onClick: () => console.log('click') }
];

const onClose = ():void => {
console.log('close')
}

return (
<Container.FullGray>
<H2 className="text-2xl">{configurationText.specifySetUp()}</H2>
{resources.map((resource, index) => (
<ResourceView
dialog={false}
isDependent={false}
isSubForm={false}
key={index}
resource={resource.resource as SpecifyResource<Collection>}
viewName={resource.viewName}
onAdd={undefined}
onClose={() => onClose()}
onDeleted={undefined}
onSaved={async () => resource.onClick()}

/*
* Example on how to call another function and not the normal save logic:
* onSaving={async () => resource.onClick()}
* onSaving={(unsetUnloadProtect): false => {
* unsetUnloadProtect();
* loading(
* ajax<number>(`/api/workbench/create_recordset/${datasetId}/`, {
* method: 'POST',
* headers: { Accept: 'application/json' },
* body: formData({ name: recordSet.get('name') }),
* errorMode: 'dismissible',
* }).then(({ data }) =>
* unsafeNavigate(`/specify/record-set/${data}/`)
* )
* );
* return false;
* }}
*/
/>
))}
</Container.FullGray>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,37 @@ export const webOnlyViews = f.store(() =>
'edit',
['name']
),
[adminUser]: autoGenerateViewDefinition(
tables.SpecifyUser,
'form',
'edit',
['name', 'password', 'agents']
Copy link
Member

Choose a reason for hiding this comment

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

Field captions are usually determined by the schema configuration, but in the case the user sees this upon a first run, the captions will just be verbatim the name (e.g. "IsAccessionsGlobal" rather than a user-assigned schema). How are we going to set the labels?

),
[institution]: autoGenerateViewDefinition(
tables.Institution,
'form',
'edit',
['name', 'code', 'isAccessionsGlobal', 'isSingleGeographyTree', 'isSecurityOn', 'isServerBased']
Copy link
Member

Choose a reason for hiding this comment

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

isSecurityOn and isServerBased should probably be set automatically and not input by the user.

IsAccessionsGlobal and IsSingleGeographyTree will affect application behavior and absolutely impact the later generation of disciplines (each discipline would not get the choice to create a geography tree)

),
[division]: autoGenerateViewDefinition(
tables.Division,
'form',
'edit',
['name', 'abbrev']
),
[discipline]: autoGenerateViewDefinition(
tables.Discipline,
'form',
'edit',
// Required field: institution id
['name', 'type']
),
[collection]: autoGenerateViewDefinition(
tables.Collection,
'form',
'edit',
['collectionName', 'code', 'catalogNumFormatName']
Copy link
Member

Choose a reason for hiding this comment

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

CatalogNumFormatName should let the user choose form a default list of formats

),
} as const)
);

Expand All @@ -92,3 +123,8 @@ export const attachmentView = 'ObjectAttachment';
export const spAppResourceView = '_SpAppResourceView_name';
export const spViewSetNameView = '_SpViewSetObj_name';
export const recordSetView = '_RecordSet_name';
export const adminUser = '_AdminUser_setup';
export const institution = '_Institution_setup';
export const division = '_Division_setup';
export const discipline = '_Discipline_setup';
export const collection = '_Collection_setup';
5 changes: 5 additions & 0 deletions specifyweb/frontend/js_src/lib/components/Header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ export function Header({
);

const activeMenuItem = React.useContext(MenuContext);

// To chnage once we added the feature for setup detection
const isSetupMode = false

return (
<header
className={`
Expand Down Expand Up @@ -123,6 +127,7 @@ export function Header({
className={`
flex flex-1 overflow-auto
${isHorizontal ? '' : 'flex-col'}
${isSetupMode? 'invisible': ''}
`}
>
<HeaderItems
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { commonText } from '../../localization/common';
import { configurationText } from '../../localization/configurationText';
import { headerText } from '../../localization/header';
import { preferencesText } from '../../localization/preferences';
import { resourcesText } from '../../localization/resources';
Expand Down Expand Up @@ -62,6 +63,11 @@ const rawUserTools = ensure<IR<IR<Omit<MenuItem, 'name'>>>>()({
url: '/specify/schema-config/',
icon: icons.adjustments,
},
configurationTool: {
title: configurationText.configurationTool(),
url: '/specify/configuration-tool/',
icon: icons.cog,
},
},
[headerText.administration()]: {
resources: {
Expand Down
9 changes: 9 additions & 0 deletions specifyweb/frontend/js_src/lib/components/Router/Routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -365,9 +365,18 @@ export const routes: RA<EnhancedRoute> = [
title: preferencesText.preferences(),
element: () =>
import('../Preferences').then(

({ PreferencesWrapper }) => PreferencesWrapper
),
},
{
path: 'configuration-tool',
title: preferencesText.preferences(),
element: () =>
import('../ConfigurationTool').then(
({ ConfigurationTool }) => ConfigurationTool
),
},
{
path: 'schema-config',
title: schemaText.schemaConfig(),
Expand Down
18 changes: 18 additions & 0 deletions specifyweb/frontend/js_src/lib/localization/configurationText.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Localization strings for the preferences menu
*
* @module
*/

import { createDictionary } from './utils';

// Refer to "Guidelines for Programmers" in ./README.md before editing this file

export const configurationText = createDictionary({
configurationTool: {
'en-us': 'Configuration Tool'
},
specifySetUp: {
'en-us': 'Specify Setup'
},
} as const)
3 changes: 2 additions & 1 deletion specifyweb/specify/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""

from calendar import c
import http
import json
import logging
import re
Expand Down Expand Up @@ -1191,4 +1192,4 @@ def _handle_special_update_priors(obj, data):
)
data = modify_update_of_interaction_sibling_preps(obj, data)
data = modify_update_of_loan_return_sibling_preps(obj, data)
return data
return data
3 changes: 3 additions & 0 deletions specifyweb/specify/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
url(r'^specify/(?P<model>\w+)/$', views.collection), # permissions added
url(r'^specify_rows/(?P<model>\w+)/$', views.rows), # permissions added

# new setup
url(r'^specify/institution/create/$', views.create_institution),

url(r'^delete_blockers/(?P<model>\w+)/(?P<id>\d+)/$', views.delete_blockers),

# this url always triggers a 500 for testing purposes
Expand Down
11 changes: 10 additions & 1 deletion specifyweb/specify/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ def view(request, *args, **kwargs):
collection_bulk_copy = api_view(api.collection_dispatch_bulk_copy)
collection_bulk = api_view(api.collection_dispatch_bulk)


def raise_error(request):
"""This endpoint intentionally throws an error in the server for
testing purposes.
Expand Down Expand Up @@ -1367,3 +1366,13 @@ def parse_locality_set_foreground(collection, column_headers: List[str], data: L
return 422, errors

return 200, parsed

def create_institution(request):
if request.method == 'POST':
try:
data = json.loads(request.body)
new_institution = spmodels.Institution.objects.create(**data)
return http.JsonResponse({"success": True, "institution_id": new_institution.id}, status=201)
except Exception as e:
return http.JsonResponse({"error": str(e)}, status=400)
return http.JsonResponse({"error": "Invalid request"}, status=400)
Loading