Skip to content

Commit

Permalink
Sketch class cartography improvements (#632)
Browse files Browse the repository at this point in the history
* Better support GLStyleEditor for sketch classes

Includes a preview map, sketch-class-specific insert-new-layer actions, and adds a constraint and migration to for sketch_classes to have a populated mapbox_gl_style value.
  • Loading branch information
underbluewaters authored Aug 14, 2023
1 parent 1c46a68 commit c5f7ecf
Show file tree
Hide file tree
Showing 22 changed files with 1,594 additions and 103 deletions.
12 changes: 12 additions & 0 deletions packages/api/generated-schema-clean.gql
Original file line number Diff line number Diff line change
Expand Up @@ -4768,6 +4768,16 @@ type EnableOfflineSupportPayload {
query: Query
}

enum ExtendedGeostatsType {
ARRAY
BOOLEAN
MIXED
NULL
NUMBER
OBJECT
STRING
}

"""All input for the `failDataUpload` mutation."""
input FailDataUploadInput {
"""
Expand Down Expand Up @@ -5449,6 +5459,8 @@ type FormElementType implements Node {
allowAdminUpdates: Boolean!
allowedLayouts: [FormElementLayout]
componentName: String!
geostatsArrayOf: ExtendedGeostatsType
geostatsType: ExtendedGeostatsType
isHidden: Boolean!

"""
Expand Down
12 changes: 12 additions & 0 deletions packages/api/generated-schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -4768,6 +4768,16 @@ type EnableOfflineSupportPayload {
query: Query
}

enum ExtendedGeostatsType {
ARRAY
BOOLEAN
MIXED
NULL
NUMBER
OBJECT
STRING
}

"""All input for the `failDataUpload` mutation."""
input FailDataUploadInput {
"""
Expand Down Expand Up @@ -5449,6 +5459,8 @@ type FormElementType implements Node {
allowAdminUpdates: Boolean!
allowedLayouts: [FormElementLayout]
componentName: String!
geostatsArrayOf: ExtendedGeostatsType
geostatsType: ExtendedGeostatsType
isHidden: Boolean!

"""
Expand Down
48 changes: 48 additions & 0 deletions packages/api/migrations/committed/000271.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
--! Previous: sha1:69255ad304c205eab43cd0db6d0193bc403b8f8a
--! Hash: sha1:6d0e0ecb4eb8cbce2e864dce288208def90f03d1

-- Enter migration here
drop type if exists extended_geostats_type cascade;
create type extended_geostats_type as enum (
'string',
'number',
'boolean',
'null',
'mixed',
'array',
'object'
);

alter table form_element_types add column if not exists geostats_type extended_geostats_type default null;
alter table form_element_types add column if not exists geostats_array_of extended_geostats_type default null;

update form_element_types set geostats_type = 'string' where component_name = 'ShortText';
update form_element_types set geostats_type = 'string' where component_name = 'TextArea';
update form_element_types set geostats_type = 'string' where component_name = 'Name';
update form_element_types set geostats_type = 'string' where component_name = 'Email';
update form_element_types set geostats_type = 'number' where component_name = 'Rating';
update form_element_types set geostats_type = 'number' where component_name = 'Number';
update form_element_types set geostats_type = 'boolean' where component_name = 'YesNo';
update form_element_types set geostats_type = 'string' where component_name = 'ComboBox';
update form_element_types set geostats_type = 'array' where component_name = 'MultipleChoice';
update form_element_types set geostats_array_of = 'string' where component_name = 'MultipleChoice';
update form_element_types set geostats_type = 'string' where component_name = 'FeatureName';
update form_element_types set geostats_type = 'number' where component_name = 'SAPRange';
update form_element_types set geostats_type = 'number' where component_name = 'ParticipantCount';


-- Then all polygons missing a style
update sketch_classes set mapbox_gl_style = '[{"type":"fill","paint":{"fill-color":"#f28e2c","fill-opacity":0.6},"layout":{}},{"type":"line","paint":{"line-color":"#f28e2c","line-width":2},"layout":{}}]' where geometry_type = 'POLYGON' and mapbox_gl_style is null;
update sketch_classes set mapbox_gl_style = '[{"type":"fill","paint":{"fill-color":"#f28e2c","fill-opacity":0.6},"layout":{}},{"type":"line","paint":{"line-color":"#f28e2c","line-width":2},"layout":{}}]' where geometry_type = 'POLYGON' and mapbox_gl_style = '{}'::jsonb;

-- Then all points missing a style
update sketch_classes set mapbox_gl_style = '[{"type":"circle","paint":{"circle-color":"#fb9b2d","circle-radius":5,"circle-opacity":0.5,"circle-stroke-color":"#ff822e","circle-stroke-width":1},"layout":{}}]' where geometry_type = 'POINT' and mapbox_gl_style is null;
update sketch_classes set mapbox_gl_style = '[{"type":"circle","paint":{"circle-color":"#fb9b2d","circle-radius":5,"circle-opacity":0.5,"circle-stroke-color":"#ff822e","circle-stroke-width":1},"layout":{}}]' where geometry_type = 'POINT' and mapbox_gl_style = '{}'::jsonb;

-- Then all lines missing a style
update sketch_classes set mapbox_gl_style = '[{"type":"line","paint":{"line-color":"#ffffff","line-width":4},"layout":{"line-cap":"round"}},{"type":"line","paint":{"line-color":"#ff9d14","line-width":2},"layout":{}}]' where geometry_type = 'LINESTRING' and mapbox_gl_style is null;
update sketch_classes set mapbox_gl_style = '[{"type":"line","paint":{"line-color":"#ffffff","line-width":4},"layout":{"line-cap":"round"}},{"type":"line","paint":{"line-color":"#ff9d14","line-width":2},"layout":{}}]' where geometry_type = 'LINESTRING' and mapbox_gl_style = '{}'::jsonb;

-- Then add a constraint to make sure gl style is set for all polygon, point, and line sketches
alter table sketch_classes drop constraint if exists sketch_classes_mapbox_gl_style_not_null;
alter table sketch_classes add constraint sketch_classes_mapbox_gl_style_not_null check (mapbox_gl_style is not null or geometry_type not in ('POLYGON', 'POINT', 'LINESTRING'));
22 changes: 20 additions & 2 deletions packages/api/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,21 @@ CREATE TYPE public.email_summary_frequency AS ENUM (
);


--
-- Name: extended_geostats_type; Type: TYPE; Schema: public; Owner: -
--

CREATE TYPE public.extended_geostats_type AS ENUM (
'string',
'number',
'boolean',
'null',
'mixed',
'array',
'object'
);


--
-- Name: field_rule_operator; Type: TYPE; Schema: public; Owner: -
--
Expand Down Expand Up @@ -1274,7 +1289,8 @@ CREATE TABLE public.sketch_classes (
preprocessing_project_url text,
translated_props jsonb DEFAULT '{}'::jsonb NOT NULL,
CONSTRAINT sketch_classes_geoprocessing_client_url_check CHECK ((geoprocessing_client_url ~* 'https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,255}\.[a-z]{2,9}\y([-a-zA-Z0-9@:%_\+.~#?&//=]*)$'::text)),
CONSTRAINT sketch_classes_geoprocessing_project_url_check CHECK ((geoprocessing_project_url ~* 'https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,255}\.[a-z]{2,9}\y([-a-zA-Z0-9@:%_\+.~#?&//=]*)$'::text))
CONSTRAINT sketch_classes_geoprocessing_project_url_check CHECK ((geoprocessing_project_url ~* 'https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,255}\.[a-z]{2,9}\y([-a-zA-Z0-9@:%_\+.~#?&//=]*)$'::text)),
CONSTRAINT sketch_classes_mapbox_gl_style_not_null CHECK (((mapbox_gl_style IS NOT NULL) OR (geometry_type <> ALL (ARRAY['POLYGON'::public.sketch_geometry_type, 'POINT'::public.sketch_geometry_type, 'LINESTRING'::public.sketch_geometry_type]))))
);


Expand Down Expand Up @@ -6986,7 +7002,9 @@ CREATE TABLE public.form_element_types (
is_spatial boolean DEFAULT false NOT NULL,
sketch_class_template_id integer,
is_required_for_sketch_classes boolean DEFAULT false NOT NULL,
allow_admin_updates boolean DEFAULT true NOT NULL
allow_admin_updates boolean DEFAULT true NOT NULL,
geostats_type public.extended_geostats_type,
geostats_array_of public.extended_geostats_type
);


Expand Down
1 change: 0 additions & 1 deletion packages/api/src/plugins/sketchClassStylePlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ const SketchClassStylePlugin = makeExtendSchemaPlugin((build) => {
) => {
const { pgClient, adminPool } = context;
const { sketchClassId, style } = args;
console.log({ style });
if (!sketchClassId) {
throw new Error("sketchClassId is required");
}
Expand Down
38 changes: 19 additions & 19 deletions packages/api/tests/forms.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ describe("Forms", () => {
async (conn, projectId, adminId, userIds) => {
await createSession(conn, adminId, true, false, projectId);
const sketchClassId = await conn.oneFirst(
sql`insert into sketch_classes (name, project_id) values ('Sketch Class A', ${projectId}) returning id`
sql`insert into sketch_classes (mapbox_gl_style, name, project_id) values ('[]'::jsonb, 'Sketch Class A', ${projectId}) returning id`
);
expect(
conn.oneFirst(
Expand All @@ -77,7 +77,7 @@ describe("Forms", () => {
async (conn, projectId, adminId, userIds) => {
await createSession(conn, adminId, true, false, projectId);
const sketchClassId = await conn.oneFirst(
sql`insert into sketch_classes (name, project_id) values ('Sketch Class A', ${projectId}) returning id`
sql`insert into sketch_classes (mapbox_gl_style, name, project_id) values ('[]'::jsonb, 'Sketch Class A', ${projectId}) returning id`
);
const form = await conn.one(
sql`select * from initialize_blank_sketch_class_form(${sketchClassId})`
Expand All @@ -95,7 +95,7 @@ describe("Forms", () => {
async (conn, projectId, adminId, userIds) => {
await createSession(conn, adminId, true, false, projectId);
const sketchClassId = await conn.oneFirst(
sql`insert into sketch_classes (name, project_id) values ('Sketch Class A', ${projectId}) returning id`
sql`insert into sketch_classes (mapbox_gl_style, name, project_id) values ('[]'::jsonb, 'Sketch Class A', ${projectId}) returning id`
);
await createSession(conn, userIds[0], true, false, projectId);
expect(
Expand All @@ -113,7 +113,7 @@ describe("Forms", () => {
async (conn, projectId, adminId, userIds) => {
await createSession(conn, adminId, true, false, projectId);
const sketchClassId = await conn.oneFirst(
sql`insert into sketch_classes (name, project_id) values ('Sketch Class A', ${projectId}) returning id`
sql`insert into sketch_classes (mapbox_gl_style, name, project_id) values ('[]'::jsonb, 'Sketch Class A', ${projectId}) returning id`
);
const form = await conn.one(
sql`select * from initialize_blank_sketch_class_form(${sketchClassId})`
Expand Down Expand Up @@ -141,7 +141,7 @@ describe("Forms", () => {
async (conn, projectId, adminId, userIds) => {
await createSession(conn, adminId, true, false, projectId);
const sketchClassId = await conn.oneFirst(
sql`insert into sketch_classes (name, project_id) values ('Sketch Class A', ${projectId}) returning id`
sql`insert into sketch_classes (mapbox_gl_style, name, project_id) values ('[]'::jsonb, 'Sketch Class A', ${projectId}) returning id`
);
let form = await conn.one(
sql`select * from initialize_blank_sketch_class_form(${sketchClassId})`
Expand All @@ -168,7 +168,7 @@ describe("Forms", () => {
async (conn, projectId, groupId, adminId) => {
await createSession(conn, adminId, true, false, projectId);
const sketchClassId = await conn.oneFirst(
sql`insert into sketch_classes (name, project_id) values ('Sketch Class A', ${projectId}) returning id`
sql`insert into sketch_classes (mapbox_gl_style, name, project_id) values ('[]'::jsonb, 'Sketch Class A', ${projectId}) returning id`
);
await limitToGroup(conn, "sketch_class_id", sketchClassId, groupId);
let form = await conn.one(
Expand Down Expand Up @@ -261,7 +261,7 @@ describe("Forms", () => {
async (conn, projectId, adminId, userIds) => {
await createSession(conn, adminId, true, true, projectId);
const sketchClassId = await conn.oneFirst(
sql`insert into sketch_classes (name, project_id) values ('Sketch Class A', ${projectId}) returning id`
sql`insert into sketch_classes (mapbox_gl_style, name, project_id) values ('[]'::jsonb, 'Sketch Class A', ${projectId}) returning id`
);
let form = await conn.one(
sql`select * from initialize_blank_sketch_class_form(${sketchClassId})`
Expand Down Expand Up @@ -289,7 +289,7 @@ describe("Forms", () => {
async (conn, projectId, adminId, userIds) => {
await createSession(conn, adminId, true, false, projectId);
const sketchClassId = await conn.oneFirst(
sql`insert into sketch_classes (name, project_id) values ('Sketch Class A', ${projectId}) returning id`
sql`insert into sketch_classes (mapbox_gl_style, name, project_id) values ('[]'::jsonb, 'Sketch Class A', ${projectId}) returning id`
);
const form = await conn.one(
sql`select * from initialize_blank_sketch_class_form(${sketchClassId})`
Expand All @@ -305,7 +305,7 @@ describe("Forms", () => {
async (conn, projectId, adminId, userIds) => {
await createSession(conn, adminId, true, true, projectId);
const sketchClassId = await conn.oneFirst(
sql`insert into sketch_classes (name, project_id) values ('Sketch Class A', ${projectId}) returning id`
sql`insert into sketch_classes (mapbox_gl_style, name, project_id) values ('[]'::jsonb, 'Sketch Class A', ${projectId}) returning id`
);
const source = await conn.one(
sql`select * from initialize_blank_sketch_class_form(${sketchClassId})`
Expand All @@ -316,7 +316,7 @@ describe("Forms", () => {
expect(template.is_template).toBe(true);
await createSession(conn, adminId, true, false, projectId);
const sketchClassBId = await conn.oneFirst(
sql`insert into sketch_classes (name, project_id) values ('Sketch Class B', ${projectId}) returning id`
sql`insert into sketch_classes (mapbox_gl_style, name, project_id) values ('[]'::jsonb, 'Sketch Class B', ${projectId}) returning id`
);
const form = await conn.one(
sql`select * from initialize_sketch_class_form_from_template(${sketchClassBId}, ${template.id})`
Expand All @@ -332,7 +332,7 @@ describe("Forms", () => {
async (conn, projectId, adminId, userIds) => {
await createSession(conn, adminId, true, true, projectId);
const sketchClassId = await conn.oneFirst(
sql`insert into sketch_classes (name, project_id) values ('Sketch Class A', ${projectId}) returning id`
sql`insert into sketch_classes (mapbox_gl_style, name, project_id) values ('[]'::jsonb, 'Sketch Class A', ${projectId}) returning id`
);
const source = await conn.one(
sql`select * from initialize_blank_sketch_class_form(${sketchClassId})`
Expand All @@ -353,7 +353,7 @@ describe("Forms", () => {
).toBe(1);
await createSession(conn, adminId, true, false, projectId);
const sketchClassBId = await conn.oneFirst(
sql`insert into sketch_classes (name, project_id) values ('Sketch Class B', ${projectId}) returning id`
sql`insert into sketch_classes (mapbox_gl_style, name, project_id) values ('[]'::jsonb, 'Sketch Class B', ${projectId}) returning id`
);
const form = await conn.one(
sql`select * from initialize_sketch_class_form_from_template(${sketchClassBId}, ${template.id})`
Expand Down Expand Up @@ -383,7 +383,7 @@ describe("Form Fields", () => {
async (conn, projectId, adminId, userIds) => {
await createSession(conn, adminId, true, false, projectId);
const sketchClassId = await conn.oneFirst(
sql`insert into sketch_classes (name, project_id) values ('Sketch Class A', ${projectId}) returning id`
sql`insert into sketch_classes (mapbox_gl_style, name, project_id) values ('[]'::jsonb, 'Sketch Class A', ${projectId}) returning id`
);
const form = await conn.one(
sql`select * from initialize_blank_sketch_class_form(${sketchClassId})`
Expand Down Expand Up @@ -412,7 +412,7 @@ describe("Form Fields", () => {
async (conn, projectId, adminId, userIds) => {
await createSession(conn, adminId, true, false, projectId);
const sketchClassId = await conn.oneFirst(
sql`insert into sketch_classes (name, project_id) values ('Sketch Class A', ${projectId}) returning id`
sql`insert into sketch_classes (mapbox_gl_style, name, project_id) values ('[]'::jsonb, 'Sketch Class A', ${projectId}) returning id`
);
const form = await conn.one(
sql`select * from initialize_blank_sketch_class_form(${sketchClassId})`
Expand Down Expand Up @@ -491,7 +491,7 @@ describe("Form Fields", () => {
async (conn, projectId, groupId, adminId) => {
await createSession(conn, adminId, true, false, projectId);
const sketchClassId = await conn.oneFirst(
sql`insert into sketch_classes (name, project_id) values ('Sketch Class A', ${projectId}) returning id`
sql`insert into sketch_classes (mapbox_gl_style, name, project_id) values ('[]'::jsonb, 'Sketch Class A', ${projectId}) returning id`
);
await limitToGroup(conn, "sketch_class_id", sketchClassId, groupId);
let form = await conn.one(
Expand All @@ -514,7 +514,7 @@ describe("Form Fields", () => {
async (conn, projectId, adminId, userIds) => {
await createSession(conn, adminId, true, false, projectId);
const sketchClassId = await conn.oneFirst(
sql`insert into sketch_classes (name, project_id) values ('Sketch Class A', ${projectId}) returning id`
sql`insert into sketch_classes (mapbox_gl_style, name, project_id) values ('[]'::jsonb, 'Sketch Class A', ${projectId}) returning id`
);
const form = await conn.one(
sql`select * from initialize_blank_sketch_class_form(${sketchClassId})`
Expand All @@ -537,7 +537,7 @@ describe("Form Fields", () => {
async (conn, projectId, adminId, userIds) => {
await createSession(conn, adminId, true, false, projectId);
const sketchClassId = await conn.oneFirst(
sql`insert into sketch_classes (name, project_id) values ('Sketch Class A', ${projectId}) returning id`
sql`insert into sketch_classes (mapbox_gl_style, name, project_id) values ('[]'::jsonb, 'Sketch Class A', ${projectId}) returning id`
);
const form = await conn.one(
sql`select * from initialize_blank_sketch_class_form(${sketchClassId})`
Expand Down Expand Up @@ -577,7 +577,7 @@ describe("Form Fields", () => {
async (conn, projectId, adminId, userIds) => {
await createSession(conn, adminId, true, false, projectId);
const sketchClassId = await conn.oneFirst(
sql`insert into sketch_classes (name, project_id) values ('Sketch Class A', ${projectId}) returning id`
sql`insert into sketch_classes (mapbox_gl_style, name, project_id) values ('[]'::jsonb, 'Sketch Class A', ${projectId}) returning id`
);
const form = await conn.one(
sql`select * from initialize_blank_sketch_class_form(${sketchClassId})`
Expand Down Expand Up @@ -670,7 +670,7 @@ describe("Form Fields", () => {
async (conn, projectId, adminId, userIds) => {
await createSession(conn, adminId, true, false, projectId);
const sketchClassId = await conn.oneFirst(
sql`insert into sketch_classes (name, project_id) values ('Sketch Class A', ${projectId}) returning id`
sql`insert into sketch_classes (mapbox_gl_style, name, project_id) values ('[]'::jsonb, 'Sketch Class A', ${projectId}) returning id`
);
const form = await conn.one(
sql`select * from initialize_blank_sketch_class_form(${sketchClassId})`
Expand Down
Loading

0 comments on commit c5f7ecf

Please sign in to comment.